Точечный символ '.' в MVC Web API 2 для запроса типа api / people / STAFF.45287

106

URL-адрес, который я пытаюсь разрешить работать, имеет вид: http://somedomain.com/api/people/staff.33311 (точно так же, как сайты, такие как LAST.FM, разрешают всевозможные знаки в своих URL-адресах RESTFul и WebPage. , например " http://www.last.fm/artist/psy'aviah " - действительный URL-адрес для LAST.FM).

Работают следующие сценарии: - http://somedomain.com/api/people/ - который возвращает всех людей - http://somedomain.com/api/people/staff33311 - также будет работать, но это не то, что я ' m после того, как я хочу, чтобы URL-адрес принимал «точку», как в примере ниже - http://somedomain.com/api/people/staff.33311 - но это дает мне

HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.

Я установил следующее:

  1. Контроллер PeopleController

    public IEnumerable<Person> GetAllPeople()
    {
        return _people;
    }
    
    public IHttpActionResult GetPerson(string id)
    {
        var person = _people.FirstOrDefault(p => p.Id.ToLower().Equals(id.ToLower()));
        if (person == null)
            return NotFound();
    
        return Ok(person);
    }    
  2. Файл WebApiConfig.cs

    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
    
        // Web API routes
        config.MapHttpAttributeRoutes();
    
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }

Я уже пробовал следовать всем советам этого сообщения в блоге http://www.hanselman.com/blog/ExperimentsInWackinessAllowingPercentsAnglebracketsAndOtherNaughtyThingsInTheASPNETIISRequestURL.aspx, но он все равно не сработает .. Я также думаю, что это довольно утомительно, и мне интересно, нет ли другого, лучший и более безопасный способ.

У нас есть внутренний идентификатор, подобный этому, поэтому нам нужно будет найти решение, чтобы так или иначе уместить точку, предпочтительно в стиле "." но при необходимости я открыт для альтернативных предложений по URL ...

Ив Шелпе
источник
10
Не ответ, но почему вы получаете 404 для somedomain.com/api/people/staff.33311 - по умолчанию IIS просматривает этот URL-адрес и видит файл . как расширение файла и вызывает обработчик статических файлов, минуя ваш MVC API. Принятый вами ответ (запуск всех управляемых модулей для всех запросов) работает, потому что вы заставляете каждый запрос к IIS проходить через конвейер ASP.NET (следовательно, ваши контроллеры)
Генри С.
Близкий пост здесь .
RBT

Ответы:

105

Следующие настройки в вашем web.configфайле должны решить вашу проблему:

<configuration>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
Киран Чалла
источник
4
Это сделало свое дело. Но есть ли уязвимости при установке этой опции? Почему это не стандартное поведение?
Yves Schelpe
2
Хорошо, для чьего-либо интереса: я вижу, что на мой вопрос выше был дан ответ здесь в принятом ответе на момент написания (ответ Капила Ханделвала): stackoverflow.com/questions/11048863/…
Ив Шелпе
2
Да, это сработало, шину другим, я хотел бы знать, какой именно модуль требуется для работы этой функции?
Greg Z.
3
Когда я попробовал это, это сработало бы, только если бы я поставил '/' в конце пути. Есть предложения, почему это так? С другой стороны, ответ ниже, который специально добавляет UrlRoutingModule вместо запуска всех модулей, также работал у меня, хотя по-прежнему с проблемой, что для работы требуется '/' в конце.
Николай Дам Ларсен
10
На stackoverflow.com/a/12151501/167018 стоит обратить внимание, если вас беспокоит (и это справедливо) влияние на производительность включения runAllManagedModulesForAllRequests.
Henry C
140

Добавьте к URL-адресу косую черту, например, http://somedomain.com/api/people/staff.33311/вместо http://somedomain.com/api/people/staff.33311.

Дэнни Варод
источник
3
@AgustinMeriles, мой ответ можно рассматривать скорее как обходной путь, чем как фактический ответ, зависит от вашей интерпретации вопроса.
Дэнни Варод
5
Однако это не работает, когда точка находится в конце раздела URL, например / people / member.
eYe
2
Нет, а что, если я не хочу косую черту в конце ?! Этого не должно быть.
Джош М.
1
@JoshM. Это обходной путь, я не писал ASP.NET. Также косая черта не влияет на запрос. Это, однако, поможет сделать ваши намерения более ясно , как и в google.com/my query goes here/VS. google.com/subDomain my query goes here.
Дэнни Варод 06
1
Да, это лучшее, что вам не нужно изменять web.config.
Тимоти Гонсалес
35

Я обнаружил, что добавление следующего до стандарта ExtensionlessUrlHandlerрешает проблему для меня:

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

Я не думаю, что имя на самом деле имеет такое большое значение, за исключением того, что оно, вероятно, помогает, если ваша IDE (в моем случае Visual Studio) управляет конфигурацией вашего сайта.

H / T на https://stackoverflow.com/a/15802305/264628

BrianS
источник
Я добавил его «после» стандартной строки, и он тоже работал нормально.
Джалал Эль-
Это должен быть принятый ответ. Не требует / в конце uri
daudihus
2
Спасибо за ДО, потому что он не работал после!
Mese,
Я считаю, что модули работают в порядке объявления, поэтому всегда ставьте более конкретные (или более важные) перед более общими.
BrianS
24

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

