Asp.net mvc 不带ViewContext的Url表单操作
是否可以在不知道ViewContext的情况下(例如,在控制器中)从操作获取URL?大概是这样的:Asp.net mvc 不带ViewContext的Url表单操作,asp.net-mvc,url,routes,Asp.net Mvc,Url,Routes,是否可以在不知道ViewContext的情况下(例如,在控制器中)从操作获取URL?大概是这样的: LinkBuilder.BuildUrlFromExpression(ViewContext context, Expression<Action<T>> action) LinkBuilder.BuildUrlFromExpression(ViewContext上下文,表达式操作) …但使用Controller.RouteData而不是ViewContext。我似乎在
LinkBuilder.BuildUrlFromExpression(ViewContext context, Expression<Action<T>> action)
LinkBuilder.BuildUrlFromExpression(ViewContext上下文,表达式操作)
…但使用Controller.RouteData而不是ViewContext。我似乎在这上面有金属块。下面是我在单元测试中如何做到的:
private string RouteValueDictionaryToUrl(RouteValueDictionary rvd)
{
var context = MvcMockHelpers.FakeHttpContext("~/");
// _routes is a RouteCollection
var vpd = _routes.GetVirtualPath(
new RequestContext(context, _
routes.GetRouteData(context)), rvd);
return vpd.VirtualPath;
}
根据评论,我将适应控制器:
string path = RouteTable.Routes.GetVirtualPath(
new RequestContext(HttpContext,
RouteTable.Routes.GetRouteData(HttpContext)),
new RouteValueDictionary(
new { controller = "Foo",
action = "Bar" })).VirtualPath;
用真名替换“Foo”和“Bar”。这是我不知道的,所以我不能保证这是可能的最有效的解决方案,但它会让你走上正确的轨道。克雷格,谢谢你的正确答案。它工作得很好,也让我思考起来。因此,在我努力消除那些抗重构的“魔串”的过程中,我在您的解决方案上开发了一个变体:
public static string GetUrlFor<T>(this HttpContextBase c, Expression<Func<T, object>> action)
where T : Controller
{
return RouteTable.Routes.GetVirtualPath(
new RequestContext(c, RouteTable.Routes.GetRouteData(c)),
GetRouteValuesFor(action)).VirtualPath;
}
public static RouteValueDictionary GetRouteValuesFor<T>(Expression<Func<T, object>> action)
where T : Controller
{
var methodCallExpresion = ((MethodCallExpression) action.Body);
var controllerTypeName = methodCallExpresion.Object.Type.Name;
var routeValues = new RouteValueDictionary(new
{
controller = controllerTypeName.Remove(controllerTypeName.LastIndexOf("Controller")),
action = methodCallExpresion.Method.Name
});
var methodParameters = methodCallExpresion.Method.GetParameters();
for (var i = 0; i < methodParameters.Length; i++)
{
var value = Expression.Lambda(methodCallExpresion.Arguments[i]).Compile().DynamicInvoke();
var name = methodParameters[i].Name;
routeValues.Add(name, value);
}
return routeValues;
}
公共静态字符串GetUrlFor(此HttpContextBase c,表达式操作)
其中T:控制器
{
返回RouteTable.Routes.GetVirtualPath(
新的RequestContext(c,RouteTable.Routes.GetRouteData(c)),
GetRouteValuesFor(action)).VirtualPath;
}
公共静态RouteValueDictionary GetRouteValuesFor(表达式操作)
其中T:控制器
{
var MethodCallExpression=((MethodCallExpression)action.Body);
var controllerTypeName=methodCallExpresion.Object.Type.Name;
var routeValues=新的RouteValueDictionary(新的
{
controller=controllerTypeName.Remove(controllerTypeName.LastIndexOf(“控制器”)),
action=methodCallExpresion.Method.Name
});
var methodParameters=methodCallExpresion.Method.GetParameters();
对于(var i=0;i
我知道有些人会说什么……可怕的反思!在我的特定应用程序中,我认为可维护性的好处大于性能方面的好处。我欢迎对此想法和代码的任何反馈。我不需要当前请求的URL,但需要其他操作。我理解。上述解决方案仍然适用。那里没有与当前请求的连接。我不明白。假设我想获取FooController.Bar(“foo”,“Bar”)的Url,它将是“/MyVirtualDir/foo.mvc/Bar/foo/Bar”。我怎样才能用一个(不同的)控制器方法来得到它呢?Craig,你能不能也用一个强类型控制器(即Microsoft.Web.MVC)来更新你的答案,而不必硬编码控制器名称和操作?可能吗?所有控制器都是强类型的。如果您能够获得性能上的成功,您当然可以反映控制器和操作名称,但不要忘记ActionNameAttribute。如果我这样做,我会尝试找到一种方法来使用框架的内部控制器和操作名缓存。我不知道如何正确地存根HttpContext(即使在与Reflector一起玩了一番之后)。我将提供一个接口,使控制器更易于测试。我能够找出如何存根HttpContext,使其在测试中工作。缺少的价格是:SetupResult.For(request.AppRelativeCurrentExecutionFilePath)。Return(“~/”);