Мой проект использует следующий код для генерации URL-адресов с маршрутизацией MVC для данных routeName
и routeValues
:
public class RouteBuilder
{
public string GetUrl(string routeName, object routeValues)
{
return RouteTable.Routes.GetVirtualPath(
new RequestContext(new MockHttpContextBase(string.Empty), new RouteData()),
routeName,
new RouteValueDictionary(routeValues)
)?.VirtualPath;
}
}
Например, с учетом следующего определения маршрута:
public MyController : Controller
{
[Route("Foo", "{bar}/{quux}")]
public IActionResult MyControllerMethod(MyModel model) { }
}
мы звоним:
// yields "zod/baz"
var routedUrl = RouteBuilder.GetUrl("Foo", new
{
bar = "zod",
quux = "baz",
});
Проблема возникает с объектом значений маршрута, переданным GetUrl
. По необходимости это может быть любой тип объекта, включая анонимный, как показано в примере. Но это проблематично, потому что если в определении объекта есть какие-либо опечатки, шаблон маршрута не будет совпадать, а URL не будет создан:
// yields null!
var routedUrl = RouteBuilder.GetUrl("Foo", new
{
baz = "zod", // oops, typo in 1st param name!
quux = "baz",
});
Это еще более серьезная проблема, поскольку она может быть обнаружена только во время выполнения.
Потенциальное решение заключается в следующем:
public class MyControllerMethodRouteParameters
{
string bar { get; set; }
string quux { get; set; }
}
public MyController : Controller
{
[Route("Foo", "{" + nameof(MyControllerMethodRouteParameters.bar) + "}/{" + nameof(MyControllerMethodRouteParameters.quux ) + "}")]
public IActionResult MyControllerMethod(MyModel model) { }
}
public class RouteBuilder
{
private string GetUrl(string routeName, object routeValues) { /* as before */ }
public string GetUrl(MyControllerMethodRouteParameters params)
{
return GetUrl(GetRouteNameFor(params.GetType(), params));
}
}
Но он имеет большой недостаток с точки зрения усилий разработчика: при добавлении нового метода контроллера вы также должны помнить о том, чтобы добавить класс параметров маршрута, перегрузку GetUrl
для него и тип параметров маршрута routename => route отображение. Легко забыть сделать, и это также кажется ненужным повторением, так как все необходимые параметры и их типы уже определены в RouteAttribute
.
Таким образом, моя идея состояла в том, чтобы сгенерировать необходимый код с помощью шаблона T4, отразив над сборкой, захватив все RouteAttribute
s и вытянув из них имя маршрута и шаблон, а затем проанализировав шаблон для имен свойств класс параметров маршрута. Это последнее препятствие, к которому я упал, потому что, хотя я знаю, что могу написать регулярное выражение (я) для сопоставления и извлечения параметров маршрута из шаблона, я бы предпочел использовать для этого существующую функциональность.
Проблема в том, что я не могу найти ничего, что, похоже, сделает это для меня. Наиболее близким является внутренний класс System.Web.Mvc.Routing.InlineRouteTemplateParser
, но мои эксперименты с ним не были особенно плодотворными. Есть ли что-то, что я могу или должен использовать, чтобы достичь этого, или я должен просто уступить темному богу регулярных выражений?