<system.webServer>
<modules>
    <remove name="UrlRoutingModule-4.0" />
    <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
</modules>
</system.webServer>
Грег З.
источник
Спасибо, я тоже не знаю, что он делает, но выглядит лучше, чем другое решение.
Thomas
1
похоже, перемещает модуль маршрутизации URL-адресов (что улавливает, что запрос включает расширение, а затем пытается обработать его как файл) в конец списка модулей, чего достаточно, чтобы поместить его после модуля, обрабатывающего запрос api . IMHO, это лучший обходной путь из тех, что я видел на SO, по крайней мере, ATTOW
Джеймс Мэннинг
1
Это не перемещение в конец списка, это удаление предварительного условия по умолчанию, что этот модуль запускается только для управляемых обработчиков. Конфигурация по умолчанию использует следующий формат:<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler" />
theta-fish
Спасибо - это объяснило бы поведение.
Грег З.
8

Я обнаружил, что мне нужно сделать больше, чем просто установить для runAllManagedModulesForAllRequestsатрибута значение true. Я также должен был убедиться, что обработчик URL-адресов без расширений настроен на просмотр всех путей. Кроме того, вы можете добавить еще одну настройку конфигурации бонусов, которая в некоторых случаях поможет. Вот мой рабочий Web.config:

<system.web>
    <httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <handlers>
        <remove name="WebDAV" />
        <remove name="OPTIONSVerbHandler" />
        <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
        <add name="ExtensionlessUrlHandler-Integrated-4.0"  path="*" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>

Обратите внимание, в частности, что ExtensionlessUrlHandler-Integrated-4.0имеет свой pathнабор атрибутов , чтобы *в отличие от *.(например).

Джош М.
источник
Меня только что укусил path="*.". Просто любопытно, по какой причине люди это устанавливают path="*."?
JustinP8
На самом деле, я изменил его на, path="*"и у меня возникла проблема, потому что мы размещаем сайт документации рядом с нашим WebAPI, и у этого сайта были проблемы с .jpg, .png и другими файлами с расширениями.
JustinP8
@ JustinP8 Тоже ставил <modules runAllManagedModulesForAllRequests="true" />? Это должно заставить .NET обрабатывать эти статические файлы.
Джош М.
1
Да. Я закончил этим. Мне это не очень нравится, потому что теперь все статические файлы проходят через конвейер .NET. К счастью, поскольку это служба webAPI, затронуты только материалы Swagger и Swashbuckle для документации / вспомогательного сайта API.
JustinP8
Я обнаружил, что это нарушает все запросы статических файлов. ошибка 500. У меня runAllManaged ... установлено значение true.
Сэм
2

Я застрял в этой ситуации, но добавление / в конце URL-адреса было для меня не очень удобным.

так что просто добавьте ниже в тег web.config, handlers и все будет хорошо.

<add name="Nancy" path="api" verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" allowPathInfo="true" />
Хаваджа Асим
источник
Можете ли вы объяснить, что такое Нэнси и будет ли это библиотека для включения в проект? Спасибо!
голубоватый
1

Я обнаружил, что у меня работают оба способа: либо установить для runAllManagedModulesForAllRequests значение true, либо добавить ExtentionlessUrlHandler следующим образом. Наконец, я решил добавить extensionUrLHandler, поскольку runAllManagedModulesForAllRequests действительно влияет на производительность сайта.

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <remove name="WebDAV" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*" 
       type="System.Web.Handlers.TransferRequestHandler" 
       preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
Xuemei
источник
1

Я бы использовал это в файле Web.config:

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

раньше стандартного ExtensionlessUrlHandler.

Например, в моем случае я поместил это здесь:

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ManagedFiles" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

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

голубоватый
источник
0

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

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

public class GetuserdetailsbyuseridController : ApiController
{
     string getuserdetailsbyuserid(string userId)
     {
        //some code to get user details
     }
}

Взгляните на приведенный ниже URL-адрес, где пользователь вводит свой идентификатор пользователя, чтобы получить свои личные данные:

http://mywebsite:8080/getuserdetailsbyuserid/foo.bar

Поскольку вам нужно просто получить некоторые данные с сервера, мы используем команду http GET. При использовании GETвызовов любые входные параметры можно передавать только во фрагментах URL.

Итак, чтобы решить мою проблему, я изменил http-глагол своего действия на POST. POSTГлагол Http также может передавать любой пользовательский или не пользовательский ввод в теле. Итак, я создал данные JSON и передал их в тело http- POSTзапроса:

{
  "userid" : "foo.bar"
}

Измените определение вашего метода, как показано ниже:

public class GetuserdetailsbyuseridController : ApiController
{
     [Post]
     string getuserdetailsbyuserid([FromBody] string userId)
     {
        //some code to get user details
     }
}

Примечание : Более того, когда использовать GETглагол и когда использовать POSTглагол здесь .

RBT
источник
Не подходящее решение, если вы создаете REST API.
Мустафа Озтюрк