[英]ASP.NET MVC 3 : Is there a way to get a controller's string Name from its Type?
使用MVC3中的UrlHelper
,您可以使用字符串为控制器和操作构建URL:
@Url.Action("Index", "Somewhere")
这会将请求路由到SomewhereController.Index()
。
我想做的是获取控制器和操作的URL,但是传递控制器的类型:
@Url.Action("Index", typeof(SomewhereController))
有没有办法做到这一点?
编辑/澄清:
我意识到控制器的约定是控制器名称路由到名为{Name}Controller
的类,所以我可以从Type.Name的末尾删除'Controller'。 我想我假设有一种方法可以通过一些自定义路由覆盖此约定。 虽然我看得越多,但我不确定是否可能......
也许MVC3 只能路由到名为“* Controller”的类? 我正在通过MVC3源寻找“控制器”硬编码的地方,但尚未找到答案......但如果可以将“Somewhere”路由到SomewhereFoo
类而不是SomewhereController
,那么只需删除“控制器“来自班级名称将是不正确的。
如果某人可以向我提供证据支持或反对“控制器”被硬编码到某个地方的MVC3,那么我会对“从名称中移除控制器”的方法感到更舒服。
没有现有的扩展,但您可以编写自己的扩展,以MvcFutures的ActionLink为模型。 我建议使用像@Url.Action<SomewhereController>( c => c.Index )
一样的泛型方法@Url.Action<SomewhereController>( c => c.Index )
public static UrlHelperExtensions
{
public static string Action<TController>( this UrlHelper helper, Expression<Action<T>> action ) where TController : Controller
{
var routeValues = GetRouteValuesFromExpression( action );
return helper.Action( routeValues["action"], routeValues );
}
// copied from MvcFutures
// http://aspnet.codeplex.com/SourceControl/changeset/view/72551#266392
private static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action) where TController : Controller
{
if (action == null) {
throw new ArgumentNullException("action");
}
MethodCallExpression call = action.Body as MethodCallExpression;
if (call == null) {
throw new ArgumentException(MvcResources.ExpressionHelper_MustBeMethodCall, "action");
}
string controllerName = typeof(TController).Name;
if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {
throw new ArgumentException(MvcResources.ExpressionHelper_TargetMustEndInController, "action");
}
controllerName = controllerName.Substring(0, controllerName.Length - "Controller".Length);
if (controllerName.Length == 0) {
throw new ArgumentException(MvcResources.ExpressionHelper_CannotRouteToController, "action");
}
// TODO: How do we know that this method is even web callable?
// For now, we just let the call itself throw an exception.
var rvd = new RouteValueDictionary();
rvd.Add("Controller", controllerName);
rvd.Add("Action", call.Method.Name);
AddParameterValuesFromExpressionToDictionary(rvd, call);
return rvd;
}
}
@Url.Action("Index", typeof(SomewhereController).Name.Replace("Controller", ""))
有很多方法可以做到这一点。 如果您使用的是类型,我能想到的最简单的方法是实现Name
属性,如下所示:
public static string Name { get { return "Somewhere"; } }
然后像这样调用你的Action:
@Url.Action("Index", SomewhereController.Name);
根据接受的答案 :
var url = Url.RouteUrl<MyController>(c => c.MyAction(dummy,args));
要么:
@using (Html.BeginForm(Url.Route<MyController>(c => c.MyAction(dummy,args))))
{
// yadda yadda
}
public static class ActionRouteHelper
{
/// <summary>
/// Given a controller/action selector, return its URL route
/// </summary>
/// <typeparam name="TController"></typeparam>
/// <param name="url">helper extended</param>
/// <param name="action">A lambda for choosing an action from the indicated controller. May need to provide dummy method arguments.</param>
/// <returns></returns>
public static string RouteUrl<TController>(this UrlHelper url, Expression<Action<TController>> action) where TController : Controller
{
return url.RouteUrl(url.Route(action));
}
/// <summary>
/// Given a controller/action selector, return its URL route
/// </summary>
/// <remarks>See inspiration from https://stackoverflow.com/a/8252301/1037948 </remarks>
/// <typeparam name="TController">the controller class</typeparam>
/// <param name="url">helper extended</param>
/// <param name="action">A lambda for choosing an action from the indicated controller. May need to provide dummy method arguments.</param>
/// <returns></returns>
public static RouteValueDictionary Route<TController>(this UrlHelper url, Expression<Action<TController>> action) where TController : Controller
{
// TODO: validate controller name for suffix, non-empty result, if that's important to you here rather than the link just not working
var controllerName = typeof(TController).Name.Replace("Controller", string.Empty);
// strip method name out of the expression, the lazy way (https://stackoverflow.com/questions/671968/retrieving-property-name-from-lambda-expression/17220748#17220748)
var actionName = action.ToString(); // results in something like "c => c.MyAction(arg1,arg2)"
var startOfMethodName = actionName.IndexOf('.')+1;
var startOfArgList = actionName.IndexOf('(');
actionName = actionName.Substring(startOfMethodName, startOfArgList - startOfMethodName);
return new RouteValueDictionary {
{ "Controller", controllerName },
{ "Action", actionName }
};
}
}
你可以创建一个Razor助手:
@helper MyAction(string action, Type controller) {
var controllerName = typeof(controller)
.Name.Replace("Controller", "");
@Url.Action(action, controllerName);
}
然后可以用它代替@Url.Action
:
@MyAction("ActionName", typeof(MyController))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.