DPS907 notes – Tue Sep 13

Applying your past ASP.NET MVC web app knowledge and experience to web services. Data and serialization. Content negotiation. Handling all common HTTP request methods.

 

Test today

Test 1 is today, at the beginning of the class timeslot at 11:40am.

All tests in this course are hand-written. Pen or pencil. Answer styles will vary, but we’re mostly looking for short- to medium-length answers, and/or diagrams, and so on.

No references or resources are permitted – “closed book, open brain”. More information is on the graded work page.

The duration of each test depends upon the number of questions. Generally, about 4 minutes per question is allotted, which seems to work out OK.

The tested topics are mostly forward-looking. You will be tested on comprehension, understanding, and the application of the current week’s topics. For this week, it’s mostly the notes below, linked references, and the posted code examples. Also, you may be tested on a past recently-covered topic, which enables you to show that you have the foundational knowledge needed for current and future tasks.

 

Code examples

Code examples for today include:

  • DebuggingIntro
  • AllHttpMethods

 

New feature in the code examples

Almost all current and future code examples will include “comment tokens“.

As you will learn in the linked article, Visual Studio has a built-in token named “TODO”. In your Visual Studio, you will add a custom token named “ATTENTION”. This is a one-time operation on your own computer.

Open Tools > Options. Navigate to the Environment > Task List panel. Enter “ATTENTION” into the “Name:” textbox, and click the “Add” button. It will add it to the “Token list”, as shown below.

attention-token-tools-options

 

Then, when you show your Task List (from the View menu in Visual Studio), it will show you a nice list of tokenized comments. Arrange, resize, and sort the columns as desired (by click+drag in the headers):

 

attention-token-task-list

 

Each item on the list can be double-clicked. When you do that, the source code file will open, and it will scroll to the position of the comment. Enjoy.

 

Routing in ASP.NET Web API

An ASP.NET MVC web app or web service uses the front controller pattern. (Read this Wikipedia overview article). Every request is inspected by a single module (in the ASP.NET runtime engine), and then dispatched to the code module that can handle the request (which is usually a controller).

The dispatch destination is defined by routes. Routes are configured in a class, in the project’s App_Start folder:

  • Web app routes are in the RouteConfig.cs source code file
  • Web service routes are in the WebApiConfig.cs source code file

By default, web service request URIs include an “/api/” segment, although we can change that default in the future.

Then, by default, the next segment of the route designates the controller that will handle the request.

The HTTP request method, along with the presence of a query string, and/or an entity body, will then determine the method in the controller that handles the request.

Routing basics are covered in this ASP.NET Web API article. Study the other articles in the “Routing” collection of articles.

 

Serialization and model binding

On the ASP.NET Web API web site, there’s a collection of articles on serialization and model binding.

By default, the Web API project template can handle three internet media types:

  • JSON – application/json – in and out
  • XML – application/xml – in and out
  • Form data (i.e. data from HTML Forms) – application/x-www-form-urlencoded – incoming only

Data in-and-out of  the web service is handled by serializers. Formally, serialization is done in a media formatter, which is a class that plugs into the request-processing pipeline.

Serialization for JSON and XML is introduced in this ASP.NET Web API article. Please note that the article covers some scenarios that we may not encounter, because we use resource (view) models to overcome limitations and potential problems.

 

Model validation

Incoming data is validated against a resource (view) model, just like in ASP.NET MVC web apps. The School of ICT recommended app design process is to use resource (view) models for all data used when interacting with users (human or programmatic). Continue to use resource models, and ModelState.IsValid in your code.

Read this ASP.NET Web API article on model validation.

 

Content negotiation

Which media type gets returned? It depends, on several factors. Read this ASP.NET Web API article on content negotiation (often abbreviated as “conneg”), and think about the different use cases.

In RFC 7231, content negotiation is specified in Section 3.4.

 

Data annotations in web services

Most students in the course are familiar with data annotations. The second-year ASP.NET MVC web apps course introduces data annotations early in the course, and students use them in all their work for the remainder of the academic term.

If you need a refresher, then review the web app class notes page, in the section titled:

Data annotations overview

The notes linked (above) use web apps terminology, so it uses “view models”. Remember, in web services, we typically call these kinds of classes “resource models”. They’re the same: resource model = view model.

 

System design guidance and how-to

During this course, you will learn to create a web service that has some level of sophistication. Therefore, you will need some guidance on how to design the system.

In your second-year web app programming and systems analysis courses, you used a “system design guidance” diagram to help you learn a set of topics. We will use a version of that diagram that’s customized for a web service. Click to open the PDF in a new tab/window:

System Design Guidance V7 for ASP.NET Web API web service

 

Debugging refresher/reminder

