Получение шаблона маршрута для заданного контроллера и действия - PullRequest
0 голосов
/ 24 сентября 2018

Я создаю приложение с помощью angularjs и ASP.NET.Для того, чтобы мои угловые сервисы могли отправлять запросы, мне нужно составить список шаблонов URL с учетом списка контроллеров ASP.NET и действий, которые я затем могу отправить клиенту.

Вид результата, который яищу что-то вроде:

[RoutePrefix("my-controller")]
public class MyController : ControllerBase
{
    [Route("my-action/{arg1}/{arg2}")]
    public ActionResult MyAction(int arg1, string arg2) {
        // ...
    }
}

// Elsewhere in my code
GetRouteTemplate("MyController", "MyAction") // => "my-controller/my-action/{arg1}/{arg2}"

Я бы предпочел не кодировать их жестко в интерфейс, так как любое изменение в маршрутизации нарушило бы угловой код, поэтому яЯ искал способ их генерирования.

Моя первая попытка - использовать отражение, чтобы получить все методы действия, а затем вызвать Url.Action, чтобы получить URL-адреса.Я поместил это в свой базовый класс контроллера:

protected Dictionary<String, String> GetUrlTemplates()
{
    var controllerName = this
        .GetType()
        .Name;

    var actionNames = this
        .GetType()
        .GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
        .Where(m => !m.IsDefined(typeof(NonActionAttribute), false))
        .Select(m => m.Name)
        .Distinct()
        .ToList();

    return actionNames 
        .ToDictionary(
            actionName => actionName,
            actionName => Url.Action(actionName, controllerName));
}

Это нормально для любых действий без аргументов, но в противном случае не удается вернуть правильный маршрут.

Моя следующая попытка былачтобы попытаться извлечь шаблоны непосредственно из RouteTable:

protected Dictionary<String, String> GetUrlTemplates()
{
    var controllerName = this
        .GetType()
        .Name;

    var actions = this
        .GetType()
        .GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
        .Where(m => !m.IsDefined(typeof(NonActionAttribute), false))
        .Select(m => m.Name)
        .Distinct()
        .ToList();

    return RouteTable.Routes
        .OfType<LinkGenerationRoute>()
        .Select(lgr => new {
            url = lgr.Url,
            routeAction = lgr.DataTokens["MS_DirectRouteActions"][0]
        })
        .Where(o => o.routeAction.ControllerDescriptor.ControllerName == controllerName
            && actions.Contains(o.routeAction.ActionName))
        .ToDictionary(
            o => o.routeAction.ActionName,
            o => o.url);
}

Это не работает, потому что LinkGenerationRoute является внутренним классом, поэтому, если нет другого способа получить доступ к этим значениям в таблице маршрутов, это также выглядиткак тупик.

Обе эти попытки немного уродливы и кажутся неправильным подходом, но я не вижу другого способа сделать это.Конечно, генерация шаблонов URL для внешнего интерфейса - довольно распространенная задача - Существует ли «правильный» способ получения шаблонов URL в ASP.NET?Неужели я неправильно подхожу к этой проблеме? Спасибо.

1 Ответ

0 голосов
/ 25 сентября 2018

В конце я решил получить шаблоны маршрутов непосредственно из атрибутов RoutePrefix и Route, что хорошо для этого проекта, поскольку все маршруты настроены таким образом.Я все еще чувствую, что должно быть более легкое / менее хрупкое решение - если кто-то ответит лучшим ответом, я приму его.

Это метод, который я добавил к своему базовому контроллеру:

protected Dictionary<String, String> GetRouteTemplates(Type controllerType, params String[] actions)
{
    var routePrefix = controllerType
        .GetCustomAttribute<RoutePrefixAttribute>()
        .Prefix;

    var routeTemplates = controllerType
        .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
        .Where(m => !actions.Any() || actions.Contains(m.Name))
        .Where(m => !m.IsDefined(typeof(NonActionAttribute), false) && m.IsDefined(typeof(RouteAttribute), false))
        .Select(m => new {m.Name, m.GetCustomAttribute<RouteAttribute>().Template})
        .ToDictionary(r => r.Name, r => $"/{routePrefix}/{r.Template}");

    return routeTemplates;
}

И на любом контроллере я хочу вернуть шаблоны URL:

[Route("urls")]
public JsonResult Urls(Int32 organisationId)
{
    var routeTemplates = GetRouteTemplates(GetType());

    return Json(routeTemplates);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...