Подтвердить что ты не робот

Получить URL из имен ApiController и Action в проекте, содержащем контроллеры и ApiControllers

Существующий проект имеет контроллеры, которые наследуют либо:

  • Controller: RouteTable.Routes.MapRoute с помощью "{controller}/{action}/{id}".
  • ApiController: GlobalConfiguration.Configure и в обратном вызове MapRoute с "api/{controller}/{id}".

Все работает отлично, но мне нужно создать URL-адреса для методов действий в обоих этих типах контроллеров. Дано:

  • имя или тип контроллера, который наследуется от любого из них, и
  • имя метода действия

Затем со стороны веб-сайта, как я могу создать правильные URL-адреса для веб-интерфейса API?

Я использую отражение, чтобы получить действия и имена контроллеров прямо сейчас, а затем с помощью UrlHelper.Action(actionName, controllerName, routeValueDictionary) получить правильный URL для маршрутов веб-сайтов.

Однако этот метод (конечно) генерирует URL-адреса, подобные этому для стороны WebAPI: /ApiControllerName/Get?parameter1=value, когда это должно быть /api/ApiControllerName?parameter1=value и отдельное знание о том, что это запрос GET.

Цель: это для страницы smoke test для веб-сайта, который использует атрибуты и отражение, чтобы решить, что делать с smoke test. Было бы неплохо иметь возможность использовать один и тот же атрибут во всем проекте, и, кроме того, было бы очень полезно использовать правильный UrlHelper, который знает таблицы маршрутизации и может создать правильный префикс, например /api/ вместо предположения кода, возможно, ошибочно, что маршруты API были зарегистрированы с помощью api и не, скажем, webapi.

Обновление

После продолжения исследования я нашел метод Url.HttpRouteUrl, который может генерировать URL WebAPI, но для этого требуется знать имя маршрута, а не имя метода действия.

Я сделал еще больше исследований по этому вопросу и не стал ближе к решению. Похоже, если вы знаете название маршрута соответствующего маршрута, вы можете легко сварить URL-адрес. Есть также некоторые возможные подсказки здесь и здесь. Но если есть несколько маршрутов для WebApi, откуда вы знаете, какой из них соответствует контроллеру и какое действие вы хотите? Было бы глупо переопределять то, что сам MVC уже делает при выборе контроллера и действий. Наверное, я мог бы создать URL-адрес из заданных параметров с помощью каждого маршрута WebApi, а затем запустить URL-адрес через его шаги (используя некоторые из приведенных выше ссылок) и посмотреть, будет ли он соответствовать желаемому контроллеру... yuck.

Там должен быть более простой способ.

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

4b9b3361

Ответ 1

Вот несколько способов сделать это:

  • Используя метод RouteUrl():

    var url1 = Url.RouteUrl(new { id = 1, controller = "...",  httproute = true });
    

Трюк, конечно, httproute = true. Установив это свойство, вы сообщаете, что вам нужны только маршруты http (маршруты веб-Api).

  • Используя метод HttpRouteUrl():

    var url2 = Url.HttpRouteUrl(null, new { id = 2, controller = ".." });
    
  • И еще один способ сделать это, используя непосредственно маршруты и httproute значение:

    var values = new RouteValueDictionary(new
    {
        id = 3,
        controller = "...",
        httproute = true
    });
    var url3 = RouteTable.Routes.GetVirtualPath(Request.RequestContext, values).VirtualPath;
    

3 способа в основном одинаковы. Поскольку вы не укажете маршрут, система попытается найти первое соответствие в соответствии с значениями маршрута. Например, предположим, что у вас есть ApiController, называемый RestfulController, а маршруты web-api настроены следующим образом:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

Используя первый метод, когда вы выполняете var url = Url.RouteUrl(new { id = 123, controller = "restful", httproute = true }); в MVC Controller, значение в url равно /api/restful/123.

Но если вы добавите новый маршрут ConstraintApi:

config.Routes.MapHttpRoute(
    name: "ConstraintApi",
    routeTemplate: "api2/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional },
    constraints: new { controller = "restful" }
);

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

URL, возвращаемый RouteUrl, равен /api2/restful/123.

Вам следует знать порядок, когда вы объявляете свои маршруты. Если маршрут DefaultApi добавлен до маршрута ConstraintApi, генерируемый url /api/restful/123.

Ответ 2

Существует библиотека Hyprlinkr, которая позволяет создавать URI из контроллера и действия с использованием конфигурации маршрута.

Ответ 3

Это похоже на взлом, но стоит попробовать, если вы только планируете использовать его для тестирования. Как вы упомянули, вы можете создать URL с именем маршрута. Таким образом, вы можете захватить все имена маршрутов и создать все возможные URL-адреса. Затем вам нужно проверить, разрешает ли URL-адрес необходимое вам действие или нет. Для этого вы можете использовать что-то вроде следующего: fooobar.com/info/362965/.... Основная идея заключается в том, что, если у вас есть URL-адрес, тогда сделайте поддельную переадресацию туда и получите данные маршрутизации из фреймворка.