In your web apps course, you may have used the Visual Studio debugger to help you locate and fix logic and runtime errors.

Beginning in the Winter 2016 academic term, all students in the ASP.NET MVC web apps course were trained to effectively and efficiently use the debugger.

If you need a refresher, or if you have not used the debugger much, then review the web app class notes page, in the section titled:

Debugging introduction

To follow along with those notes, you can download the web app code repository, and then open-and-run the “DebuggingIntro” app in the Week_04 folder.

A browser is used to interact with a web app. Therefore, when you coded web apps in the past, a logic or runtime error was displayed to you in the browser. When using the debugger, the error condition would bring the Visual Studio debugger window to the foreground, and display windows/panels with the line of code that has the error, and information about the contents of variables.

 

Debugging a web service, differences

Debugging a web service is similar. Instead of using a browser, you use Fiddler to interact with a web service. The debug experience in Visual Studio remains the same.

Your professor has enhanced the code example above, by adding a web service controller. Download the web service code repository for this course, and then open-and-run the DebuggingIntro app in the Week_02 folder.

After the app loads in a browser window, copy its URL. Then, use Fiddler to interact with the web service, using the copied URL as the base. Here are the requests that you can work with in Fiddler:

Get all customers:

  • Method is GET
  • URL segment to add to the base is /api/customers

Edit customer contact info:

  • Method is PUT
  • URL segment to add to the base is (for example) /api/customers/15
  • Must have application/json content type header
  • Must have entity body data, can copy that from EntityBodyData.js in the project root folder

Your professor will also demonstrate this in class.

 

Now, let’s turn to some brand new course content…

 

Visual Studio project template

Your professor has created a Visual Studio project template that can be used to create new web services.

Its main feature is that includes a fully-configured data persistence scheme, with hundreds of objects that we can query. We will use it in the next few weeks, as we learn how to build web services.

Get the project template from the course’s code example repository on GitHub. It’s in the Templates_and_solutions folder. Copy the “Web service project v1.zip” file to the following path:


%userprofile%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C#\Web

Do NOT unzip the file – leave it as is. You must create the “Web” folder at the end of the path.

Then, when you choose File > New > Project in Visual Studio, the template will appear in the center panel.

Today’s AllHttpMethods code example was created with the template.

 

Supporting all relevant HTTP methods

Section 4 of RFC 7231 specifies the HTTP request methods. Please read/skim sections 4.1 and 4.2 now.

As you can see in Section 4.3, there are many methods available. In this web services course, you will learn to work with a subset of methods, which we call the “relevant” methods.

Our code example today (AllHttpMethods) will help you learn to support all relevant HTTP methods.

In addition, you will learn to create the correct response, which will be an error (as noted in a later section), or one of the results in the following table.

Request Return type Status code Comment
GET collection Collection 200
GET collection Empty collection 200 “Empty” is not an error condition
GET one One 200
GET one No item 404 Truly is ‘not found’
POST add item The added item 201 Added item typically includes an identity property
PUT item updated The updated item 200
DELETE item (no content) 204 The response body for DELETE requests have not been defined

 

Coding principles

In the later section (“HTTP status codes for errors”), you will learn that our manager methods will return data, or null.

In our controller methods, the return types will be as follows:

  • Get all – return an entity collection, typically in an IHttpActionResult
  • Get one, add new, update existing – return IHttpActionResult
  • Delete one – return void, which automatically returns HTTP status code 204

The “get all” case will always be successful. That’s why we can set the method’s return type as IHttpActionResult.

The “delete one” case may succeed, or fail. We don’t care at the controller level. By convention, a void return type returns 204.

For the others, the method’s return type will be IHttpActionResult. Always.

Review the section “Return type of a controller method” in the September 8 class notes.

 

For the following explanations, the week 2 code example named “AllHttpMethods” will be used. It has an entity named “Customers” that you can interact with.

 

“Get one” explained 

In the manager, “get one” uses the object’s identifier. If found, return the appropriate resource model type. Otherwise, null.

In the controller, call the manager method.

If the return value is null, return HTTP 404, “not found”.

Otherwise, return an Ok() result, along with the object.

 

“Add new” explained 

In the manager, “add new” attempts to add a new object. The object’s data passed input data validation in the controller, so the attempt should succeed. In the future, you can add business logic here if you need additional validation to be done.

Return the appropriate resource model type.

In the controller, you must first check the model state (i.e. input data validation). If the data is bad, return BadRequest().

If you have a well-designed resource model class, and use data annotations, the quality of the input data rises.

In addition, this step guards against under-posting (missing data), and over-posting (too much data).

 

If successful, call the manager method. Then, return a Created() result, along with the new object.

