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

Можно ли использовать периоды в маршрутах App.Net Web Api?

Я работаю над перемещением проекта API из необработанных обработчиков HTTP, где я использую периоды в путях:

http://server/collection/id.format

Я хотел бы следовать той же схеме URL-адресов в версии веб-Api (самостоятельно) и пробовал это:

var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
    name: "DefaultApiRoute",
    routeTemplate: "{controller}/{id}.{format}",
    defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
    constraints: null
);

К сожалению, это не похоже на разрешение (согласованное 404 on/foo,/foo/bar и /foo/bar.txt). Аналогичный шаблон с использованием косой черты перед "форматом" отлично работает:

var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
    name: "DefaultApiRoute",
    routeTemplate: "{controller}/{id}/{format}",
    defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
    constraints: null
);

Я еще не углубился в код для Web Api, и прежде чем я подумал, что попрошу здесь узнать, является ли это известным или, возможно, даже оправданным ограничением в Web Api.

ОБНОВЛЕНИЕ: Я забыл упомянуть, что "id" и "format" - это строки, которые, как оказалось, важны для решения этого вопроса. Добавление ограничения для исключения периодов из маркера "id" решает проблему 404.

4b9b3361

Ответ 1

Я не могу воспроизвести проблему. Это должно сработать. Здесь моя настройка:

  • Создайте новое консольное приложение .NET 4.0
  • Перейти к профилю .NET Framework 4.0
  • Установите Microsoft.AspNet.WebApi.SelfHost NuGet
  • Определите Product

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
  • Соответствующий API-контроллер:

    public class ProductsController : ApiController
    {
        public Product Get(int id)
        {
            return new Product
            {
                Id = id,
                Name = "prd " + id
            };
        }
    }
    
  • И хост:

    class Program
    {
        static void Main(string[] args)
        {
            var config = new HttpSelfHostConfiguration("http://localhost:8080");
    
            config.Routes.MapHttpRoute(
                name: "DefaultApiRoute",
                routeTemplate: "{controller}/{id}.{format}",
                defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
                constraints: null
            );
    
            using (var server = new HttpSelfHostServer(config))
            {
                server.OpenAsync().Wait();
                Console.WriteLine("Press Enter to quit.");
                Console.ReadLine();
            }
        }
    }
    

Теперь, когда вы запускаете это консольное приложение, вы можете перейти к http://localhost:8080/products/123.xml. Но, конечно, вы можете перейти к http://localhost:8080/products/123.json, и вы все равно получите XML. Поэтому возникает вопрос: как включить согласование контента с использованием параметра маршрута?

Вы можете сделать следующее:

    class Program
    {
        static void Main(string[] args)
        {
            var config = new HttpSelfHostConfiguration("http://localhost:8080");
            config.Formatters.XmlFormatter.AddUriPathExtensionMapping("xml", "text/html");
            config.Formatters.JsonFormatter.AddUriPathExtensionMapping("json", "application/json");

            config.Routes.MapHttpRoute(
                name: "DefaultApiRoute",
                routeTemplate: "{controller}/{id}.{ext}",
                defaults: new { id = RouteParameter.Optional, formatter = RouteParameter.Optional },
                constraints: null
            );

            using (var server = new HttpSelfHostServer(config))
            {
                server.OpenAsync().Wait();
                Console.WriteLine("Press Enter to quit.");
                Console.ReadLine();
            }
        }
    }

и теперь вы можете использовать следующие URL:

http://localhost:8080/products/123.xml
http://localhost:8080/products/123.json

Теперь вам может быть интересно, какая связь между параметром маршрута {ext}, который мы использовали в нашем определении маршрута, и методом AddUriPathExtensionMapping, потому что мы нигде не указали его. Ну, угадайте, что: он жестко закодирован в классе UriPathExtensionMapping до ext, и вы не можете его модифицировать, потому что он доступен только для чтения:

public class UriPathExtensionMapping
{
    public static readonly string UriPathExtensionKey;

    static UriPathExtensionMapping()
    {
        UriPathExtensionKey = "ext";
    }

    ...
}

Все это, чтобы ответить на ваш вопрос:

Можно использовать периоды в маршрутах App.Net Web Api?

Да.

Ответ 2

Я смог добиться этого, выполнив следующие действия: замените "*." на "*" в system.webServer.handlers в web.config, т.е. удалите период.

<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

Ответ 3

Будьте осторожны, чтобы установить параметр runAllManagedModulesForAllRequests в атрибуте modules в вашем web.config

<modules runAllManagedModulesForAllRequests="true">..</modules>

В противном случае он не будет работать в IIS (вероятно, он будет обрабатываться не управляемыми обработчиками).

Ответ 4

Я принимаю ответ Дарина (да, периоды можно использовать в URL-адресах маршрута), потому что это было точно правильно для моего примера, но бесполезно для меня. Это моя ошибка, поскольку я не указываю, что "id" - это строка, а не целое число.

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

var c = new HttpSelfHostConfiguration(b);
c.Routes.MapHttpRoute(
    name: "DefaultApiRoute",
    routeTemplate: "{controller}/{id}.{format}",
    defaults: new { id = RouteParameter.Optional, format = RouteParameter.Optional },
    constraints: new { id = "[^\\.]+" } // anything but a period
);

Добавление ограничения на предыдущий токен позволяет правильно разложить и обработать входящие URL-адреса. Без подсказки маркер "id" можно интерпретировать в соответствии с оставшейся степенью URL. Это всего лишь конкретный случай необходимости ограничить границы между строковыми параметрами в целом.

Да, периоды могут использоваться в маршрутах URL в веб-API Asp.Net, но если они должны следовать строковому параметру, обязательно примените правильное ограничение к маршруту.

Ответ 5

IIS перехватывает запросы с периодом загрузки файлов. В вашем web.config вы можете настроить IIS на игнорирование определенных URL-адресов, потому что webapi будет обрабатывать запросы вместо этого. Если вы хотите, чтобы IIS обрабатывал загрузку файлов, а также вызовы webapi процесса, вы можете добавить конфигурацию ManagedDllExtension в system.webServer.handlers в web.config.

      <add name="ManagedDllExtension" path="collection/*.*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />