Контроллер MVC обрабатывает отправленный JSON в виде строки

У меня есть стороннее приложение, которое отправляет на мой сайт POST-запросы с application / json в теле. Я могу записать строго типизированный объект как:

публичная строка Postback ([FromBody] MyResponse myResponse)

Моя проблема в том, что после того, как я так много поработал, меня направили на поддержку 2-го типа на той же конечной точке. Поэтому мне нужно принять строковое значение (вместо результата привязки модели), а затем JsonConvert строки к одному или другому из двух возможных типов.

Итак, я полагаю, что должен изменить подпись моего метода на:

публичная строка Postback ([FromBody] строка _sfResponse)

Но строка всегда показывает null (с директивой [FromBody] или без нее). Похоже, ModelBinder настаивает на участии. В любом случае, чтобы убедить его не делать этого?

На всякий случай что-нибудь про маршрутизацию:

routes.MapRoute(
    "MyPostback",
    url: "rest/V1/sync/update",
    defaults: new { controller = "Admin", action = "MyPostback" }    
);

Действие контроллера:

[System.Web.Mvc.HttpPost]
[System.Web.Mvc.AllowAnonymous]
public string MyPostback([System.Web.Http.FromBody][ModelBinder(typeof(MyResponseModelBinder))] MyResponseToProduct _sfResponse)
{
//stuff
}

Отправляемый json сложнее среднего, но имейте в виду, что когда подпись контроллера ссылается на строго типизированный объект, соответствующий этому json, все работает. (и повторюсь - мне нужно учитывать 2 разных типа входящих, поэтому мне нужно взять строку в начале вместо модели).

 {
"results": [
    {
        "errors": {
            "error": "No Error"
        },
        "sku": "70BWUS193045G81",
        "status": "success",
        "productId": "123"
    },
    {
        "errors": {
            "error": "No Error"
        },
        "sku": "70BWUS193045G82",
        "status": "success",
        "productId": "123"
    }
],
"validationType": "products",
"messageId": "ac5ed64f-2957-51b4-8fbb-838e0480e7ad"
}

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

public class MyResponseModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        HttpRequestBase request = controllerContext.HttpContext.Request;
        int id = Convert.ToInt32(request.Form.GetValues("Id"));

        return new MyResponseToProduct()
        {
            results = new List<MyResponseToProduct.Result>()
        };
    }
}

Когда я проверяю значения в привязке пользовательской модели, controllerContext.HttpContext.Request.Form пуст (это отправка POST, поэтому тело действительно должно быть там, не так ли?)

Я могу видеть свои битовые данные в bindingContext.PropertyMetadata, но я не могу представить, что должен зайти так глубоко.

Очень странно, почему Request.Form пуст.


person justSteve    schedule 05.08.2019    source источник


Ответы (1)


ASP.Net Core:

Вы можете объявить аргумент действия вашего контроллера как object, а затем вызвать для него ToString(), например:

[HttpPost]
public IActionResult Foo([FromBody] object arg)
{
    var str = arg?.ToString();
    ...
}

В этом примере переменная str будет содержать строку JSON из тела запроса.

ASP.Net MVC:

Поскольку предыдущий вариант не работает в старом ASP.Net MVC, в качестве варианта вы можете читать данные непосредственно из свойства Request в действии вашего контроллера. В этом вам поможет следующий метод расширения:

public static string GetBody(this HttpRequestBase request)
{
    var requestStream = request?.InputStream;
    requestStream.Seek(0, System.IO.SeekOrigin.Begin);
    using (var reader = new StreamReader(requestStream))
    {
        return reader.ReadToEnd();
    }
}

И ваше действие будет выглядеть так:

[HttpPost]
[Route("test")]
public ActionResult Foo()
{
    string json = Request.GetBody();
    ...
}
person Vitalii Ilchenko    schedule 05.08.2019
comment
Спасибо за ответ, но: _arg.ToString () //System.Object - person justSteve; 06.08.2019
comment
Я протестировал его в проекте ASP.Net Core, прежде чем оставить его здесь. str переменная содержит содержимое тела запроса в виде строки. Не могли бы вы показать свой код? - person Vitalii Ilchenko; 06.08.2019
comment
Мой проект - MVC4. - person justSteve; 06.08.2019
comment
@justSteve Я обновил свой ответ (добавлен параметр для старого ASP.Net MVC) - person Vitalii Ilchenko; 06.08.2019
comment
Очень признателен за то, что вы застряли с проблемой достаточно долго, чтобы ее решить. Престижность. - person justSteve; 09.08.2019