Извлечение параметров маршрута из шаблонов маршрутов MVC 5 - PullRequest
2 голосов
/ 24 мая 2019

Мой проект использует следующий код для генерации 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, но мои эксперименты с ним не были особенно плодотворными. Есть ли что-то, что я могу или должен использовать, чтобы достичь этого, или я должен просто уступить темному богу регулярных выражений?

...