DPS907 notes – week 4 – Sep 28 and Oct 1

Internet media types in web services.


Agenda for the Friday class

Here’s the agenda for the Friday class:

  • Test 1
  • Transition your knowledge about media handling to the web service context
  • Rules (guidance)
  • Media type formatter class and code


Test today

Test 1 is today, at the beginning of the timeslot.

As discussed in class a few times, it will cover the week 3 content and the week 4 content.

Review the relevant info about tests on the week 2 notes page and on the graded work page.

The test will begin at the start of the class timeslot, at 3:20pm, and its duration will be about 40 minutes. It is worth 12%, which means that you will answer any 12 questions, as each is worth one mark.

After the test, we will cover the highlights of the week’s new topics.


Code examples

In the GitHub code example repository for this week, you will see several interesting assets.

The MediaUpload code example will be studied today, and discussed in the notes below.

Soon, another code example, MediaUploadAndDeliver, will be posted, and we’ll likely discuss that in the next class/session.

The ByteFormatter folder has a fully-working and complete media type formatter, built with the instructions that are in the notes below.


Reminder – use the Visual Studio Task List…

Make sure that your Visual Studio app is configured to use the “ATTENTION” comment token.

Then use Visual Studio’s “Task List” to help you study the design and coding features of the code example.


Transition your web apps media-handling knowledge

All students have experience with media handling in web apps. In this section, you can begin to transition your knowledge to the web services context.

Refresh your memory about media handling in web apps…

Read and study the professor’s class notes and code examples on this topic, recently covered in a web apps course:
BTI420 Class Notes – March 22, 2017  – working with internet media types, simple
BTI420 Class Notes – March 24, 2017 – continued, more complex scenario

It will take about an hour for you to go through that content, and its code examples. Do it now. Before continuing.


Welcome back.

In a web app, you learned how to accept (i.e. “upload”) a media item, and how to deliver a media item. You probably coded these kinds of solutions:

Accept (upload)

  • HTML Form
  • Includes an “input type=file” element
  • The form may also have included other input elements


  • Specialized controller, or specialized methods in an existing controller
  • Returns a File() ActionResult object


The web service solution

Accept (upload)

Well, a web service obviously does not have an HTML Form. Therefore, accepting a media item must be done as an atomic and specialized task. The requestor must send only the media item, and its media type (as a content type header), in the request.

If the media item is to be “linked” to an entity object, then that object must exist, before adding/uploading the media item.

In other words, if you are coding a solution that enables a requestor to, for example, create a new “product” object that has a photo as one of its properties, the solution requires the requestor to create two separate requests. First, create the “product” object by supplying data that can be expressed in the “application/json” media type. Then, using the new object’s identifier, create another request to modify the object, and send along the media item as an “image/png” media type.


This part of the solution will be similar to the web app solution. The only difference is that the method return type will be different, because it can take advantage of some functionality that you can build into the web service.


Media handling scenarios

There are at least three scenarios for handling media:

Object with one media item
An entity that can also be represented with a media item.
For example, a Seneca “student” object has a single photo item.
Or, a “song” object has a single audio (e.g. m4a, mp3) item.

Today’s code example covers this object-with-one-media-item scenario: MediaUpload.

Object with many media items
An entity that may have zero or more associated media items.
This scenario requires a separate “media” entity, associated to its parent entity.
For example, a “product” object has a collection of product photo items.

Media driven app
In this scenario, the media drives the app’s purpose and design.
The “media” entity is central to the design model, and will be associated (by definition, or logically) with other entities.
For example, a photo app, like Instagram.
Or, a video app, like YouTube.
Or, a music app, like Apple Music.
Or, a document (file) app, like DropBox.



There are at least two important rules that you must follow when working with media items:

In a request or response, do NOT package a media item inside another container.


Accept or deliver the media item as-is, even if it means that the requestor must create another request to fetch the item.

When storing a media item, its media type name MUST also be stored.

