#c# #asp.net-mvc #json #asp.net-web-api2
#c# #asp.net-mvc #json #asp.net-web-api2
Вопрос:
Я действительно борюсь с чем-то, с чем, я надеюсь, люди здесь могут помочь. Я пишу RESTful API в Web API 2. Всякий раз, когда я отправляю запрос в эту службу, ответ последовательно отправляется с Content-Type
помощью of text/plain
. Очевидно, что это никуда не годится, мой ответ должен быть Content-Type
application/json
. Я попробовал несколько предложений, которые я нашел в Google, но я не думаю, что понимаю всю картину.
Есть ли что-то особенное, что мне нужно сделать, чтобы мой веб-сервис отвечал application/json
контентом? Обратите внимание, что я хочу, чтобы это работало глобально во всем приложении, поэтому я не ищу способ изменить данный ответ и установить его тип содержимого — я хочу, чтобы это было поведение по умолчанию для всей веб-службы: если запрос содержит Accept
заголовок для application/json
, я хочу, чтобы мой веб-сервис возвращал этовместо Content-Type
text/plain
.
Отредактируйте, чтобы уточнить:
Мой ответ содержит объект с именем «responseData», который должен быть сериализован в JSON и включен в тело. В настоящее время я собираю свой ответ следующим образом:
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, responseData);
return response;
responseData
это POCO. Этот get правильно сериализуется как JSON и возвращается в ответе — единственной недостающей частью является тип содержимого, для которого неверно задано значение «текст / обычный». Я мог бы вручную изменить это для каждого отдельного ответа, который я составляю, но я хочу настроить это на глобальном уровне.
Комментарии:
1. Возвращает ли рассматриваемый API a
string
с содержимым JSON, которое вы создали самостоятельно?2.Проверьте это asp.net/web-api/overview/formats-and-model-binding/… ,msdn.microsoft.com/en-us/magazine/dn574797.aspx ,http://…,
3. @Corey в настоящее время ответ создается следующим образом:
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, responseData);
а затем я просто возвращаюсьresponse
в свое действие. Содержимое responseData хорошо сериализуется в JSON, но фактический заголовок content-type по-прежнему имеет значение text / plain : (4. @malkam похоже, что этот пост касается кодировок, меня интересуют типы контента
5. Опубликованная ссылка @malkam указывает на общее направление ответа, вам просто нужно еще немного покопаться в библиотеке, чтобы увидеть, какие есть варианты.
Ответ №1:
Хорошо, предполагая, что ваш responseData
является строкой, Content-type
заголовок будет text/plain
при создании HttpResponseMessage
. Не имеет значения, каково содержимое строки, поскольку не предпринимается никаких попыток определить это.
Решение состоит в том, чтобы создать соответствующий объект содержимого для вашего сообщения, инициализированный типом возвращаемого носителя:
HttpResponseMessage response = new HttpResponseMessage()
{
Content = new StringContent(
responseData,
Encoding.UTF8,
"application/json"
)
};
Существуют и другие методы, которые сводятся к возврату определенного типа объекта и позволяют библиотекам API сериализоваться в JSON или XML для вас по мере необходимости. Я предпочитаю, чтобы фреймворк выполнял всю работу за меня, где это возможно, но именно так вы могли бы добиться этого с помощью строки, которую создали сами.
Для получения строгого результата только для JSON удалите средство форматирования XML из конфигурации WebAPI и верните свой POCO.
В App_StartWebApiConfig.cs
, добавьте следующее к WebApiConfig.Register
методу:
config.Formatters.Remove(config.Formatters.XmlFormatter);
И для вашего API:
public class MyObject
{
public bool resu<
public string reason;
}
public class TestController : ApiController
{
public MyObject GetData()
{
MyObject result = new MyObject { result = "true", reason = "Testing POCO return" };
return resu<
}
}
Я запустил это и запросил /api/Test
у Chrome, который даже не упоминается application/json
в Accept
заголовке. Вот заголовки ответа до тех пор, пока он не попадет Content-Type
:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
И тело:
{"result":true,"reason":"Testing POCO return"}
Поскольку я отключил XML, по умолчанию используется JSON.
Комментарии:
1. Как упоминалось в моем вопросе, я пытаюсь найти глобальный способ настроить это, вместо того, чтобы явно определять тип контента для каждого создаваемого мной ответа. Возможно, моя формулировка была немного неясной — я отредактировал свой OP, чтобы, надеюсь, прояснить пару моментов.
2. Вы пробовали просто возвращать сам объект?
HttpResponseMessage
это нормально, когда вы хотите больше контролировать отдельные возвраты, но вы можете вернуть POCO и позволить библиотекам позаботиться о сериализации за вас — JSON или XML, в зависимости отAccept
заголовка в запросе.3. Я полагаю, проблема в том, что мне все равно придется возвращать 404 или 500 и т. Д., Если что-то пойдет не так — возможно ли это при использовании описанного подхода?
4. Да, путем
HttpResponseException
ввода .
Ответ №2:
Добавьте следующее в глобальный файл.asax.
protected void Application_Start()
{
JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
var jsonFormatter = new JsonNetFormatter(serializerSettings);
jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
GlobalConfiguration.Configuration.Formatters.Insert(0, jsonFormatter);
}
Комментарии:
1. Это предполагает, что кто-то создал какой-то jsonnet Formatter и не работает без этого понимания или более подробной информации.
Ответ №3:
Другой возможный источник описанной проблемы заключается в том, что в игре может быть перенаправление авторизации, как это было в нашем случае, когда один из инженеров решил повторно использовать аутентификацию пользователя для api.
Это означает, что входящие запросы перенаправлялись на страницу входа в систему, которая была text/html
ответом, который не мог быть проанализирован ReadAsync<>
. Конечно, глупая ошибка, но ее нелегко обнаружить.
Решением в этом случае было удалить аутентификацию пользователя и реализовать аутентификацию на основе HMAC для api.