Как убедиться, что контроллер и действие существуют до выполнения перенаправления, asp.net mvc3

В одной из моих контроллеров + пары действий я получаю значения другого контроллера и действия как строки откуда-то, и я хочу перенаправить свое текущее действие. Прежде чем делать перенаправление, я хочу убедиться, что в моем приложении существует действие controller + action, если нет, то перенаправление на 404. Я ищу способ сделать это.

public ActionResult MyTestAction()
{
    string controller = getFromSomewhere();
    string action = getFromSomewhereToo();

    /*
      At this point use reflection and make sure action and controller exists
      else redirect to error 404
    */ 

    return RedirectToRoute(new { action = action, controller = controller });
}

Все, что я сделал, это, но это не работает.

var cont = Assembly.GetExecutingAssembly().GetType(controller);
if (cont != null && cont.GetMethod(action) != null)
{ 
    // controller and action pair is valid
}
else
{ 
    // controller and action pair is invalid
}

Ответ 1

Вы можете реализовать IRouteConstraint и использовать его в таблице маршрутов.

Реализация этого ограничения маршрута может использовать рефлексию, чтобы проверить, существует ли контроллер/действие. Если он не существует, маршрут будет пропущен. В качестве последнего маршрута в таблице маршрутов вы можете установить тот, который ловит всех и сопоставляет его с действием, которое отображает вид 404.

Вот фрагмент кода, который поможет вам начать:

public class MyRouteConstraint : IRouteConstraint
    {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {

            var action = values["action"] as string;
            var controller = values["controller"] as string;

            var controllerFullName = string.Format("MvcApplication1.Controllers.{0}Controller", controller);

            var cont = Assembly.GetExecutingAssembly().GetType(controllerFullName);

            return cont != null && cont.GetMethod(action) != null;
        }
    }

Обратите внимание, что вам нужно использовать полностью квалифицированное имя контроллера.

RouteConfig.cs

routes.MapRoute(
                "Home", // Route name
                "{controller}/{action}", // URL with parameters
                new { controller = "Home", action = "Index" }, // Parameter defaults
                new { action = new MyRouteConstraint() } //Route constraints
            );

routes.MapRoute(
                "PageNotFound", // Route name
                "{*catchall}", // URL with parameters
                new { controller = "Home", action = "PageNotFound" } // Parameter defaults
            );

Ответ 2

Если вы не можете получить полностью квалифицированное имя контроллера для перехода в GetType(), вам нужно будет использовать GetTypes(), а затем выполнить сравнение строк по результатам.

Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();

Type type = types.Where( t => t.Name == controller ).SingleOrDefault();

if( type != null && type.GetMethod( action ) != null )

Ответ 3

Отражение - дорогостоящая операция.

Вы действительно должны быть модульным тестированием этих методов, чтобы убедиться, что они перенаправляются на соответствующие действия и контроллер.

например. (NUnit)

[Test]
public void MyTestAction_Redirects_To_MyOtherAction()
{
  var controller = new MyController();

  var result = (RedirectToRouteResult)controller.MyTestAction();

  Assert.That(result.RouteValues["action"], Is.EqualTo("MyOtherAction");
  Assert.That(result.RouteValues["controller"], Is.EqualTo("MyOtherController");
}