猿问

使用 ActionName 属性时如何获取操作名称?

随着nameofC# 6 中运算符的引入,您可以通过编程方式获取操作名称,而无需魔法字符串:


<p>@Html.ActionLink("Contact", nameof(HomeController.Contact), "Home")</p>

如果您不更改视图的名称,这将非常有效。


但是,如果操作方法正在使用该[ActionName]属性,有没有办法获得正确的操作名称(并避免使用魔法字符串)?也许通过组合nameof()和扩展方法?


[ActionName("Contact2")]

public ActionResult Contact()

{    

    // ...

}

在本例中,nameof(HomeController.Contact)将返回字符串“Contact”和 URL“ http://localhost:2222/Home/Contact ”,而正确的 URL 应该是“ http://localhost:2222/Home/Contact2 ”,因为[ActionName("Contact2")]属性。


qq_遁去的一_1
浏览 360回答 3
3回答

慕莱坞森

不,你不能。因为属性名称已经是一个魔法字符串,并且对于所有意图和目的,控制器方法的名称本身就是一个魔法字符串(在您使用隐式操作名称的情况下)。魔术弦并不坏,只是经常被误用。在这种情况下,您最好只使用常量。internal const string ContactActionName2 = nameof(ContactActionName2);和[ActionName(ContactActionName2)]和HomeController.ContactActionName2应该足以满足您的用例。但是,由于每个人都对此大发雷霆,我决定去寻找一个完全不依赖字符串的解决方案(除了您无法避免依赖的字符串 - 操作名称)。我不喜欢这个解决方案,因为 1) 它太过分了,2) 它仍然只是访问一个字符串值,这可以更简单地使用一个常量来完成,3) 你实际上必须写出整个方法调用作为一个表达式,并且4) 每次使用时它都会分配一个表达式。public static class ActionNameExtensions<TController>{&nbsp; &nbsp; public static string FindActionName<T>(Expression<Func<TController, T>> expression)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; MethodCallExpression outermostExpression = expression.Body as MethodCallExpression;&nbsp; &nbsp; &nbsp; &nbsp; if (outermostExpression == null)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new ArgumentException("Not a " + nameof(MethodCallExpression));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return outermostExpression.Method.GetCustomAttribute<ActionNameAttribute>().Name;&nbsp; &nbsp; }}用法示例:public class HomeController : Controller{&nbsp; &nbsp; [ActionName("HelloWorld")]&nbsp; &nbsp; public string MyCoolAction(string arg1, string arg2, int arg4)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return ActionNameExtensions<HomeController>.FindActionName(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; controller => controller.MyCoolAction("a", "b", 3)&nbsp; &nbsp; &nbsp; &nbsp; );&nbsp; &nbsp; }}可以编写一个重载来接受没有void返回的方法。虽然这有点奇怪,因为它假设用于控制器方法,通常返回一个值。

ibeautiful

...如果操作方法使用 [ActionName] 属性,有没有办法获得正确的操作名称(并避免使用魔法字符串)?也许通过 nameof() 和扩展方法的组合?您可以使用反射。这是一个内联版本:<p>@(&nbsp; &nbsp; (&nbsp; &nbsp; &nbsp; &nbsp; (ActionNameAttribute)(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; typeof(HomeController)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .GetMethod(nameof(HomeController.Contact))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .GetCustomAttributes(typeof(ActionNameAttribute), false)[0]&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; ).Name)</p>这是与剃刀功能相同的操作:@functions {&nbsp; &nbsp; public string GetActionName(Type controller, string methodName) {&nbsp; &nbsp; &nbsp; &nbsp; var method = controller.GetMethod(methodName);&nbsp; &nbsp; &nbsp; &nbsp; var attributeType = typeof(ActionNameAttribute);&nbsp; &nbsp; &nbsp; &nbsp; var attribute = method.GetCustomAttributes(attributeType, false)[0];&nbsp; &nbsp; &nbsp; &nbsp; return (attribute as ActionNameAttribute).Name;&nbsp; &nbsp; }}<p>@GetActionName(typeof(HomeController), nameof(HomeController.Contact))</p>这是与通用剃刀函数相同的操作:@functions {&nbsp; &nbsp; public string GetActionName<T>(string methodName) {&nbsp; &nbsp; &nbsp; &nbsp; var controllerType = typeof(T);&nbsp; &nbsp; &nbsp; &nbsp; var method = controllerType.GetMethod(methodName);&nbsp; &nbsp; &nbsp; &nbsp; var attributeType = typeof(ActionNameAttribute);&nbsp; &nbsp; &nbsp; &nbsp; var attribute = method.GetCustomAttributes(attributeType, false)[0];&nbsp; &nbsp; &nbsp; &nbsp; return (attribute as ActionNameAttribute).Name;&nbsp; &nbsp; }}<p>@(GetActionName<HomeController>(nameof(HomeController.Contact)))</p>剩下的就是向函数添加防御性编程(例如null检查)GetActionName。您的问题专门询问了扩展方法。据我所知,扩展方法不会提供太大的改进,因为我们正在使用类型和方法,而扩展方法适用于对象。

红糖糍粑

如果你不喜欢你可以用泛型做一些非常奇特的逻辑:public static class HtmlHelperExtensions{&nbsp; &nbsp; public static IHtmlContent ActionLink<TController>(&nbsp; &nbsp; &nbsp; &nbsp; this IHtmlHelper htmlHelper,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; string linkText,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; string actionName)&nbsp; &nbsp; &nbsp; where TController : ControllerBase&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var suffix = nameof(Controller);&nbsp; &nbsp; &nbsp; &nbsp; var controllerName = typeof(TController).Name.Replace(suffix, "");&nbsp; &nbsp; &nbsp; &nbsp; var method = typeof(TController).GetMethod(actionName);&nbsp; &nbsp; &nbsp; &nbsp; var attributeType = typeof(ActionNameAttribute);&nbsp; &nbsp; &nbsp; &nbsp; var attribute = method.GetCustomAttributes(attributeType, false);&nbsp; &nbsp; &nbsp; &nbsp; actionName = attribute.Length == 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? actionName&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : (attribute[0] as ActionNameAttribute).Name;&nbsp; &nbsp; &nbsp; &nbsp; return htmlHelper.ActionLink(linkText, actionName);&nbsp; &nbsp; }}对此进行了测试,它可能会抱怨(很确定会)签名已经存在,因此您可能必须重命名该方法。在任何情况下,您都可以像这样使用它:@(Html.ActionLink<HomeController>("Link Text", nameof(HomeController.Index)))
随时随地看视频慕课网APP
我要回答