X-HTTP-Method-Override предоставляет NotFound (404) в веб-API ASP.NET

Я пытаюсь реализовать переопределение метода HTTP, следуя шагам, описаннымВот, По сути, я создаю DelegatingHandler, похожий на следующий, и добавляю его в качестве обработчика сообщений.Application_Start

public class MethodOverrideHandler : DelegatingHandler      
{
    readonly string[] _methods = { "DELETE", "HEAD", "PUT" };
    const string _header = "X-HTTP-Method-Override";

    protected override Task SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Check for HTTP POST with the X-HTTP-Method-Override header.
        if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
        {
            // Check if the header value is in our methods list.
            var method = request.Headers.GetValues(_header).FirstOrDefault();
            if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
            {
                // Change the request method.
                request.Method = new HttpMethod(method);
            }
        }
        return base.SendAsync(request, cancellationToken);
    }
}

У меня есть следующие методы, определенные на моем контроллере:

persons/{id}, ПОЛУЧИТЬpersons/{id}, ПОЛОЖИЛpersons/{id}, УДАЛЯТЬ

Я могу позвонить им через ихродные" методы и они работают как положено. Тем не менее, когда я пытаюсь вызвать их через POST, отправкаX-HTTP-Method-Override заголовок с "УДАЛЯТЬ" или же "ПОЛОЖИЛ"ДаетНе найден (404) ошибка. Важно добавить, что, когда он дает эту ошибку, он никогда не достигаетMethodOverrideHandler - Я поставил точку останова, которая никогда не срабатывает; он достигает точки останова, когда я вызываю обычные команды DELETE и PUT.

Я даже попытался добавить другой метод:

persons/{id}, СООБЩЕНИЕ

Когда я делаю это, я получаюМетод не разрешен (405) вместо.

Я думал, что обработчики сообщений запускались ДО диспетчеров маршрутизации и контроллера. Почему это дает мне 404?

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

routes.MapHttpRoute(
    String.Format("{0}_{1}", operation.Name, service.ServiceId),
    String.Format("{0}/{1}", service.RoutePrefix, routeTemplateAttribute.Template),
    defaults,
    new { httpMethod = GetHttpMethodConstraint(operation) });
[HttpDelete, RouteTemplate("persons/{id}")]
public HttpResponseMessage DeletePerson(string id)
{
    // ...
}

РЕДАКТИРОВАТЬ:GetHttpMethodConstraint код ниже.

private static HttpMethodConstraint GetHttpMethodConstraint(MethodInfo methodInfo)
{
    var methodResolver = HttpMethodResolver.FromMethodInfo(methodInfo);
    return new HttpMethodConstraint(methodResolver.Resolve());
}
internal class HttpMethodResolver
{
    private MethodInfo _methodInfo;

    private HttpMethodResolver(MethodInfo methodInfo)
    {
        _methodInfo = methodInfo;
    }

    public static HttpMethodResolver FromMethodInfo(MethodInfo methodInfo)
    {
        return new HttpMethodResolver(methodInfo);
    }

    public string[] Resolve()
    {
        var verbs = new List();

        if (MethodHasAttribute())
        {
            verbs.Add(HttpMethod.Get);
        }
        else if (MethodHasAttribute())
        {
            verbs.Add(HttpMethod.Post);
        }
        else if (MethodHasAttribute())
        {
            verbs.Add(HttpMethod.Delete);
        }
        else if (MethodHasAttribute())
        {
            verbs.Add(HttpMethod.Put);
        }
        else
        {
            throw new ServiceModelException("HTTP method attribute should be used");
        }

        return verbs.Select(v => v.Method).ToArray();
    }

    private bool MethodHasAttribute() where T : Attribute
    {
        return GetMethodAttribute() != null;
    }

    private T GetMethodAttribute() where T : Attribute
    {
        return _methodInfo.GetCustomAttributes(typeof(T), true).FirstOrDefault() as T;
    }
}
 alextercete19 дек. 2012 г., 21:45
Для справки, моя проблема прояснилась следующим ответом:stackoverflow.com/a/13959148/1288760.
 Ben Foster29 окт. 2012 г., 21:48
Вы пытались изменить свой метод действия сDeletePerson к?Delete
 tugberk30 окт. 2012 г., 10:17
Я ответил ниже, но если вы можете заархивировать ваше приложение и положить его куда-нибудь, я могу посмотреть, как я нене могу воспроизвести вашу проблему.

Ответы на вопрос(2)

Решение Вопроса

но я нене в состоянии. Здесь вы можете скачать мой простой проект с помощью вашего обработчика сообщений:https://dl.dropbox.com/u/20568014/WebApplication6.zip

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

Кроме того, я думаю, что вашIRouteConstraint реализация,GetHttpMethodConstraintвыглядит подозрительно для меня.

Вот мой регистрационный код для обработчика сообщений:

protected void Application_Start(object sender, EventArgs e) {

    var config = GlobalConfiguration.Configuration;
    config.Routes.MapHttpRoute(
        "DefaultHttpRoute",
        "api/{controller}/{id}",
        new { id = RouteParameter.Optional }
    );

    config.MessageHandlers.Add(new MethodOverrideHandler());
}
 tugberk30 окт. 2012 г., 18:24
@alexterceteGetHttpMethodConstraint запускается перед обработчиками сообщений. Мои деньги на то, с чем связана твоя проблема.GetHttpMethodConstraint
 alextercete30 окт. 2012 г., 18:21
Спасибо за ваш ответ! я весьма уверенGetHttpMethodConstraint работает правильно, так как я могу вызывать методы, объявленные как "ПОЛОЖИЛ" а также "УДАЛЯТЬ" с успехом используя ихродные" глаголы. Проблема возникает только тогда, когда я вызываю с использованием POST и заголовка переопределения метода. Я попытался зарегистрировать обработчик сообщений до и после сопоставления маршрутов очереди, и он не работал. Я также удалил другой обработчик сообщений, который я зарегистрировал, чтобы проверить, не вызывает ли это проблему, но не повезло. Я могу подтвердить, что ваше приложение работает, поэтому оно не имеет ничего общего с инфраструктурой или чем-то еще.
 alextercete04 нояб. 2012 г., 23:26
Я награждаю вас за ваши усилия ответом. Однако, так как я все еще не решил свою проблему, я оставляю это как оставшийся без ответа. Спасибо, в любом случае!
 alextercete30 окт. 2012 г., 18:36
Я добавил код дляGetHttpMethodConstraint на вопрос. Я думаю, что в этом нет ничего особенного ...

У меня такая же проблема. Похоже, что ограничения маршрута проверяются перед обработчиками сообщений.

Поэтому я создал собственное ограничение, которое знает, что нужно проверять переопределенный метод HTTP:

class OverrideableHttpMethodConstraint : HttpMethodConstraint
{
    public OverrideableHttpMethodConstraint(HttpMethod httpMethod) : base(httpMethod)
    {
    }

    protected override bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object=""> values, HttpRouteDirection routeDirection)
    {
        IEnumerable<string> headerValues;
        if (request.Method.Method.Equals("POST", StringComparison.OrdinalIgnoreCase) && 
            request.Headers.TryGetValues("X-HTTP-Method-Override", out headerValues))
        {
            var method = headerValues.FirstOrDefault();
            if (method != null)
            {
                request.Method = new HttpMethod(method);
            }
        }

        return base.Match(request, route, parameterName, values, routeDirection);
    }
}
</string></string,>

Ваш ответ на вопрос