DPS907 notes – Thu Sep 29

Content negotiation. Hands-on with Assignment 4.


Delivering a media item in a response

There are two techniques for delivering a media item in a response:

  1. Determined by the web service (and you, the programmer)
  2. Negotiated between the requestor and the web service



There’s a new MediaUploadAndDeliver code example today. Open and study it as you go through the content below.

It has a GetPhoto() method, which returns a media item.

The request includes a URI, and no other configuration. In other words, the request does not need an Accept header configured, because the method simply returns the media item as is.



The other “get one” method, Get(), uses content negotiation.

The request includes a URI. It also includes an Accept header.

The method will attempt to fulfill this request. If it cannot, it will process the request in a predetermined manner (which is decided by the programmer).


Content negotiation

Content negotiation is described formally in RFC 7231. Read that section now.

It is also described in this Wikipedia article.

In summary:

The requestor and the server must negotiate the media type of the response.

If the requestor has no preference (i.e. the request does NOT have an Accept request header), the server will deliver its preferred media type.

If the requestor includes an Accept request header, the server will attempt to deliver the resource as the requested media type. You, as the web service programmer, have complete control over this process.

What if the requested media type not available?

What do you deliver as a response?

This RFC 7231 section clearly states that you must return HTTP 404, because “the origin server did not find a current representation for the target resource”.


Implementing content negotiation

The MediaUploadAndDelivery code example is based on the previously-studied MediaUpload code example. As its name suggests, it adds “delivery” of media items as a feature. The following additions/changes were made:

  1. Resource model class
  2. Manager method return types
  3. Controller methods

Each is described below in more detail.


Resource model class

A new BookWithMedia resource model class was created. It includes the bytes for the media item.

It should be used only in scenarios where you are working with one entity object. In other words, do not do a “get all” and deliver a BookWithMedia collection to another place in your code. Why? Think about it: If you have thousands of entity objects, and each object includes a large media item, then the memory and processing load on the app server will be immense.




Manager method return types

The “get one” method DOES return the media item bytes, and the metadata.

A controller method will determine whether the media item bytes are returned in the response.


Controller methods

There are two methods that service the “get one” use case:

  1. GetPhoto(int? id), URI is /api/books/{id}/photo
  2. Get(int? id), URI is /api/books/{id}

Remember the rule: In a request or response, do NOT package a media item inside another container.


GetPhoto(int? id), URI is /api/books/{id}/photo

This method implements the predetermined technique.

Notice the custom route. When using this route, the requestor really is intending to get the media item in the response.

It is not necessary for the requestor to include an Accept header in the request. The method will simply return the media item in the response, and set the Content-Type header accordingly. This approach is similar to the one seen in web app (that uses a browser as a user interface), where the method returns a File() result.


Get(int? id), URI is /api/books/{id}

This method implements the negotiated technique.

Notice the logic flow:

  • It looks for a suitable Accept header value
    • If available, it looks for a media item
      • If available, it delivers the media item; the media type formatter transforms the byte array to a byte stream
      • If not available, it responds with HTTP 404
    • If not available, it handles this as a “normal” request, and responds with a JSON result


The important point is that the method’s return value is a byte array – the actual media item. The custom media type formatter transforms the byte array to a byte stream in the response.


Extra topic: Object with a collection of media items

This new section covers the second scenario in the previous class/session notes section titled “Media Handling Scenarios”, where an object could have a collection of zero-or-more media items.

Here’s how to get started with its implementation.


Create a design model class to hold the media item

First, create a design model class to hold the media item.

It obviously needs a byte array for the media, and a string for media type.

Also, add any other metadata properties that would be useful in your app. What will be useful? Think about the reason for your app, and for existence of the media items. Think about the use cases. Use the results to answer the question.


Configure the design model classes to have an association

In the “MediaUpload” and “MediaUploadAndDeliver” code examples, the entity class was Book.

Modify the design of Book, so that it does NOT have media properties. Instead, it will have a collection property that points to the media item class.

Here’s an example of what this design could look like:



Configure the manager and controller logic

The “add media item” approach is similar in concept:

First, create the principal item, the Book.

Then, knowing the Book identifier, you can create (POST) a new media item to the BookCovers collection, associating it with the principal Book item.

Finally, knowing the BookCover identifier, you can set its photo property (PUT), using the technique you learned recently. Obviously, in the manager method, it will end up doing an “add new” BookCover task.


Get started on the assignment

Assignment 4 is now available.

Before leaving the classroom at the end of the timeslot, hand in your work report.






























%d bloggers like this: