3 回答
TA贡献1810条经验 获得超4个赞
不,你不能。因为属性名称已经是一个魔法字符串,并且对于所有意图和目的,控制器方法的名称本身就是一个魔法字符串(在您使用隐式操作名称的情况下)。魔术弦并不坏,只是经常被误用。在这种情况下,您最好只使用常量。
internal const string ContactActionName2 = nameof(ContactActionName2);
和
[ActionName(ContactActionName2)]
和
HomeController.ContactActionName2
应该足以满足您的用例。
但是,由于每个人都对此大发雷霆,我决定去寻找一个完全不依赖字符串的解决方案(除了您无法避免依赖的字符串 - 操作名称)。我不喜欢这个解决方案,因为 1) 它太过分了,2) 它仍然只是访问一个字符串值,这可以更简单地使用一个常量来完成,3) 你实际上必须写出整个方法调用作为一个表达式,并且4) 每次使用时它都会分配一个表达式。
public static class ActionNameExtensions<TController>
{
public static string FindActionName<T>(Expression<Func<TController, T>> expression)
{
MethodCallExpression outermostExpression = expression.Body as MethodCallExpression;
if (outermostExpression == null)
{
throw new ArgumentException("Not a " + nameof(MethodCallExpression));
}
return outermostExpression.Method.GetCustomAttribute<ActionNameAttribute>().Name;
}
}
用法示例:
public class HomeController : Controller
{
[ActionName("HelloWorld")]
public string MyCoolAction(string arg1, string arg2, int arg4)
{
return ActionNameExtensions<HomeController>.FindActionName(
controller => controller.MyCoolAction("a", "b", 3)
);
}
}
可以编写一个重载来接受没有void返回的方法。虽然这有点奇怪,因为它假设用于控制器方法,通常返回一个值。
TA贡献1993条经验 获得超5个赞
...如果操作方法使用 [ActionName] 属性,有没有办法获得正确的操作名称(并避免使用魔法字符串)?也许通过 nameof() 和扩展方法的组合?
您可以使用反射。这是一个内联版本:
<p>@(
(
(ActionNameAttribute)(
typeof(HomeController)
.GetMethod(nameof(HomeController.Contact))
.GetCustomAttributes(typeof(ActionNameAttribute), false)[0]
)
).Name
)</p>
这是与剃刀功能相同的操作:
@functions {
public string GetActionName(Type controller, string methodName) {
var method = controller.GetMethod(methodName);
var attributeType = typeof(ActionNameAttribute);
var attribute = method.GetCustomAttributes(attributeType, false)[0];
return (attribute as ActionNameAttribute).Name;
}
}
<p>@GetActionName(typeof(HomeController), nameof(HomeController.Contact))</p>
这是与通用剃刀函数相同的操作:
@functions {
public string GetActionName<T>(string methodName) {
var controllerType = typeof(T);
var method = controllerType.GetMethod(methodName);
var attributeType = typeof(ActionNameAttribute);
var attribute = method.GetCustomAttributes(attributeType, false)[0];
return (attribute as ActionNameAttribute).Name;
}
}
<p>@(GetActionName<HomeController>(nameof(HomeController.Contact)))</p>
剩下的就是向函数添加防御性编程(例如null检查)GetActionName。
您的问题专门询问了扩展方法。据我所知,扩展方法不会提供太大的改进,因为我们正在使用类型和方法,而扩展方法适用于对象。
TA贡献1815条经验 获得超6个赞
如果你不喜欢你可以用泛型做一些非常奇特的逻辑:
public static class HtmlHelperExtensions
{
public static IHtmlContent ActionLink<TController>(
this IHtmlHelper htmlHelper,
string linkText,
string actionName)
where TController : ControllerBase
{
var suffix = nameof(Controller);
var controllerName = typeof(TController).Name.Replace(suffix, "");
var method = typeof(TController).GetMethod(actionName);
var attributeType = typeof(ActionNameAttribute);
var attribute = method.GetCustomAttributes(attributeType, false);
actionName = attribute.Length == 0
? actionName
: (attribute[0] as ActionNameAttribute).Name;
return htmlHelper.ActionLink(linkText, actionName);
}
}
对此进行了测试,它可能会抱怨(很确定会)签名已经存在,因此您可能必须重命名该方法。在任何情况下,您都可以像这样使用它:
@(Html.ActionLink<HomeController>("Link Text", nameof(HomeController.Index)))
- 3 回答
- 0 关注
- 359 浏览
添加回答
举报