Avoid hard-coding controller and action names

2019-02-02 02:46发布

问题:

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?

回答1:

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!



回答2:

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.



回答3:

try T4MVC: http://mvccontrib.codeplex.com/wikipage?title=T4MVC



回答4:

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:

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