The Created() result requires you to supply a URI for the new object. The runtime will use that URI as the value of the Location header. To construct a URI, use the “new Uri” constructor. The Url.Link method is a helper method (System.Web.Http.Routing.UrlHelper). The method takes two arguments:

  1. A route name, which can be seen in App_Start/WebApiConfig.cs, and
  2. A route value, which we get from the new object’s “Id” (identifier) property

The “route name” will resolve to a URI that effectively is the base URI to this controller’s actions. The “route value” is then appended.

 

“Update existing” explained

In the repository, “update existing” first attempts to fetch the existing object. If the existing object does not exist, null is returned.

Alternatively, if successful, it has a reference to the object, and will proceed to update the object, and then return the updated object:

  1. ds.Entry(p) is the reference to an object “p”
  2. .CurrentValues is the object’s collection of current values
  3. .SetValues(updatedP) will update/change those values with the new supplied values

The SetValues method ignores missing properties, as well as navigation properties to associated objects.

In the controller, you must first check the model state. At the same time, for “update existing” scenarios, you must ensure that the identifier on the URI matches the identifier in the request entity body. If the data is bad, return BadRequest()..

This step guards against some kinds of attacks.

 

Alternatively, if successful, call the manager method. If successful, return an Ok() result and the updated resource.

 

“Delete existing” explained

In the manager, “delete existing” first attempts to fetch the existing object. If the existing object does not exist, do nothing (but in the future, we’ll fix that).

Alternatively, if successful, it attempts to remove the existing object from the collection. This attempt is guarded by a try-catch block. The attempt may fail, because the existing object may be associated with other objects.

In the controller, we simply call the manager method. We don’t care if the object exists, because we don’t want to reveal too much information (to the requestor) about our entity collection.

 

Which controller method executes?

You have learned that an ASP.NET Web API web service uses the front controller pattern to determine which method in which controller to run when a request is received.

How does the algorithm work?

Before we cover the steps, think about the data that could be part of a request. A request could include simple data types, and/or complex data types.

Simple data types – in the URI and/or query string – include:

  • int, single, double, decimal
  • string, byte, char, bool, guid
  • datetime, timespan

Complex data types – in the message body – include:

  • anything else; typically any instance of a class
  • your own classes, or .NET Framework classes
  • one-of, or collections-of

Here’s the algorithm:

1. The URI is inspected, looking for a controller name match

2. The HTTP method is inspected

3. The request’s data is inspected – data could be part of the URI and/or query string, or in the message body

Interestingly, these two URIs are the same, for a ‘get-one’ request:

http://example.com/api/foo/3

http://example.com/api/foo?id=3

Then:

4. Identify all controller methods that match the HTTP method name (e.g. ‘GetSomething‘)

5. Match the simple parameter data types – that should be enough to uniquely identify the controller method

If step 5 above yields more than one match, the runtime throws an exception, with a useful message that tells you how to improve your code to avoid the problem in the future.

 

Documentation

Mike Wasson has two articles that provide more detail, on the official asp.net/webapi web site:

Routing in ASP.NET Web API

Routing and Action Selection

 

Exception handling, version 1

This is an initial entry-level treatment of exception-handling. Later in the course, we will learn more about this topic, and improve our treatment.

Our code example today will help you learn how to handle errors and exceptions in your web service.

 

HTTP status codes for errors

In our web APIs, if there is an error, we must return an HTTP error code.

Study the list of HTTP status codes. We may use a number of ‘client’ error codes, and maybe a few ‘server’ error codes:

Code Title Description
400 Bad request Request syntax is not correct
401 Unauthorized Authentication required; the response includes how-to-authenticate info
403 Forbidden Authentication was successful, but the request fails authorization
404 Not found
405 Method not allowed Method not allowed for the resource; response MUST include an Allow header containing a list of valid methods for the requested resource
415 Unsupported media type Request entity body format is not supported
500 Internal server error Default generic message, please limit its use in your code
501 Not implemented Request method not implemented; cannot fulfill the request

Looking for documentation? This Wikipedia article is readable. However, the official source is RFC 7231, in Section 6.

 

Coding principles

Our “version 1” strategy is to handle request errors in a simple yet informative manner.

In this version, our manager methods will return data, or null. The null value will indicate that there’s no data, or an error.

In our controller methods, we will interpret null as ‘no data’ or an error. Its meaning will depend on the method’s context.

Later, our “version 2” strategy will be extended to handle additional kinds of errors, in a way that covers the entire application, with less code to write and maintain.

 

 

 

 

 

 

 

 

 

.

.

.

.

.

.

.

.

.

.

.

.

..

.

.

.

.

.

.

.

%d bloggers like this: