Подтвердить что ты не робот

WebAPI не возвращает XML даже с правильным заголовком Accepts

Я использую ASP.NET WebAPI RC и хостинг контроллера API, ничего не подозревая об этом. Все отлично работает с JSON, но я тестирую различные форматы, используя заголовок Accepts, и там, где у меня возникают проблемы.

Я использую jQuery для выдачи запроса AJAX и установки параметра 'dataType' этого запроса. Это правильно устанавливает соответствующий заголовок Accept, как вы увидите ниже.

$.ajax({
    type: method,
    url: url,
    dataType: "xml",
    data: data || null,
    success: function (data) {
        // omitted
    }
});

Здесь вы можете сохранить запрос/ответ скрипта. Как видно, заголовок Accept отвечает application/xml, но WebAPI возвращает JSON. Я также попытался вручную настроить заголовок Accept только на "application/xml" (поэтому он также не содержит текст /html ), но безрезультатно.

Что, черт возьми, я пропустил? (примечание: я обрезал конфиденциальную информацию в данных, но не изменял ее в противном случае)

GET http://localhost/insp**snip**6716 HTTP/1.1
Host: localhost
Connection: keep-alive
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.60 Safari/537.1
Accept: application/xml, text/xml, */*; q=0.01
Referer: http://localhost/inspector/api/test?
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: m=34e2:|2c69:t|47ba:t|4e99:t; .INSPECTOR3COOKIE=08BA683091E2A457B1832E9B*snip*F911D9ED97076


HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
Persistent-Auth: true
X-Powered-By: ASP.NET
Date: Fri, 03 Aug 2012 22:27:42 GMT
Content-Length: 1816

{"Id":2416716,"ProjectId":36,"Url":"http://ins *snip, but obviously this is JSON not XML *

Я хотел бы указать, что я не настраиваю какие-либо форматиры в AppStart или что-то еще, насколько я понимаю, форматы JSON и XML должны быть включены по умолчанию.

ОБНОВЛЕНИЕ: Я понял это - проверьте мой собственный ответ ниже

4b9b3361

Ответ 1

Я понял это!

У меня это было в моем AppStart, потому что я хотел, чтобы сериализатор Xml не был сериализатором DataContract:

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;

ОДНАКО... видимо, в моей модели есть что-то, что заставляет Xml Serializer думать, что он не может сериализовать его. Я предполагаю, что WebAPI решил использовать вместо этого форматтер JSON.

Это совершенно неинтуитивно понятно, что этот безобидный вид может повлиять на то, какой форматтер используется. Надеемся, что пользователи WebAPI видят это:)

Какой-то инструмент, который позволит вам понять входы и выходы процесса согласования контента, чтобы вы могли отлаживать такие проблемы, как это было бы хорошо.

Ответ 2

У меня была такая же проблема, но я исправил ее, добавив конструкторы по умолчанию ко всем моделям, которые я возвращал.

Сериализатор XML создает пустые объекты модели, а затем заполняет его через сеттеры свойств. Если сеттеры защищены или закрыты, то это свойство не будет сериализовано либо

Ответ 3

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

При поиске "лучшего" форматирования, DefaultContentNegotiator, как правильно описано AASoft, запрашивает каждый из разработчиков форм, могут ли они поддерживать определенный тип. Затем он сопоставляет эти форматирования с заголовками accept в запросе.

Если он не находит никакого совпадения на основе заголовков accept, он выбирает первое, которое может сериализовать тип, в данном случае форматировщик JSON. Однако вы можете настроить DefaultContentNegotiator вместо того, чтобы возвращать формат по умолчанию, а затем вернуть код статуса 406 None Accepted. Это указывает клиенту, что не может быть найдено совпадающее представление и вместо отправки данных, которые клиент может не использовать, генерирует ответ об ошибке.

Настройка этого параметра описана в блоге "Обновления веб-API ASP.NET - 14 мая" [1] в разделе "Улучшения согласования содержимого".

Надеюсь, что это поможет,

Хенрик

[1] http://blogs.msdn.com/b/henrikn/archive/2012/05/14/asp-net-web-api-updates-may-14.aspx

Ответ 4

Ответ уже предоставлен, но я подумал, что поместил свои выводы так, чтобы это было полезно для всех, кто придет позже.

Преступник был IEnumerable. Например, возвращающий объект Class Album, содержащий IEnumerable и никогда не получающий XML-возврат, - только JSON.

Я использовал

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true; 

в Global.asax. Что действительно необходимо для возврата xml. Тем не менее я не получал XML обратно.

Затем я изменил IEnumerable в List, и он работал нормально. Похоже, XML Formatter в Web API не может обрабатывать IEnumerable в обратных объектах.

Надеюсь, что это поможет.

Ответ 5

Я работал с веб-сервисами на Java, но принцип тот же.

Поддерживает ли ваш код веб-службы XML-запросы? Возможно, возвращение JSON является отказом в случае, если он не может поддерживать представление, которое вы запрашиваете в Accept.

Вы можете показать код?

Ответ 6

Как продолжение этого. У нас была эта проблема, когда у нас был список объектов в нашей модели возврата, но у объекта в списке не было конструктора без параметров. Наш код выглядел так:

public class ReturnClass
{
    public int Value { get; set; }

    public List<OtherClass> ListOfThings { get; set; }
}

public class OtherClass 
{
    public int OtherValue { get; set; }

    public OtherClass(OtherObject o) 
    {
       this.OtherValue = o.OtherValue;
    }  
}

Нам просто пришлось добавить конструктор без параметров для объекта SubClass.

public class ReturnClass
{
    public int Value { get; set; }

    public List<OtherClass> ListOfThings { get; set; }
}

public class OtherClass 
{
    public int OtherValue { get; set; }

    public OtherClass(OtherObject o) 
    {
       this.OtherValue = o.OtherValue;
    }

    public OtherClass()
    {
    }

}

Ответ 7

Будьте осторожны с использованием nullable int для любого из свойств, которые вы можете сериализовать. NULL-int с набором config.Formatters.XmlFormatter.UseXmlSerializer = true заставит Web API возвращать JSON независимо от того, что говорит ваш заголовок accept

Ответ 8

Я просто хочу добавить еще одну причину этого, свойства с внутренним get или set. Тип, который генерируется VS, когда вы добавляете свойства в класс, нажав Ctrl -.

like public string Foo {get; internal set;}