Domain Driven Design with Web API revisited Part 14: the abstract application service

Introduction

In the previous post we discussed the role of view models. We saw that they are simple classes with a collection of properties and usually no logic. They can be used to format the domain object in a special way that fits a specific purpose without having to change the domain object itself. E.g. the UI of the application can show the domain in a specialised way, like we hinted at in the previous post: customer name instead of customer ID, agent country and city instead of agent ID etc.

In this post we’ll start discussing the application service layer. In particular we’ll build the abstract service and the messaging objects. We’ll build the concrete application service in the next post.

The application service

We took up services in general before in the series. Services can come in several different forms in an application. Services are not associated with things, but rather actions and activities. Services are the “doers”, the manager classes and may span multiple domain objects. They define what they can DO for a client. They are unlikely to have attributes as Entities or Value objects do and will absolutely lack any form of identity. We said that the Timetable object could be viewed as a domain service.

Application services normally only carry out co-ordination tasks and are void of any extra logic themselves. They consult repositories and possibly other services to carry out tasks on behalf of the caller. The caller is typically some front end layer: an MVC controller in a web project, a Web API controller in a Web API project or a XAML view-model in an MVVM WPF project. Application services provide therefore the connecting tissue between the backend and the front end of the application.

A pattern that often comes up within the context of application services is the request-response pattern. We used it in the original DDD series and will use it here again. You can read about it in a dedicated post here. In short they are wrapper objects for a range of parameters to a function in a service. Here’s a quick example:

public class GetProductsRequest
{
    public string Region {get; set;}
    public string SalesPoint {get; set;}
    public DateTime FromDate {get; set;}
    public DateTime ToDate {get; set;}
}

It can be used in a service as follows:

GetProductsResponse GetProducts(GetProductsRequest request);

…where GetProductsResponse may look as simple as the following:

public class GetProductsResponse
{
    public IEnumerable<Product> Products {get; set;}
}

The Amazon SDK – at least the .NET and the Java version – is loaded with this pattern. We’ll go for this pattern in the service layer. You may think it is overkill in some cases but it’s up to you how you take ideas from here and how you apply them.

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’re forward looking and want to build asynchronous controllers in the Web API layer further on. Therefore we’ll need to prepare the service layer in a way that fits the await/async pattern.

The application service layer

Open the project where we left off in the previous post. Locate the BoundedContexts/LoadTesting folder and add a new C# class library into it called WebSuiteDemo.Loadtesting.ApplicationServices. Remove Class1.cs. At this point we have the following folders and applications in our demo solution:

State of application after adding the application service layer

Add a project reference to the WebSuiteDemo.Loadtesting.Domain and WebSuiteDDD.SharedKernel layers.

Then add a new folder called Messaging and insert the following base classes for the service requests and responses:

public abstract class ServiceRequestBase
{
}
public abstract class ServiceResponseBase
{
    public ServiceResponseBase()
    {
        this.Exception = null;
    }
     
    public Exception Exception { get; set; }
}

Our service requests and responses will derive from these base classes. The Exception property of ServiceResponseBase will hold any exception encountered during the execution of the request.

Insert the following requests and responses to the Messaging folder.

AddOrUpdateLoadtestsRequest and AddOrUpdateLoadtestsResponse for adding and updating load tests:

public class AddOrUpdateLoadtestsRequest : ServiceRequestBase
{
	private IEnumerable<LoadtestViewModel> _loadtests;

	public AddOrUpdateLoadtestsRequest(IEnumerable<LoadtestViewModel> loadtests)
	{
		if (loadtests == null) throw new ArgumentNullException("Loadtests");
		_loadtests = loadtests;
	}

	public IEnumerable<LoadtestViewModel> Loadtests
	{
		get
		{
			return _loadtests;
		}
	}
}
public class AddOrUpdateLoadtestsResponse : ServiceResponseBase
{
	public AddOrUpdateLoadtestsValidationResult AddOrUpdateLoadtestsValidationResult { get; set; }
}

Request and response for load test deletion:

public class DeleteLoadtestRequest : ServiceRequestBase
{
	private Guid _id;

	public DeleteLoadtestRequest(Guid id)
	{
		_id = id;
	}

	public Guid Id
	{
		get
		{
			return _id;
		}
	}
}
public class DeleteLoadtestResponse : ServiceResponseBase
{
}

Request and response to retrieve the load tests in the timetable by dates:

public class GetLoadtestsForTimePeriodRequest : ServiceRequestBase
{
	private DateTime _searchStartDateUtc;
	private DateTime _searchEndDateUtc;

	public GetLoadtestsForTimePeriodRequest(DateTime searchStartDateUtc, DateTime searchEndDateUtc)
	{
		_searchStartDateUtc = searchStartDateUtc;
		_searchEndDateUtc = searchEndDateUtc;
	}

	public DateTime SearchStartDateUtc
	{
		get
		{
			return _searchStartDateUtc;
		}
	}

	public DateTime SearchEndDateUtc
	{
		get
		{
			return _searchEndDateUtc;
		}
	}
}
public class GetLoadtestsForTimePeriodResponse : ServiceResponseBase
{
	public IEnumerable<LoadtestViewModel> Loadtests { get; set; }
}

We can now create the abstract timetable service. Add a folder called Abstractions to the application service layer.

The ITimetableService looks as follows:

public interface ITimetableService
{
	Task<AddOrUpdateLoadtestsResponse> AddOrUpdateLoadtestsAsync(AddOrUpdateLoadtestsRequest addOrUpdateLoadtestsRequest);
	Task<DeleteLoadtestResponse> DeleteLoadtestAsync(DeleteLoadtestRequest deleteLoadtestRequest);
	Task<GetLoadtestsForTimePeriodResponse> GetLoadtestsForTimePeriodAsync(GetLoadtestsForTimePeriodRequest getLoadtestsForTimePeriodRequest);
}

You’ll recognise the CRUD requests in the interface. You’ll also see how all of them return tasks in line with the async/await pattern.

We’re done with the abstraction for the timetable. We’ll build the concrete implementation in the next post.

View the list of posts on Architecture and Patterns here.

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

Leave a comment

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

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