У меня возникла проблема с порядком выполнения конвейера запросов веб-API ASP.NET.
В соответствии с документацией ASP.NET Web API (доступно здесь), глобальные обработчики сообщений должны быть выполнены до механизма маршрутизации.
На этом изображении MessageHandler1
является глобальным обработчиком сообщений, тогда как MessageHandler2
относится к Маршруту 2.
Я создал очень простой пример, чтобы показать, что, похоже, проблема в порядке выполнения... или я действительно пропускаю что-то важное.
У меня есть этот контроллер
public class FooController : ApiController {
[HttpPut]
public string PutMe() {
return Request.Method.Method;
}
}
Он принимает только запросы PUT
.
Приложение настроено как таковое:
protected void Application_Start() {
var configuration = GlobalConfiguration.Configuration;
configuration.MessageHandlers.Add( new SimpleMethodOverrideHandler() );
configuration.Configuration.Routes.MapHttpRoute(
name: "Foo",
routeTemplate: "api/foo",
defaults: new { controller = "foo", action = "putme" },
constraints: new { put = new HttpPutOnlyConstraint() }
);
}
SimpleMethodOverrideHandler
- очень простой DelegatingHandler
, который просто изменил метод запроса в соответствии с параметром "method"
в строке запроса.
public class SimpleMethodOverrideHandler : DelegatingHandler {
protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken ) {
var method = request.RequestUri.ParseQueryString()["method"];
if( !string.IsNullOrEmpty( method ) ) {
request.Method = new HttpMethod( method );
}
return base.SendAsync( request, cancellationToken );
}
}
В принципе, запрос /api/foo?method=put
в моем браузере запускает метод FooController
PutMe
.
В самом деле, как видно ранее, обработчик сообщений обрабатывает запросы до того, как он будет передан в HttpRoutingDispatched
.
Наконец, вот как определяется константа HttpPutOnlyConstraint
:
public class HttpPutOnlyConstraint : IHttpRouteConstraint {
public bool Match( HttpRequestMessage request,
IHttpRoute route,
string parameterName,
IDictionary<string, object> values,
HttpRouteDirection routeDirection ) {
return request.Method == HttpMethod.Put;
}
}
Хорошо, проблема в том, что когда я запрашиваю /api/foo?method=put
в своем браузере, программа сначала вводит метод HttpPutOnlyConstraint
Match
, что неверно.
Если мы ссылаемся на ранее связанный образ, обработчик сообщения должен быть выполнен первым, к сожалению, это не так.
Итак, конечно, Match
возвращает false
, и никакой контроллер/действие не найдено для запроса, выполняется 404.
Если я удалю ограничение из определения маршрута, программа войдет в SimpleMethodOverrideHandler
, метод запроса будет успешно изменен и сможет сопоставить и выполнить мой метод контроллера.
Я что-то делаю неправильно? Есть ли секретный параметр конфигурации, чтобы знать, чтобы делать такие вещи?: -)
Если кому-то нужен весь проект, он доступен здесь [zip файл 7KB].
Спасибо.