ObjectContent Constructors

Topics: ASP.NET Web API
Apr 1, 2012 at 11:05 PM

 

In looking at creating custom HttpResponse object instances I think there's too much noise in the creation of specific content instances. I think it'd be really useful to have at least one extra constructor  to simplify creating object instances. Specifcally in regards to the formatter instance.

Currently I have to do this:

 

    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Content = new ObjectContent<IEnumerable<Album>>(albums, new JsonMediaTypeFormatter());

 

which works fine to give me JSON. But how do I know that I need to use JsonMediaTypeFormatter() and why should I have to specify that explicitly? It would be much nicer if I could just specify a string of the media type I'm trying to return:

    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Content = new ObjectContent<IEnumerable<Album>>(albums,"application/json");

which doesn't require me to know which formatters are available.

We already had this discussion, but it would also be nice to get the default content negotiation from here by not specifying a media type or formatter at all. I know I can do this with:

var resp = Request.CreateResponse<IEnumerable<Album>>(HttpStatusCode.OK, albums);

But something about this really bugs me from the fact that it comes of the (unexpected) Request object, to the fact that this is so different from the process to create the message in the example above. I think that message creation should be consistent and not have two different paths. The preferred behavior IMHO would be that if you don't specify a media type or formatter the default content negotiation kicks in and picks a formatter for me, so the following should be enough:

    resp.Content = new ObjectContent<IEnumerable<Album>>(albums);

to get default content negotiation.

Everytime I use HttpResponseMessage it seems I have to remember a lot of different pieces to create my response - this is one of the most common things we'll need to do in our APIs and it should be as easy as possible to create a response with minimal amount of code, IMHO.

+++ Rick ---

Apr 1, 2012 at 11:26 PM

While I completely agree that this looks nice:

                    resp.Content = new ObjectContent<IEnumerable<Album>>(albums);

we ran into two issues that were hard to get around:

1) In order to do content negotiation we do need the request and it may not be there. While the request can be associated with a response by setting the “RequestMessage” property on the Response that doesn’t happen if you just do this:

var resp = new HttpResponseMessage(HttpStatusCode.OK);

Without a request we have no way of detecting client preferences in the content negotiation and so we would have to go with the default format.

2) The second issue is that we don’t have the configured formatters set on the HttpConfiguration. This means that at best we can use some default formatters that are not open to configuration and we can’t use a static because that breaks the model of having multiple independent HttpConfiguration instances.

As a result we put the CreateRequest on the Request where we can ensure that we have both the request (by definition) and the configuration (because we put it in the property bag on the request). This allows us to provide a consistent story where we always pick the formatters that are configured in the HttpConfiguration and can do content negotiation on the request.

It also allows users to do the same in that content negotiation now is a stand-alone step which you can do yourself and just pass the resulting formatter in as a result. This is what this ObjectContent overload is for:

new ObjectContent<IEnumerable<Album>>(albums, new JsonMediaTypeFormatter());

Basically, you can here just tell us what formatter to use and we won’t do any content negotiation or anything else – we will just use it as-is.

Hope this makes sense,

Henrik

From: rstrahl [email removed]
Sent: Sunday, April 01, 2012 4:06 PM
To: Henrik Frystyk Nielsen
Subject: ObjectContent Constructors [ASPNETWebStack:350820]

From: rstrahl

In looking at creating custom HttpResponse object instances I think there's too much noise in the creation of specific content instances. I think it'd be really useful to have at least one extra constructor to simplify creating object instances. Specifcally in regards to the formatter instance.

Currently I have to do this:

    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Content = new ObjectContent<IEnumerable<Album>>(albums, new JsonMediaTypeFormatter());

which works fine to give me JSON. But how do I know that I need to use JsonMediaTypeFormatter() and why should I have to specify that explicitly? It would be much nicer if I could just specify a string of the media type I'm trying to return:

    var resp = new HttpResponseMessage(HttpStatusCode.OK);
    resp.Content = new ObjectContent<IEnumerable<Album>>(albums,"application/json");

which doesn't require me to know which formatters are available.

We already had this discussion, but it would also be nice to get the default content negotiation from here by not specifying a media type or formatter at all. I know I can do this with:

var resp = Request.CreateResponse<IEnumerable<Album>>(HttpStatusCode.OK, albums);

But something about this really bugs me from the fact that it comes of the (unexpected) Request object, to the fact that this is so different from the process to create the message in the example above. I think that message creation should be consistent and not have two different paths. The preferred behavior IMHO would be that if you don't specify a media type or formatter the default content negotiation kicks in and picks a formatter for me, so the following should be enough:

    resp.Content = new ObjectContent<IEnumerable<Album>>(albums);

to get default content negotiation.

Everytime I use HttpResponseMessage it seems I have to remember a lot of different pieces to create my response - this is one of the most common things we'll need to do in our APIs and it should be as easy as possible to create a response with minimal amount of code, IMHO.

+++ Rick ---

Apr 2, 2012 at 12:09 AM

Ok... then how about making CreateRequest() more useful by providing additional constructors to allow for custom output types (like by media type string)? That way we'd get whatever the request holds and can override what we need.

CreateResponse() currently doesn't let you easily override the formatter (not in constructor).

I think the goal should be that we can use one API/Method call to handle most scenarios rather than having several different ways to get a HttpResponseMessage.

For example I think I should be able to do:

return Request.CreateResponse<ApiMessageError>(HttpStatusCode.Conflict, error,"application/json");             
The easier it is to create HttpResponseMessage instances the less support is coming your way in the future :-)

+++ Rick ---

 

Apr 2, 2012 at 1:25 AM

Right on (and I should have mentioned) – we are just adding some more CreateResponse overloads that will take the media type exactly as you propose.

We also plan to add some that help create a variety of common HTTP responses such as redirects, etc. but that will be a little later.

I completely agree with making CreateResponse as easy as possible and your feedback is greatly appreciated.

Henrik

From: rstrahl [email removed]
Sent: Sunday, April 01, 2012 5:09 PM
To: Henrik Frystyk Nielsen
Subject: Re: ObjectContent Constructors [ASPNETWebStack:350820]

From: rstrahl

Ok... then how about making CreateRequest() more useful by providing additional constructors to allow for custom output types (like by media type string)? That way we'd get whatever the request holds and can override what we need.

CreateResponse() currently doesn't let you easily override the formatter (not in constructor).

I think the goal should be that we can use one API/Method call to handle most scenarios rather than having several different ways to get a HttpResponseMessage.

For example I think I should be able to do:

return Request.CreateResponse<ApiMessageError>(HttpStatusCode.Conflict, error,"application/json");             

The easier it is to create HttpResponseMessage instances the less support is coming your way in the future :-)

+++ Rick ---

Apr 2, 2012 at 4:20 PM

Rick, this discussion is very timely as Henrik and I were talking abou the need for such helpers just last week. In fact, there's already an item in the issue tracker covering this: http://aspnetwebstack.codeplex.com/workitem/12 (the wording is not very specific right now but i'll work on improving that). I'm probably going to check in a fix for this tomorrow.

Apr 2, 2012 at 8:37 PM

Awesome!