Действие формы URL Без viewContext
-
21-08-2019 - |
Вопрос
Можно ли получить URL-адрес из действия, не зная viewContext (например, в контроллере)?Что - то вроде этого:
LinkBuilder.BuildUrlFromExpression(ViewContext context, Expression<Action<T>> action)
...но используя контроллер.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;
}
Я знаю, что скажут некоторые... Ужасное отражение!В моем конкретном приложении, я думаю, преимущество ремонтопригодности перевешивает проблемы с производительностью.Я приветствую любые отзывы об этой идее и коде.