Избегайте жесткого кодирования контроллера и имен действий

ASP.NET MVC, похоже, побуждает меня использовать жестко закодированные строки для обозначения контроллеров и действий.

Например, в контроллере:

return RedirectToAction("Index", "Home");

или, в представлении:

Html.RenderPartial("Index", "Home");

Мне не нужны жестко закодированные строки по всему моему коду. Что я могу сделать, чтобы избежать этого?

Ответ 1

Мне кажется, что вы хотите использовать строго типизированные перенаправления. Я создал статический вспомогательный класс под названием RedirectionHelper, который имеет следующий метод:

public static string GetUrl<T>(Expression<Action<T>> action, RequestContext requestContext, RouteValueDictionary values = null) where T : Controller
{
    UrlHelper urlHelper = new UrlHelper(requestContext);
    RouteValueDictionary routeValues = ExpressionHelper.GetRouteValuesFromExpression(action);

    if (values != null)
        foreach (var value in values)
            routeValues.Add(value.Key, value.Value);

    return urlHelper.RouteUrl(routeValues);
}

Единственное предостережение в том, что вам понадобится использовать фьючерсную библиотеку Microsoft.Web.Mvc, доступную в Nuget.

Теперь для вашего контроллера создайте базовый контроллер, который наследует все контроллеры, который имеет этот метод:

protected RedirectResult RedirectToAction<T>(Expression<Action<T>> action, RouteValueDictionary values = null) where T : Controller
{
    return new RedirectResult(RedirectionHelper.GetUrl(action, Request.RequestContext, values));
}

Теперь, в вашем действии, все, что вам нужно сделать, это сказать:

return RedirectToAction<Controller>(x => x.Index());

Аналогичным образом вы можете написать метод расширения html, который принимает одни и те же параметры и создает тэг привязки.

Как вы сказали выше, что вы хотели, когда вы меняете имена контроллеров или Action, ваш проект будет ломаться во время компиляции и покажет вам, где происходят перерывы. Однако это произойдет только в контроллерах, поскольку они не компилируются.

Надеюсь, это поможет!

Ответ 2

Посмотрите T4MVC, это порождает классы, поэтому вы можете иметь строго типизированные действия и имена контроллеров. Поскольку это еще только сопоставление с строкой, рефакторинг не приведет к обновлению имен в ваших представлениях, если вы, например, измените имя контроллера.

После восстановления вы получите ошибки компиляции из-за того, что имена исчезают из ваших сгенерированных классов, хотя они по-прежнему полезны при рефакторинге и уловах, которые вы можете пропустить, используя жестко закодированные строки.

Ответ 4

Не уверен, что кто-то уже добавил метод расширения в один из проектов ASP.NET MVC, но здесь часть кода, которую вы можете использовать для создания собственного метода расширения:

public RedirectToRouteResult RedirectToAction<TController>(Expression<Action<TController>> action, RouteValueDictionary routeValues) where TController : Controller
    {
        RouteValueDictionary rv = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action);

        return RedirectToAction((string)rv["Action"], (string)rv["Controller"], routeValues ?? new RouteValueDictionary());
    }

    public ActionResult Index()
    {
        return RedirectToAction<DashboardController>(x => x.Index(), null);
    }

Нет никаких параметров, объединяющих логику, поэтому вам придется добавлять их самостоятельно.

UPDATE: @mccow002 добавила аналогичное решение за несколько секунд до меня, поэтому я думаю, что его решение должно быть принято.

Ответ 5

Я знаю, что это старая тема, но когда я искал ответ для ASP.NET 5, эта тема впервые появилась. Больше нет необходимости в hardcode, просто используйте имя

[HttpGet]
public IActionResult List()
{
   ...
   return View();
}

[HttpPost]
public IActionResult Add()
{
    ...
    return RedirectToAction(nameof(List));
}