Вопрос по model-binding, asp.net-web-api, asp.net-mvc, asp.net-mvc-4 – Обновление до MVC4 RC: MediaTypeFormatter недоступен для чтения объекта типа «TestRequestModel» из содержимого с типом носителя «undefined»

8

Я использовал бета-версию MVC4 и в настоящее время работаю над обновлением до недавно выпущенной версии RC.

It appears that model-binding complex request types has changed, но я не могу понять, как / что я делаю неправильно.

Например, скажем, у меня есть следующий контроллер API:

public class HomeApiController : ApiController
{
    public TestModel Get()
    {
        return new TestModel
        {
            Id = int.MaxValue,
            Description = "TestDescription",
            Time = DateTime.Now
        };
    }
}

Это дает ожидаемый результат:

<TestModel xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/xxxx">
    <Description>TestDescription</Description>
    <Id>2147483647</Id>
    <Time>2012-06-07T10:30:01.459147-04:00</Time>
</TestModel>

Теперь скажите, что я просто изменяю подпись, принимая тип запроса, например так:

public TestModel Get(TestRequestModel request)
{
    ...

public class TestRequestModel
{
    public int? SomeParameter { get; set; }
}

Теперь я получаю следующую ошибку:

<Exception xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.Web.Http.Dispatcher">
    <ExceptionType>System.InvalidOperationException</ExceptionType>
    <Message>
        No MediaTypeFormatter is available to read an object of type 'TestRequestModel' from content with media type ''undefined''.
    </Message>
    <StackTrace>
    at System.Net.Http.HttpContentExtensions.ReadAsAsync[T](HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) at System.Net.Http.HttpContentExtensions.ReadAsAsync(HttpContent content, Type type, IEnumerable`1 formatters, IFormatterLogger formatterLogger) at System.Web.Http.ModelBinding.FormatterParameterBinding.ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) at System.Web.Http.Controllers.HttpActionBinding.<>c__DisplayClass1.<ExecuteBindingAsync>b__0(HttpParameterBinding parameterBinder) at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext() at System.Threading.Tasks.TaskHelpers.IterateImpl(IEnumerator`1 enumerator, CancellationToken cancellationToken)
    </StackTrace>
</Exception>

Я рассмотрел исходный код того, где это исключение выдается вHttpContentExtensions, но похоже, что он проверяет заголовки содержимого (что у меня должно быть), и если его нет, он пытается получить средство форматирования изMediaTypeFormatter коллекцию, которую он имеет для определенного типа (которую он может ') и затем выбрасывает.

Anyone else experienced this? Some global registration I'm missing?

Что такое HTTP-запрос в фиддлере? В частности, что этоContent-Type значение заголовка? Aliostad
Я могу вручную передатьContent-Type изapplication/jsonчто, что интересно, помогает мне преодолеть эту ошибку (я проходил мимоapplication/json только в заголовке принятия). Но теперь сложные типы становятся нулевыми, что, кажется, разделяет некоторую общую проблему. Brandon Linton
Так что в тебеaccept затем?Accept: application/json не работает?? Попробуйте использовать[FromBody] по параметру. Aliostad

Ваш Ответ

2   ответа
13

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

http://weblogs.thinktecture.com/cweyer/2012/06/aspnet-web-api-changes-from-beta-to-rc.html

Эта ссылка имеет некоторые подробности об этом. Но чтобы подвести итог изменениям, которые, кажется, влияют на вас, привязка модели извлекает свои значения либо из тела, либо из URI запроса. Это верно и для предыдущих выпусков, но с кандидатом на выпуск MVC4 по умолчанию будет искать тело для сложных типов и uri для типов значений.

Таким образом, если вы отправите тело с вашим запросом, содержащее & quot; SomeParameter & quot; ключ, вы должны увидеть это связать. Или вы можете связать с URL, если вы измените объявление на:

 public TestModel Get(int? someParameter)
 {

 }

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

 public TestModel Get([FromUri]TestRequestModel request)
 {

 }

Ключ здесь[FromUri] который говорит связующему модели искать значения в URI. Существует также[FromBody] если вы хотите поместить тип значения в тело запроса.

Спасибо за ссылку для других изменений RC. Я некоторое время искал полный список, подобный этому. Похоже, мне нужно добавить много атрибутов :) Brandon Linton
2

что сложный объект передавался в метод get. Нам нужно было добавить атрибут [FromUri] в параметр к этому методу.

http://forums.asp.net/t/1809925.aspx/1?GET+requests+with+complex+object+as+input+parameter

public class SearchController : ApiController
{
    // added [FromUri] in beta to RC transition otherwise media type formatter error
    public IQueryable<SearchResultEventModel> Get( [FromUri]SearchSpecModel search )
    {
        // ...
    }
}

Похожие вопросы