Url Form Ação Sem ViewContext
-
21-08-2019 - |
Pergunta
É possível obter um URL de uma ação sem saber ViewContext (por exemplo, em um controlador)? Algo parecido com isto:
LinkBuilder.BuildUrlFromExpression(ViewContext context, Expression<Action<T>> action)
... mas usando Controller.RouteData vez de ViewContext. Eu pareço ter bloco de metal sobre este assunto.
Solução
Aqui está como eu fazê-lo em um teste de unidade:
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;
}
Por comentários, vou adaptar-se a um controlador:
string path = RouteTable.Routes.GetVirtualPath(
new RequestContext(HttpContext,
RouteTable.Routes.GetRouteData(HttpContext)),
new RouteValueDictionary(
new { controller = "Foo",
action = "Bar" })).VirtualPath;
Substitua "Foo" e "Bar", com nomes reais. Esta é em cima da minha cabeça, então eu não pode garantir que é a solução mais eficiente possível, mas deverá fazê-lo no caminho certo.
Outras dicas
Craig, Obrigado pela resposta correta. Ele funciona muito bem, e também ir me fez pensar. Então, na minha unidade para eliminar esses refactor-resistentes "cordas mágicas" Eu desenvolvi uma variação sobre a sua solução:
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;
}
Eu sei que alguns vão dizer ... temido reflexão! Na minha aplicação particular, acho que o benefício de maintainability supera conerns desempenho. Congratulo-me com algum comentário sobre esta ideia e o código.