如何在ASP.NET MVC Url.Action中使用C#nameof()

Mik*_*eon 33 c# asp.net asp.net-mvc c#-6.0 nameof

是否有推荐的方式来使用新的

nameof()
Run Code Online (Sandbox Code Playgroud)

在ASP.NET MVC中表达控制器名称?

Url.Action("ActionName", "Home")  <------ works
Run Code Online (Sandbox Code Playgroud)

VS

Url.Action(nameof(ActionName), nameof(HomeController)) <----- doesn't work
Run Code Online (Sandbox Code Playgroud)

显然它不起作用因为nameof(HomeController)转换为"HomeController"而MVC需要的只是"Home".

Gig*_*igi 23

我喜欢詹姆斯关于使用扩展方法的建议.只有一个问题:虽然你正在使用nameof()并消除了魔法字符串,但仍然存在类型安全的小问题:你仍在使用字符串.因此,很容易忘记使用扩展方法,或提供无效的任意字符串(例如,错误输入控制器的名称).

我认为我们可以通过使用Controller 的通用扩展方法来改进James的建议,其中泛型参数是目标控制器:

public static class ControllerExtensions
{
    public static string Action<T>(this Controller controller, string actionName)
        where T : Controller
    {
        var name = typeof(T).Name;
        string controllerName = name.EndsWith("Controller")
            ? name.Substring(0, name.Length - 10) : name;
        return controller.Url.Action(actionName, controllerName);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法现在更清洁了:

this.Action<HomeController>(nameof(ActionName));
Run Code Online (Sandbox Code Playgroud)


Jam*_*mes 7

考虑一种扩展方法:

public static string UrlName(this Type controller)
{
  var name = controller.Name;
  return name.EndsWith("Controller") ? name.Substring(0, name.Length - 10) : name;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用:

Url.Action(nameof(ActionName), typeof(HomeController).UrlName())
Run Code Online (Sandbox Code Playgroud)

  • 传递 `Type` 是有风险的。 (2认同)
  • 因此,如果名称不以"Controller"结尾,我会抛出异常. (2认同)

Car*_*lin 6

我需要确保routeValues正确处理,而不是总是像querystring值一样对待。但是,我仍然想确保操作与控制器相匹配。

我的解决方案是为Url.Action.

<a href="@(Url.Action<MyController>(x=>x.MyAction))">Button Text</a>
Run Code Online (Sandbox Code Playgroud)

我有不同类型的单参数操作的重载。如果我需要通过routeValues...

<a href="@(Url.Action<MyController>(x=>x.MyAction, new { myRouteValue = myValue }))">Button Text</a>
Run Code Online (Sandbox Code Playgroud)

对于我没有显式创建重载的具有复杂参数的操作,需要使用控制器类型指定类型以匹配操作定义。

<a href="@(Url.Action<MyController,int,string>(x=>x.MyAction, new { myRouteValue1 = MyInt, MyRouteValue2 = MyString}))">Button Text</a>
Run Code Online (Sandbox Code Playgroud)

当然,大多数时候动作都在同一个控制器内,所以我仍然只使用nameof这些。

<a href="@Url.Action(nameof(MyController.MyAction))">Button Text</a>
Run Code Online (Sandbox Code Playgroud)

由于routeValues不一定与操作参数匹配,因此该解决方案允许这种灵活性。

扩展代码

namespace System.Web.Mvc {
    public static class UrlExtensions {

    // Usage : <a href="@(Url.Action<MyController>(x=>x.MyActionNoVars, new {myroutevalue = 1}))"></a>
    public static string Action<T>(this UrlHelper helper,Expression<Func<T,Func<ActionResult>>> expression,object routeValues = null) where T : Controller
        => helper.Action<T>((LambdaExpression)expression,routeValues);

    // Usage : <a href="@(Url.Action<MyController,vartype1>(x=>x.MyActionWithOneVar, new {myroutevalue = 1}))"></a>
    public static string Action<T, P1>(this UrlHelper helper,Expression<Func<T,Func<P1,ActionResult>>> expression,object routeValues = null) where T : Controller
        => helper.Action<T>(expression,routeValues);

    // Usage : <a href="@(Url.Action<MyController,vartype1,vartype2>(x=>x.MyActionWithTwoVars, new {myroutevalue = 1}))"></a>
    public static string Action<T, P1, P2>(this UrlHelper helper,Expression<Func<T,Func<P1,P2,ActionResult>>> expression,object routeValues = null) where T : Controller
        => helper.Action<T>(expression,routeValues);

    // Usage : <a href="@(Url.Action<MyController>(x=>x.MyActionWithOneInt, new {myroutevalue = 1}))"></a>
    public static string Action<T>(this UrlHelper helper,Expression<Func<T,Func<int,ActionResult>>> expression,object routeValues = null) where T : Controller
        => helper.Action<T>((LambdaExpression)expression,routeValues);

    // Usage : <a href="@(Url.Action<MyController>(x=>x.MyActionWithOneString, new {myroutevalue = 1}))"></a>
    public static string Action<T>(this UrlHelper helper,Expression<Func<T,Func<string,ActionResult>>> expression,object routeValues = null) where T : Controller
        => helper.Action<T>((LambdaExpression)expression,routeValues);

    //Support function
    private static string Action<T>(this UrlHelper helper,LambdaExpression expression,object routeValues = null) where T : Controller
        => helper.Action(
                ((MethodInfo)((ConstantExpression)((MethodCallExpression)((UnaryExpression)expression.Body).Operand).Object).Value).Name,
                typeof(T).Name.Replace("Controller","").Replace("controller",""),
                routeValues);
    }
}
Run Code Online (Sandbox Code Playgroud)