Building a Web API 2 project from scratch using OWIN/Katana .NET Part 4: async controllers and mini-DDD

Introduction

In the previous post we briefly looked at a new hosting project by Microsoft called Helios. It is meant to be the future of web application deployment where Helios removes the necessity of having the entire System.Web dependency in your web project. We saw that Helios is only in a preview state so it shouldn’t be used for real-life projects yet.

In this post we’ll diverge from OWIN/Katana and instead see how we can add asynchronous controller methods to our current CustomersApi web project. We’ll also build a miniature version of a layered application. We’ll put the layers into separate folders for simplicity.

await/async

If you work professionally with .NET web projects and/or Windows store apps then the await and async keywords must be familiar to you by now. If you’re not sure what they are and how they are used then there’s a dedicated series on this blog that starts here. In short they are meant to use the available threads on your server more efficiently. I won’t go through the things that were discussed there. If you cannot follow the below code samples then refer back to this series.

So if you have asynchronous controllers in your MVC/Web API project then the available threads on your deploy server will be better utilised. A significant benefit is a more responsive and scalable web application.

We currently have one controller action in CustomersController:

public class CustomersController : ApiController
{
	public IHttpActionResult Get()
	{
		IList<Customer> customers = new List<Customer>();
		customers.Add(new Customer() { Name = "Nice customer", Address = "USA", Telephone = "123345456" });
		customers.Add(new Customer() { Name = "Good customer", Address = "UK", Telephone = "9878757654" });
		customers.Add(new Customer() { Name = "Awesome customer", Address = "France", Telephone = "34546456" });
		return Ok<IList<Customer>>(customers);
	}
}

We’ll turn the Get action into an asynchronous method. The key to this is that the Get method needs to call an awaitable method which returns a Task. The Get method simulates a database lookup where we extract all customers from the data store.

The repository layer

We’ll follow a stripped down version of a full-fledged layered application with the domain being the centre of the project. In other words we’ll build an extremely simplified Domain Driven Design (DDD) app. I’ll use the ideas in this series later on where we’ll revisit DDD.

We currently only have a single domain, i.e. the Customer in the Model folder. Let’s add a repository interface to the same folder:

public interface ICustomerRepository
{
	IEnumerable<Customer> FindAll();
}

This indicates what actions the Customer domain wants to enable for a concrete repository. We currently only allow a single action, i.e. the extraction of all customer objects.

Add a new folder to the project called Repository and add a class called CustomerRepository to it. It will implement ICustomerRepository:

public class CustomerRepository : ICustomerRepository 
{
	public IEnumerable<Customer> FindAll()
	{
		IList<Customer> customers = new List<Customer>();
		customers.Add(new Customer() { Name = "Nice customer", Address = "USA", Telephone = "123345456" });
		customers.Add(new Customer() { Name = "Good customer", Address = "UK", Telephone = "9878757654" });
		customers.Add(new Customer() { Name = "Awesome customer", Address = "France", Telephone = "34546456" });
		return customers;
	}
}

This is the same code as above in the Get action.

The service layer

The service layer will be the connecting tissue between the controller and the repository. Add a new folder called Service with the following interface:

public interface ICustomerService
{
	Task<GetCustomersResponse> GetCustomersAsync();
}

…where GetCustomersResponse looks as follows:

public class GetCustomersResponse
{
	public IEnumerable<Customer> Customers { get; set; }
	public bool Success { get; set; }
	public Exception OperationException { get; set; }
}

GetCustomersResponse comes from the simple RequestResponse pattern.

Note that GetCustomersAsync returns a Task, i.e. it’s a good candidate for an awaitable method. However, the repository method is not asynchronous so we’ll need to accommodate that. We could transform ICustomerRepository as well but let’s pretend that we have no access to that interface.

One way to resolve this problem is the following implementation of the ICustomerService interface – add this to the Services folder:

public class CustomerService : ICustomerService
{
	private readonly ICustomerRepository _customerRepository;

	public CustomerService(ICustomerRepository customerRepository)
	{
		if (customerRepository == null) throw new ArgumentNullException("Customer repository!");
		_customerRepository = customerRepository;
	}

	public async Task<GetCustomersResponse> GetCustomersAsync()
	{
		return await Task<GetCustomersResponse>.Run(() => GetCustomers());
	}

	private GetCustomersResponse GetCustomers()
	{
		GetCustomersResponse response = new GetCustomersResponse();
		try
		{
			IEnumerable<Customer> customers = _customerRepository.FindAll();
                        response.Customers = customers;
			response.Success = true;
		}
		catch (Exception ex)
		{
			response.Success = false;
			response.OperationException = ex;
		}
		return response;
	}
}

CustomerService will need a customer repository to fulfil its job. The asynchronous GetCustomersAsync method delegates its task to GetCustomers on a different thread. GetCustomersAsync can therefore be awaited.

Just to recap we have the following folders and files in our project currently:

Minified DDD project structure in Web API 2 project

The controller

We’re now ready to modify CustomersController. We’ll delegate the retrieval of the customer objects to an ICustomerService object. Therefore the CustomersController will need a dependency of this type. For the time being we’ll construct the dependency in a parameterless CustomersController constructor but we’ll revisit this point in the next post as it’s not optimal from a dependency handling point of view:

public class CustomersController : ApiController
{
	private readonly ICustomerService _customerService;

	public CustomersController()
	{
		_customerService = new CustomerService(new CustomerRepository());
	}

	public async Task<IHttpActionResult> Get()
	{
		GetCustomersResponse response = await _customerService.GetCustomersAsync();
		if (response.Success)
		{
			return Ok<IEnumerable<Customer>>(response.Customers);
		}

		return InternalServerError(response.OperationException);
			
	}
}

So now even the Get method returns a Task and can be awaited.

That’s it, you can run the project and navigate to /customers. You should see the same XML response as before.

In the next post we’ll rectify the issue of constructing the ICustomerRepository object directly in the controller constructor.

View the list of MVC and Web API related posts here.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

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

ultimatemindsettoday

A great WordPress.com site

iReadable { }

.NET Tips & Tricks

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: