Avoid hard-coding controller and action names

2019-02-02 02:24发布

ASP.NET MVC seems to be encouraging me to use hard-coded strings to refer to controllers and actions.

For example, in a controller:

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

or, in a view:

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

I don't want hard-coded strings all over my code. What can I do to avoid this?

5条回答
地球回转人心会变
2楼-- · 2019-02-02 02:43

It sounds to me like you want to use strongly typed redirects. I made a static helper class called RedirectionHelper that has the following method:

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);
}

The only caveat is that you will have to use the Microsoft.Web.Mvc futures library available out on Nuget.

Now, for your controller, create a base controller that all controllers inherit from that has this method:

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

Now, in your action, all you have to do is say:

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

Likewise, you can write a html extension method that takes in the same parameters and builds your anchor tag.

Like you said above that you wanted, when you change Controller or Action names, your project will break at compile time and show you where the breaks occur. However, this will only occur in the controllers, seeing as how the views don't compile.

Hope this helps!

查看更多
放我归山
3楼-- · 2019-02-02 02:45

Not sure if somebody already added an extension method to one of the ASP.NET MVC related projects but here's a piece of code that you can use to create your own extension method:

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);
    }

There's no parameters merging logic, so you'll have to add it by your own.

UPDATE: @mccow002 added a similar solution a few seconds before me, so I think his solution should be accepted.

查看更多
来,给爷笑一个
5楼-- · 2019-02-02 02:51

Look at T4MVC this generates classes so you can have strongly typed actions and controller names. As it's still just a mapping to a string, refactoring won't cause the names in your views to update if you change a controller name for example.

After regenerating you will get compilation errors due to the names disappearing from your generated classes though so it's still useful in refactoring and catches problems that you can miss using hard-coded strings.

查看更多
\"骚年 ilove
6楼-- · 2019-02-02 03:00

I know this is an old topic, but when I was looking for an answer for ASP.NET 5 this theme first appeared. There is no need to hardcode anymore, just use nameof

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

[HttpPost]
public IActionResult Add()
{
    ...
    return RedirectToAction(nameof(List));
}
查看更多
登录 后发表回答