Therefore, two properties are required, in a design model class, to store a media item:
1. A byte array (in C# + Entity Framework + SQL Server), maybe named “PhotoContent” or “PhotoMedia” (assuming that we are storing a photo), and
2. A string for the type name, maybe named “PhotoContentType”
Yes, you can add other metadata properties (e.g. location, caption, tags, etc.) for the media item, if you wish.


Message lifecycle (aka “request-processing pipeline”)

Before continuing, let’s look at a topic that has been briefly and gently introduced a couple of times already.

You are probably aware that a request message flows through a request-processing pipeline before a response is returned to the requestor.

It’s time to learn more about the message lifecycle, so that you can modify or affect a message as it flows through the pipeline. In a few weeks, you will learn how to handle exceptions, and the HTTP OPTIONS method. Both tasks require you to create code that “plugs in” to the pipeline. The pipeline can be modified, customized, and extended.

The image below shows the message lifecycle. Click to open a PDF full-size in its own tab/window.



Flow from the request to the controller action

The following is a brief summary of the flow:

  1. Web server host handles the request, and creates an HttpRequestMessage object
  2. Routing dispatcher module activated for a Web API (or MVC) request
  3. Controller dispatcher selects controller, then the action (method)
  4. If applicable, authentication happens
  5. If applicable, authorization happens
  6. Model binding happens, for data in the URI, headers, and entity body *
  7. Controller action (method) is invoked, with the data

* The deserialize task is done by a media formatter.


Flow from the controller action to the response

The following is a brief summary of the flow:

  1. The result of the controller action (method) is converted to an HttpResponseMessage *
  2. If the result was an error, the built-in error handler is invoked
  3. Web server returns the HTTP response to the requestor

* For a successful result, the serialize task is done by a media formatter.



We wanted to leave you with this understanding, because it starts to become very relevant when handling internet media types in a web service.


Introduction to “media type formatters”

You have some web service experience working with the JSON and XML data formats. You can reliably accept and deliver JSON content to and from your web service app.

When accepting JSON content into a controller method that handles POST or PUT requests, you have seen that the model binding process materializes an object from the JSON content. But how does that happen?

Similarly, when delivering a result (an object or collection) from a controller method that handles a GET request, you have seen that the object or collection is delivered as JSON in the response. But how does that happen?

A “media type formatter” is the name of the component that actually does the work. This component is conceptually located between the requestor and the controller action/method. Every “Web API” project includes media type formatters that handle JSON and XML.

Read this ASP.NET document for more information about JSON and XML serialization.

The image below is an excerpt of the bottom part of the “message handling” image that you studied above. Click to open it full-size in its own tab/window.

It has been marked up with red arrows which shows the locations involving the media type formatters in the request-handling pipeline.



Here is a simplified diagram that shows the request and response flow. Click to open a full-size version in a new tab/window:



Custom media type formatter

As you have learned, every “Web API” project includes the built-in media type formatters for JSON and XML.

How do we handle other media types?

We create a custom media type formatter.

Incoming: Our formatter will transform (or convert) an incoming media item – which is a byte stream – in the HTTP request’s entity body to an object that we can use in our web service. The HTTP byte stream is transformed into a byte array (i.e. byte[]).

You may recall that your ASP.NET MVC web apps used an HttpPostedFileBase property in the incoming view model class. This piece of goodness enabled your code to get access to a media item that was sent in a POST request, in an “input type=file” element.

We do not have access to HttpPostedFileBase in a Web API web service. Instead, we create a custom media type formatter.

Outgoing: Our formatter will also transform (or convert) an object in our app – a byte array – to a byte stream in the entity body of an HTTP response.


Code example: MediaUpload

Open and study the “MediaUpload” code example, as you continue reading this content. The code example enables us to learn about writing our own media type formatter.

Another code example – MediaUploadAndDeliver – will also be studied this week.

We’ll use a simple “book” data entity (books – remember those?), and configure its entity class with properties that hold a photo of the book cover, and the internet media type of the photo (typically “image/png”).

Therefore, this design will work if an entity object has a single photo/image property. And conceptually, it can also make sense for that single photo/image to represent the object. (In other words, you would not use this design if you were building a media-driven photo sharing app/service.)

As a result, it will be possible for a book to have two representations:

  1. Data representation, as JSON
  2. Image/photo representation, as a PNG or JPG image

It will be possible for the requestor to ask for either representation.


(End of Friday content; Monday content is next.)


Agenda for the Monday class

Here’s the agenda for the Monday class:

  • Highlights of the design of a media type formatter
  • Media item delivery, and content negotiation
  • Work on the assignment


Design and implement a media type formatter

Above, we stated that we can design and implement a media type formatter. How?

Here’s the general approach to handling images, or any byte-oriented content:

  1. Create (or add) and register a custom media type formatter
  2. Configure the design model class with properties to hold the media item
  3. Configure resource model classes with media-related properties
  4. Add manager methods to handle media-related acceptance (and delivery)
  5. Configure controller methods

Continue reading below, to learn the details. Study the code example while you do that.


Create (or add) and register a custom media type formatter

We need a formatter that will handle byte-oriented content. That will enable us to handle these media types:

  • images/photos (png, jpg, etc.)
  • audio (m4a, mp3, etc.)
  • video (mp4, wmv, mov, etc.)
  • documents (pdf, docx, xlsx, zip, etc.)

Create a class that inherits from BufferedMediaTypeFormatter. In the code example, study the ByteFormatter class (it’s found in the project’s ServiceLayer folder).

All formatters have a similar structure:

  • a constructor configures the media types that it will handle
  • a reader method transforms incoming content from the HTTP request entity body
  • a writer method transforms outgoing content to the HTTP response entity body

Note: This formatter design works well for small- to medium-sized media items. If your media item is less than a few hundred kilobytes, then you can use this design, which is synchronous and therefore blocking.

For larger media items, use the asynchronous approach, where the base class is simply MediaTypeFormatter. A future code example will show you how to do this.


The formatter must be registered and initialized when the app starts. Look at the WebApiConfig class, in its Register method, for the statement that does this work.

At this point in time, the web service can handle these media types in its requests and responses, and automatically transform/convert between them and C# objects:

  1. JSON
  2. XML
  3. byte-oriented media items


Configure the design model class with properties to hold the media item

You need two properties:

  1. A byte array (byte[]) for the photo (named “PhotoMedia” or something similar), and
  2. A string for the internet media type (named “PhotoContentType”).



Configure resource model classes with media-related properties

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

However, during processing, while doing work between the controller, to/from the manager, to/from the data store, it is natural and obvious to consider the media item to be a property of an entity object.

Resource models can and should acknowledge the presence of the media item. Study the diagram below, which shows the code example’s resource model classes. Click to open the diagram full-size in its own tab/window:




The BookWithMediaInfo class includes metadata about the media item. The controller and manager can use the metadata to make processing decisions. The requestor can also do that.


Add manager methods to handle media-related acceptance (and delivery)

Today’s code example MediaUpload focuses on the acceptance (upload) of a media item.

Above, you learned that an entity object must exist before its media item can be configured. This situation is similar to any PUT request that modifies properties in an existing entity object.

Therefore, the manager method’s signature includes parameters for the object’s identifier, in addition to the media item properties.


Configure controller methods

The code example has a BookPhoto() method that handles the request, which includes:

  1. The request URI, with the entity object identifier
  2. A request header (Content-Type), which declares the media type of the entity body
  3. An entity body, which holds a byte stream

Study the method parameters:

  • an identifier for the object
  • a byte array for the media item

We can easily understand the identifier. For example, we will be working with object with Id = 234.

What about the request header? It is available in the controller’s Request property.

What about the byte array? How does it get materialized from the request’s entity body?

The media type formatter does this work. Automatically.


Studying the code example

Here are a few other design features of the MediaUpload code example.


The “BookGetAll”, “BookGetById” and “BookAdd” methods return metadata for the media item. They do NOT return the media item bytes.


As noted above, the “get” and “add new” methods return metadata for the media item. You can inspect the property values to determine whether an “add new” request was successful (and resulted in the acceptance/upload of a media item).

When testing the “BookPhoto” command method in Fiddler, use this technique:

  1. Set the method to PUT, and set the appropriate URI (/api/books/{id}/setphoto)
  2. For the request body, click the “Upload file…” link, and browse to the media item you wish to use

This is what it should look like in the Fiddler “composer” tab, after you have selected the media item:



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


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


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



Today, we introduced content negotiation, and the concepts and techniques for handling internet media types other than JSON and XML.

You learned about a media type formatter, which gets added to the request-handling pipeline.

We also covered the tasks that need to be completed to support these media items in your web service.


Work on the assignment

Continue working on the next assignment.




























































%d bloggers like this: