Intro

There is a lot of information out there how to build a WebAPI or RESTful service, but much less about how to consume it, so I decided to build one myself and share it with you.  In this blog I explain how you can create a RESTful service combined with a MVC web application that consumes this service.  The web application has the standard CRUD (Create Retrieve Update and Delete) operations and a table view for browsing the data.

Download source code

Overview

Figure 1 shows the application is divided in several layers. Each layer has it’s own responsibility.

The GUI layer renders webpages for the user interface and uses the RESTful service for receiving and storing data. The RESTful service offers the CRUD functions for the resource model. In our case the resource model represents a country. The business logic is located at the resource service. It receives the CRUD calls and knows how to validate the business rules.  The database service manages the storage and is implemented with Entity Framework. Some business rules are also implemented in this layer. For example the it checks if the primary key constrain is not violated. In this example MySQL and SqlServer are supported. In this example the GUI talks to the RESTful service, but could also talk directly to the Resource service. I skipped this because one of the goals was to create and consume a RESTful service. Each layer is created with an separate C# project.

Resource Model

The resource model is a simple POCO (Plain Old CLR Object) and represents a country. It travels between the different application layers.

It moved common fields to the base class Resource. Please note this class has a generic type for it’s Id, an Int32 for the CountryResource class.

Resource Service

I liked to start with the key layer, the Resource service. It hosts all the core resource functions by implementing the IResourceService<TResource, TKey> interface.

The generic TKey sets the primary key type like String, Int, Guid etc. This makes the interface more flexible for other resources. This design has no support for composite keys and the key name is always Id. Based on interface IResourceService I create the specific interface  ICountryResourceService .

The interface approach will allow us to create later on the RESTful controller with the DI Dependency Injection pattern and make it easier testable. Now it’s time to get our hands dirty and implement the ICountryResourceService .

The  class  CountryResourceServer  gets the parameter ServiceDbContext serviceContext as dependency injection. The context parameter is an Database Service instance and knows how to store and to retrieve data.

Resource Mapping

In this simple example the CountryResource model and the Country Entity Model are the same. With more complex resources it’s highly likely the resource model and the entity model will differ and creates the need for mapping between the two types. Mapping the two types in the Resource Service layer also drops the need for the Database Service to have a reference to the resource model and makes the design easier to maintain.  Because the mapping only occurs the Resource Service layer it’s OK to setup the mapper instance in the constructor, e.g. no need for DI. AutoMapper handles the conversion between the two types based on the CountryMapping class.

Everything is now prepared to use the AutoMapper, the FindAsync function gives a good example on how to use AutoMapper

Business Rules

Business Rules sets the resources constrains and are enforced in the Resource Service layer.

The CountryResoure businesrules are:

  • Id, unique and range from 1-999
  • Code2 unique, Length must be 2 upper case chars ranging from A-Z
  • Code3 unique, Length must be 3 upper case chars ranging from A-Z
  • Name, length ranging from 2 – 50 chars.

Validation during Create or Update

Before a resource is saved, the Resource Service layer fires three calls for business rules validation.

BeautifyResource  gives the opportunity to clean the resource from unwanted user input. Beautifying is the only task, it does not validate in any way. Beautifying enhances the success rate for valid user input. During beautifying all none letters are remove and the remaining string is converted to upper case.

ValidateAttributes enforces simple business rules at property level. Validation attributes are set by adding attributes to properties. The StringLength attribute in the CountryResource model is an example of validation attributes. One property can have multiple validation attributes. It’s up to the developer that these constrains don’t violate each other.

ValidateBussinesRules enforces complex business rules who cannot be covered by validation attributes.  The complex rules can be coded in ValidateBussinesRules. The unique constrains for fields Code2 and Code3 cannot be done by attributes.

If the constrains are not met, errors are returned to the caller. These errors are shown in the GUI.

Validation during Delete

Business rules apply also on delete operations. Suppose a resource has a special status in a workflow and is there forbidden to delete. During deletion the  ValidateDelete

method is called.

If errors are set, deletion is canceled and errors are shown

Database Service

The Database service stores the resource data and is build with Entity Framework. It receives the only calls from the Resource Service layer. This reduces the effort if you want to replace the Entity Frame work with an OM (Object Mapper) of your own choice.  The service has a few handy features:

Database agnostic

The database service has no knowledge on which database is actually used. The database configuration is set with DI (Dependency Injection) in the RESTful service layer. I explain this later in more detail.

Audit support

Just before an entity is saved (insert or update)  the audit trail fields are set. The current implementation is simple but an gives an good start point to extend the trail. The SaveChangesAsync method is overridden and a small hook AddAuditInfo is added

The audit fields are set in AuditInfo

Concurrency Detection

The Database Service supports optimistic concurrency. This means there is no lock set on an entity before editing. Optimistic locking has and easy approach. Get a entity with version info, start editing and save. During the save process the version info is compared with the latest version from the database. If they are the same all is fine. If the versions differ someone else has made an update and an concurrency error has occurred. How this error is handled and presented to the user is not up to Database Service. On deletion there is no concurrency detection. The user wants to drop the resource and if it’s already gone or the content is changed is no reason the cancel the deletion. The UpsertAsync method inserts or updates an entity and performs the concurrency check.

 

RESTful service

Before we dive into to the details first a small primer about REST (Representational State Transfer) service. REST is an architectural style for exchanging resources between computers over the internet. In last few years REST has become a dominant design for building web services. Most developers find REST easier to use than SOAP or WDSL based services. REST has a few design principles:

  • HTTP verbs Get, Post, Delete Update.
  • Stateless.
  • Transfer data in JSON.
  • Status Codes.
  • URI and API design.
  • Self describing error messages

HTTP Methods

HTTP is designed around resource and verbs. HTTP verbs specify the operation type:

  • GET retrieves a resource.
  • POST creates a resource.
  • PUT updates a resource.
  • PATCH updates a small part of a resource.
  • DELETE deletes a resource (you already guessed that).

PATCH can be useful when you want to update only one field, for example the status in a workflow application. PATCH is not used in my example.

Stateless

REST is aimed to be fast. Stateless services improves performance and are easier to design and implement.

JSON

JSON is the weapon of choice for serializing resources between the server and client.  It can also be done in XML, however XML is more chatty than JSON and will result in bigger transfer documents. An other reason is  the availability of very good JSON parsers for web client development, for example jQuery JSON.parse(…).

Status Codes

The status code of a response indicates the result. In this way there is no need to add some kind of status result in the response message itself. The most common status codes are:

Code Description Example
2xx Success
 200 OK Resource updated
 201 Created Resource created
 204 No Content Resource deleted
 4xx Client Errors
 400 Bad Request POST/PUT a resource with invalid business rules
 404 Not Found Resource not found for GET command
409 Conflict Concurrency error

URI and API

URI (Uniform Resource Identifier ) plays a major role in a well designed API. The URI’s must consistence, intuitive and easy to guess. The API for fetching a country could be

Self describing error messages

A good REST service returns an useful error message. It’s up to client if or how to show the error message.  Suppose we want to update a resource with this PUT request

The business rules requires the Name is mandatory and is not set the request and will result in an error:

Swagger

Swagger UI is a free plugging that is extremely helpful during RESTful development. With Swagger you can easily develop and test your solution.

Fig. 2 General Swagger screen

The overview shows the available API, and can easily be tested

Fig.3 Testing API call

RESTful Controller

In Dot Net Core an REST controller is the same as a MVC controller. It only differs in routing attributes.

Database Dependency Injection

In this example the RESTful service connects to either MySQL or SqlServer.

The controller gets the ResourceService interface as DI and is configured during startup. The setting is located in the appsettings.json file

Only if the DatabaseDriver points to “MySQL” (case insensitive) the service connects to a MySQL database, any other setting will connect to SqlServer.

GET method

The Resource Service fetches the resource, if found a Json structure with the resource is returned, if not and empty message is return with status code 404 (Not Found).

Camel or Pascal case

By default the returned Json structure is camel cased. I find this inconvenient, because some where down the process property names are changed and can cause errors. Fortunately the default behavior can be set during, of course the startup.

POST method

The  [HttpPost] attribute tells the controller only to react on POST request and ignore all other types. The [FromBody] attribute ensures the CountryResource is read from the message body and not the URI or another source. Swagger does not care about the [FromBody] attribute but the c# web client fails without it. Please note that on success an URI and resource is returned.

PUT Method

The PUT implementation looks a lot like the POST function. On success the updated resource is returned with status code 200 (OK) other wise an error message.

DELETE method

The DELETE method has the same pattern as POST and PUT, delegate the actual work to the resource service and report success or failure with errors.

GET revised

REST supports function overloading, you can the “same” function with other parameters. In the first GET example a country is returned based on the incoming Id. You can also fetch a country based on its Code field.

Now Get has code as a string parameter. Depending on its length, 2 or 3 chars the corresponding country is returned. In order to makes this work the original function must have the int type in the HttpGet attribute. If left out there 2 get functions who both have a string as parameter and the routing will fail to resolve this.  No additional type info is required when the parameter count resolves the routing. The more complex Get function demonstrates this:

GUI

Now we have all the required services for building the GUI. The GUI is a straight forward Dot Net Core MVC project with Bootstrap styling. I left out the security part intentionally. Its already a lot to cover and I explain the security in a next blog.

You can find more info about bootstrap-table grid in one of my previous posts. The modal dialogs are created with the excellent Dante nakupanda Bootstrap dialog library. This library removes the verbose Bootstrap model dialog html. The grid and dialogs are glued together with jQuery (of course what else), see the file cruddialog.js for more details.

GUI Controller

The GUI Controller connects with an HttpClient to the RESTful service. The HttpClient is setup outside the controller and passed with DI as an parameter in the constructor because it is not the controllers concern where the RESTful service is hosted.

The apiUrl is set in the constructor and not by DI because the Controller is tightly coupled to this url.

Setup HttpClient

The HttpClient base address is set in the configuration file appsettings.json

The dependency injection is setup during ConfigureServices (startup.cs)

HttpClient implements no interface we can pass to the GUI constructor. I created a custom HttpRestClient to get grip on the HttpClient setup.

With this approach the controller receives an HttpRestClient instance as client parameter in the constructor.

Load grid data

The Bootstrap-Table calls the Load function with a bunch of parameters. These parameters must be added to the client URL and passed to RESTful service. The service result must be converted into a format the Bootstrap-Table can read.

Insert or Edit dialog

The Insert or Edit dialog is a bit more complicated. It has two stages. In the first stage the controller get an resource based on Id and is mapped to an view model. The view model is rendered in the modal dialog. The first steps happens in the Edit method with the Get attribute.

It is the RESTful service who creates a new resource when the Id is empty  and not the GUI controller. The RESTful service has the knowledge how to initialize a new resource and this is not a concern for the GUI controller. jQuery code in the webpage handles the edit response.

First stage Edit Get

Submit Insert or Edit dialog

The second stage submits the dialog to the controller. The view model is mapped to a resource. The controller makes a POST call for a new resource or PUT call for an existing one. The controller parses the RESTful service result. On success the dialog is closed and table grid shows the new resource data. Errors are shown to the dialog and will therefor remain open.

Edit dialog at work

Submit Edit dialog

Updated grid After successful save

Updated grid After successful save

Delete Resource

Before a resource is deleted, the user receives a confirmation dialog. This is the same as the edit dialog, only now are the edit controls are in read only modus and the dialog title and buttons are adjusted.

Create or Edit dialog

If the user confirms the delete, the GUI controller gets a call with the resource Id. The controller calls the RESTful service with the Id and reads the return result. The dialog is always closed after confirmation. On success is removed from the table grid.

Errors are shown in a new dialog.

 

Delete error dialog

Get Source Code Started

The solution works with MySQL or SqlServer.  You can configure the database of your choice in appsettings.json

Make sure the database the account has sufficient rights to create the database. ConfigureServices reads the configuration and adds a DbContext.

Initialize Database content

The EntityContext constructor checks if the database exists. If a new database is created, countries are added from the embedded countries.json file.

Conclusion

Thanks that you made it this far! In this blog I showed Dot Net Core is very capable for creating RESTful services. Swagger, the open source plugging is a big help during RESTful service development. The service can be consumed with a MVC application or third party apps. RESTful design offers several benefits like performance, easy to develop, and a centralized repository. Please download the code and play with it. I hope it may be helpful for you.

Versions

1.0.0 2017 July Initial version
 1.0.1  2017 August  Section Get Source Code Started Added

 

Further Reading

Dependency Injection in ASP.NET Core

Swagger and Visual Studio

10 RESTful tips

Create REST with ASP.NET Core