Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
468 views
in Technique[技术] by (71.8m points)

asp.net mvc - Upgrading to MVC4 RC: No MediaTypeFormatter is available to read an object of type 'TestRequestModel' from content with media type ''undefined''

I've been using the MVC4 beta and am currently working to upgrade to the recently released RC version.

It appears that model-binding complex request types has changed, but I can't figure out how / what I'm doing wrong.

For example, say I have the following API controller:

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

This yields the expected result:

<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>

Now say I just change the signature, taking in a request type, like this:

public TestModel Get(TestRequestModel request)
{
    ...

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

I now get the following error:

<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>

I've looked at the source code of where this exception is thrown in the HttpContentExtensions, but it looks like it checks for content headers (which I should have), and if it doesn't have that it tries to get a formatter from the MediaTypeFormatter collection it has for the specific type (which it can't) and then throws.

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I see your original question was answered, but to answer the other one, Model binding has changed somewhat in the RC.

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

This link has some details about it. But to sum up the change that appears to be affecting you, Model binding pulls its values from either the body, or the uri of the request. This is true for previous releases as well, but with the release candidate, MVC4 will, by default, look to the body for complex types, and the uri for value types.

So, if you submit a body with your request containing the "SomeParameter" key, you should see it bind. Or you could bind with the url if you change the declaration to:

 public TestModel Get(int? someParameter)
 {

 }

Thankfully, the team foresaw the potential problems with this and left us with attributes we could use to override this behavior.

 public TestModel Get([FromUri]TestRequestModel request)
 {

 }

The key here is the [FromUri] which tells the model binder to look in the uri for the values. There is also [FromBody] if you want to put a value type in the body of a request.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...