Переопределить заголовки содержимого для запроса POST MVC

Я новичок в MVC, поэтому я надеюсь, что есть решение моей проблемы. Я использую стороннее оборудование для связи с моим веб-API MVC. Аппаратное обеспечение отправляет запросы в формате JSON, который я могу извлечь совершенно нормально. Тем не менее, я пытаюсь изменить параметр этих запросов на объекты привязки модели из-за конфликтов.

например.

        Public Function POSTRequest(Action As String, Stamp As String) As HttpResponseMessage
           ...
        End Function

        Public Function POSTRequest(Action As String, OpStamp As String) As HttpResponseMessage
           ...
        End Function

Таким образом, эти два метода используют одну и ту же визитную карточку, поэтому оба они не могут существовать в одном контроллере.

В связи с этим я создал объекты привязки модели для размещения этих параметров. Проблема в том, что, как только я это сделаю, веб-API жалуется на запрос о том, что "Content-Type" не определен. Посмотрев на это, стороннее оборудование не отправляет контент с запросом. Глядя на сеть, я обнаружил, что это приводит к тому, что браузер рассматривает это как тип контента "application/octet-stream". Это не может затем перевести это в объект привязки, определенный как параметр.

У нас нет контроля над сторонним оборудованием, поэтому мы не можем определить тип контента для этих запросов. Итак, мой вопрос: есть ли способ перехватить эти запросы и добавить к ним тип контента? Или еще один способ обойти это?

Ответ 1

Я думаю, вы можете использовать ActionFilterAttribute. См. Документацию: Создание пользовательских фильтров действий.

В вашем случае вы можете использовать следующий образец (на С#, так как мои навыки VB устарели). Он переопределяет любой заголовок запроса Content-Type с использованием значения application/json. Обратите внимание, что вам может потребоваться усилить его, чтобы поддерживать все типы HttpContent (например, я не думаю, что это нужно использовать для запросов MultiPart).

public class UpdateRequestAttribute: ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        actionContext.Request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
        base.OnActionExecuting(actionContext);
    }
}

Затем вы добавляете этот атрибут в свой класс контроллера, например:

[UpdateRequest]
public class HomeController : ApiController
{
    //[...]
}

В этом случае все запросы к контроллеру Home будут иметь переопределенные Content-Type.


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

Обработчики сторон сервера ASP.net

Например, этот обработчик сообщения будет устанавливать запрос Content-Type в application/json, если он в настоящее время пуст.

public class CustomMessageHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Content.Headers.ContentType == null)
        {
            request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
        }
        return base.SendAsync(request, cancellationToken);
    }
}

Наконец, вот как обновить WebApiConfig, чтобы добавить обработчик сообщения в конвейер:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MessageHandlers.Add(new CustomMessageHandler());

        // Other configuration not shown... 

    }
}

Ответ 2

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

[Route("Request1")]
Public Function POSTRequest(Action As String, Stamp As String) As HttpResponseMessage
           ...
        End Function
        [Route("Request2")]
        Public Function POSTRequest(Action As String, OpStamp As String) As HttpResponseMessage
           ...
        End Function

Не забудьте включить маршрутизацию атрибутов, добавив MapHttpAttributeRoutes в файл webapiconfig.vb

Public Module WebApiConfig
    Public Sub Register(ByVal config As HttpConfiguration)
        ' Web API configuration and services

        ' Web API routes
        config.MapHttpAttributeRoutes()

        config.Routes.MapHttpRoute(
            name:="DefaultApi",
            routeTemplate:="api/{controller}/{id}",
            defaults:=New With {.id = RouteParameter.Optional}
        )
    End Sub
End Module