DPS907 notes – Tue Oct 7

Working with other internet media types (e.g. images).

.

Quiz today

Today’s session begins with a quiz.

.

Future topic coverage

What other topics will we cover in this course? We will probably look at the following (and maybe a few others):

  • Working with other internet media types (today’s topic), by learning about ‘media formatters’
  • Attribute routing feature
  • Commands / tasks / operations in a resource-driven web API
  • Error/exception handling for the app, by learning about ‘filters’
  • Re-factoring the link relations code mess
  • Re-factoring the repository class even more
  • Security
  • SOAP XML ‘legacy’ web services

.

Working with other internet media types

You have some experience working with the JSON and XML data formats.

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.

Read this document for more information.

Study the following diagram (click to open a full-size version in a new tab/window):

Formatter.

.

The Images code example enables us to learn about writing our own media type formatter.

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, if it makes sense for that single photo/image to represent the object. (In other words, you would not use this design if you were building a photo sharing app/service.)

.

General design approach

Here’s the general approach to handling images.

1. Configure the design model class with properties to hold the photo. You need a byte array (byte[]) for the photo, and a string for the internet media type.

2. Configure a resource model class with these properties. Typically, you will add attributes to make the JSON and XML serializers ignore the photo-related properties (so that the photo bytes are NOT delivered to requestors unless specifically requested).

3. Add the appropriate repository method (e.g. update an object with a new photo).

4. Configure the appropriate controller methods. As you will learn, you will have to pay attention to request and response headers.

.

Do NOT deliver image bytes as a property value in an object (or collection).

It’s the web! Deliver only the image by setting its content type header.

.

Studying the code example

Get and study the code example. Here are some highlights.

1. Configure the design model class with properties to hold the photo. You need a byte array (byte[]) for the photo, and a string for the internet media type.


public byte[] Photo { get; set; }
public string ContentType { get; set; }

.

2. Configure a resource model class with these properties. Typically, you will add attributes to make the JSON and XML serializers ignore the photo-related properties.

The suggested way to do this is to create an interface, which declares the photo-related properties, and then the resource model class inherits from this interface. This feature will enable a future code refactoring opportunity.


// more...
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using System.Runtime.Serialization;

.

Also/then:


public interface IObjectWithImage
{
    byte[] Photo { get; set; }
    string ContentType { get; set; }
}

public class BookBase : BookAdd, IObjectWithImage
{
    public int Id { get; set; }

    // The following are image-related properties
    // For this code example, we do NOT expose them during normal JSON or XML serialization
    [JsonIgnore, IgnoreDataMember]
    public byte[] Photo { get; set; }
    [JsonIgnore, IgnoreDataMember]
    public string ContentType { get; set; }
}

.

3. Add the appropriate repository methods (e.g. update an object with a new photo).

The existing ‘get-one’ (i.e. GetById(int id)) method already returns a BookBase object. Therefore, it does not need to be changed.

An ‘update-existing’ method, that would also remain unchanged.

An ‘add-new’ method would accept a BookAdd object, which does not include the photo properties. Therefore, when adding a new book, it will be a two-step operation: 1) First, ‘add-new’, with the basic details, and then 2) ‘set-photo’ to configure the photo.

So, the only really new repository method is SetPhoto. Notice its argument list.

.

4. Configure the appropriate controller methods. As you will learn, you will have to pay attention to request and response headers.

The current design of the MediaTypeFormatter (and BufferedMediaTypeFormatter) classes do not provide a way to set the response’s Content-Type header dynamically. We need this capability, in order to support a range of popular image formats (JPG, PNG, GIF).

Therefore, before the controller delivers the object to the formatter, it must set/configure the Content-Type header. That’s what the extra code does (when compared to a typical ‘get-one’ method):

.

Study the code in the ImageFormatter class.

All media type formatters are similar, and they are fairly simple. They have a constructor and up to four methods – a pair of ‘read’ methods, and a pair of ‘write’ methods.

Note: These formatters work well for small- to medium-sized digital assets. If your asset is less than a few hundred kilobytes, then you can use this design, which is synchronous and therefore blocking.

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

.

Handling ‘commands’ in a web service

For many weeks, we have been learning to design and code a web service by thinking of it as an API to a database-like data store. You have learned how to handle the typical CRUD operations (create, retrieve, update, delete) normally associated with data management. The HTTP methods map nicely to these operations, and that familiarity has helped you make progress.

It’s time to expand our thinking, beyond data management. How? By adding the ability to handle commands and operations that may or may not be easily mapped to data management. In most cases, the command will change the (data) state of the targeted resource.

Today, and maybe in Lab 5, you’ll get a gentle introduction to this concept. This will prepare you for more interesting scenarios in a few weeks.

Assume that you want to do something command-like to a resource. For example, send a representation of the resource by email to a list of pre-configured recipients, and log the action. Or, increase the hourly wage 5% for all employees in a certain department. Or (as in today’s code example) set/save a photo for a resource.

.

Thinking about commands

There are two ways to look at any of these tasks:

  1. As a command, where we state our intent – ‘do this’ or ‘do that’
  2. As a data management task, where we specifically, technically, and atomically set/update data properties to specific values

Which is the more natural concept to understand? Everyone can understand #1. Only programmers would care enough to understand #2.

How do we map commands to resources?

By convention, we typically send a PUT request to a resource. The underlying method has code that carries out our intent.

.

Is this a standard?

No, but it’s a principle named “command-query separation“, or CQRS.

CQRS states that a command does something but does not return data to the caller.

Therefore, the controller method return type will be void, which automatically creates an HTTP 204 status code. In other words, when handling a ‘command’, we simply execute the command silently, without any data feedback to the requestor (other than the HTTP 204, which is one of the HTTP success status codes).

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

.

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: