ASP.NET Core MVC: как получить необработанный JSON привязан к строке без типа?
Как и этот старый вопрос о предыдущих версиях ASP.NET, я хочу, чтобы тело запроса HTTP POST было привязано к строке. Кажется, что метод связывается, но value
имеет значение null, когда ASP.NET вызывает мой метод контроллера:
namespace Demo.Controllers
{
[Route("[controller]")]
public class WebApiDemoController : Controller
{
...
// POST api/values
[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]string value)
{
// expected: value = json string, actual: json = null.
}
Должен ли я все-таки ухватиться за тело из потока? Или это просто работает? При тестировании вышеописанного метода я использовал следующие заголовки http:
Accept: Application/json
Content-Type: Application/json;charset=UTF-8
Я передаю следующее в теле: { "a": 1 }
Я НЕ хочу привязываться к строковой переменной с именем a. Я хочу связать любой JSON, который я получаю, а затем я хочу использовать контент JSON, любой произвольный контент, из моего метода.
Если я понял документацию, атрибут [FromBody]
должен был сделать то, что я хотел, но я предполагаю, что основной механизм привязки MVC для ASP.NET не привяжет json к "строковому значению", но, возможно, Я мог бы сделать что-то еще, что дает мне эквивалентный уровень гибкости.
Подобный вопрос здесь дает мне идею, может быть, я должен был написать [FromBody] dynamic data
вместо использования [FromBody] string value
.
Обновление. Об этом следует подумать, прежде чем делать это, потому что если вы хотите, чтобы ядро core.net обрабатывало JSON и XML-кодировку, вы просто убили эту возможность. Некоторые типы серверов REST могут и часто имеют требования к поддержке типов контента XML и JSON, по крайней мере, тех, с которыми я столкнулся, которые имеют документы стандартов.
Ответы
Ответ 1
Следующее работает в .net core 1.x, но не в .net core 2.x.
Как я уже [FromBody]dynamic data
, решение состоит в том, чтобы использовать [FromBody]dynamic data
качестве моего списка параметров, используя вместо string
dynamic
, и я получу JObject
.
Предостережение. Если ваша архитектура требует, чтобы один и тот же сервер WebApi одинаково свободно создавал XML и JSON, в зависимости от записей заголовка типа контента, такая стратегия прямого использования JSON может иметь неприятные последствия. (Поддержка XML и JSON в одной и той же службе возможна при достаточной работе, но затем вы берете материал, который был далее вверх по конвейеру ресурсов MVC, и перемещаете его вниз в методы вашего контроллера, что, оказывается, противоречит духу MVC где модели приходят к вам как POCOs уже разобраны.)
Как только вы преобразуете в строку внутри метода, конвертирование входящего JObject
(Newtonsoft.JSON в типе данных памяти для JSON) в строку.
Нашел другой ответ здесь.
Пример кода, благодаря Jeson Martajaya:
С динамическим:
[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]dynamic value)
{
//...
}
Пример кода с JObject:
[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]Newtonsoft.Json.Linq.JObject value)
{
//...
}
Ответ 2
Самый чистый вариант, который я нашел, добавляет ваш собственный простой InputFormatter:
public class RawJsonBodyInputFormatter : InputFormatter
{
public RawJsonBodyInputFormatter()
{
this.SupportedMediaTypes.Add("application/json");
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
using (var reader = new StreamReader(request.Body))
{
var content = await reader.ReadToEndAsync();
return await InputFormatterResult.SuccessAsync(content);
}
}
protected override bool CanReadType(Type type)
{
return type == typeof(string);
}
}
И в вашем Startup.cs внутри ConfigureServices:
services
.AddMvc(options =>
{
options.InputFormatters.Insert(0, new RawJsonBodyInputFormatter());
});
Это позволит вам получить необработанную полезную нагрузку JSON в ваших контроллерах:
[HttpPost]
public IActionResult Post([FromBody]string value)
{
// value will be the request json payload
}
Ответ 3
В качестве альтернативы вы также можете просто принять JObject
, и вы сможете использовать Linq для Json даже прямо ToString()
, если вам действительно нужна строка.
Ответ 4
Я вижу, что Сэм уже проголосовал за то, что он говорил почти то же самое, но при тестировании с помощью Postman я обнаружил, что если я установлю тело запроса на простое строковое выражение с двойными кавычками, то ASP свяжет его с по умолчанию '[ FromBody] string value.
"just send your string like this without any curly braces"
Не уверен, что приложение /json должно принимать данные в этом формате. Хотелось бы надеяться, разместив это, кто-то знающий будет трудиться и указать, действительно ли это или нет.
Ответ 5
Следующие два метода работают в ASP.NET core 2 для чтения необработанной строки json.
1) Этот имеет лучшую производительность.
[HttpPost]
public async Task<ActionResult<int>> Process()
{
string jsonString;
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
jsonString = await reader.ReadToEndAsync();
}
2)
[HttpPost]
public async Task<ActionResult<int>> Process([FromBody]JToken jsonbody)
{
var jsonString = jsonBody.ToString();
Ответ 6
Вам нужен тип для привязки данных. Пример:
public class Person
{
public string Name {get; set;}
}
для данных { "Name" : "James"}
Ответ 7
Если вы хотите получить строку, вам нужно передать ее как строку. Ваш JSON
должен быть заключен в кавычки:
'{ "a": 1 }'