A reference architecture (part 4)

…continued from part 3

The application layer

The next layer is the application layer, where we will implement the request handlers that will contain all logic to execute commands. To do that, it will use the underlying domain layer; but it can also call external services, providers or adapters to execute logic that does not belong to our domain.

In this layer we will not handle queries; this is something that will be done in the service layer as queries work directly on the data and bypass any application or domain logic.

A request handler is an operation that is responsible for executing a specific command. It can accept parameters (the request), and it can return a result (the response). As each request has its dedicated request handler, we can make sure that the designated request handler is called automatically based on the request/response type.

First, add a new class library project called ArchitectureExample.Application.Dtos to the Application Layer solution folder, and put it physically in the \Trunk\Sources\ folder:

p4_1

This project will hold the request and response objects needed by the request handlers.

As specified earlier we need the following commands to be implemented: AddBlogEntry, PublishBlogEntry, UnpublishBlogEntry, ModifyBlogEntry, AddCommentToBlogEntry, RemoveCommentFromBlogEntry. So for each of these functionalities we need a request handler; and for each request handler we will add request and response objects:

[DataContract]
public class AddBlogEntryRequest : IRequest
{
public AddBlogEntryRequest() {}
public AddBlogEntryRequest(string title, string body)
{
Title = title;
Body = body;
}

[DataMember]
public string Title { get; set; }

[DataMember]
public string Body { get; set; }
}

[DataContract]
public class AddBlogEntryResponse : IResponse
{
public AddBlogEntryResponse() {}
public AddBlogEntryResponse(int blogEntryId)
{
BlogEntryId = blogEntryId;
}

[DataMember]
public int BlogEntryId { get; set; }
}

[DataContract]
public class PublishBlogEntryRequest : IRequest
{
public PublishBlogEntryRequest() {}
public PublishBlogEntryRequest(int blogEntryId)
{
BlogEntryId = blogEntryId;
}

[DataMember]
public int BlogEntryId { get; set; }
}

[DataContract]
public class UnpublishBlogEntryRequest : IRequest
{
public UnpublishBlogEntryRequest() {}
public UnpublishBlogEntryRequest(int blogEntryId)
{
BlogEntryId = blogEntryId;
}

[DataMember]
public int BlogEntryId { get; set; }
}

[DataContract]
public class ModifyBlogEntryRequest : IRequest
{
public ModifyBlogEntryRequest() {}
public ModifyBlogEntryRequest(int blogEntryId, string title, string body)
{
BlogEntryId = blogEntryId;
Title = title;
Body = body;
}

[DataMember]
public int BlogEntryId { get; set; }

[DataMember]
public string Title { get; set; }

[DataMember]
public string Body { get; set; }
}

[DataContract]
public class AddCommentToBlogEntryRequest : IRequest
{
public AddCommentToBlogEntryRequest() {}
public AddCommentToBlogEntryRequest(int blogEntryId, string name, string emailAddress, string commentText)
{
BlogEntryId = blogEntryId;
Name = name;
EmailAddress = emailAddress;
CommentText = commentText;
}

[DataMember]
public int BlogEntryId { get; set; }

[DataMember]
public string Name { get; set; }

[DataMember]
public string EmailAddress { get; set; }

[DataMember]
public string CommentText { get; set; }
}

[DataContract]
public class AddCommentToBlogEntryResponse : IResponse
{
public AddCommentToBlogEntryResponse() {}
public AddCommentToBlogEntryResponse(int commentId)
{
CommentId = commentId;
}

[DataMember]
public int CommentId { get; set; }
}

[DataContract]
public class RemoveCommentFromBlogEntryRequest : IRequest
{
public RemoveCommentFromBlogEntryRequest() {}
public RemoveCommentFromBlogEntryRequest(int blogEntryId)
{
BlogEntryId = blogEntryId;
}

[DataMember]
public int BlogEntryId { get; set; }
}

Notice that if we don’t have to return anything, we don’t create a Response object. Also, we decorate each Request and Response object with the [DataContract] attribute and each property with the [DataMember] attribute, because eventually these are the dto’s that will be exposed by the service layer later.

We also have to add the IRequest and IResponse interfaces, for that add a new class library project called ArchitectureExample.Application.Shared to the Application Layer solution folder, and put it physically in the \Trunk\Sources\ folder:

p4_2

There, add the following interfaces:

public interface IRequest
{
}

public interface IResponse
{
}

public interface IRequestHandler<TRequest, TResponse> where TRequest : IRequest where TResponse : IResponse
{
TResponse Execute(TRequest request);
}

public interface IRequestHandler<TRequest> where TRequest : IRequest
{
void Execute(TRequest request);
}

public interface IUnitOfWork : IDisposable
{
void Commit();
}

Now add a new class library project called ArchitectureExample.Application.RequestHandlers to the Application Layer solution folder, and put it physically in the \Trunk\Sources\ folder:

p4_3

Now it’s time to add the request handlers:

public class AddBlogEntryRequestHandler : IRequestHandler<AddBlogEntryRequest, AddBlogEntryResponse>
{
private readonly IUnitOfWork _unitOfWork;
private readonly IBlogEntryRepository _blogEntryRepository;

public AddBlogEntryRequestHandler(IUnitOfWork unitOfWork, IBlogEntryRepository blogEntryRepository)
{
_unitOfWork = unitOfWork;
_blogEntryRepository = blogEntryRepository;
}

public AddBlogEntryResponse Execute(AddBlogEntryRequest request)
{
var blogEntry = new BlogEntry(request.Title, request.Body);
_blogEntryRepository.Add(blogEntry);
_unitOfWork.Commit();
return new AddBlogEntryResponse(blogEntry.Id);
}
}

public class AddCommentToBlogEntryRequestHandler : IRequestHandler<AddCommentToBlogEntryRequest, AddCommentToBlogEntryResponse>
{
private readonly IUnitOfWork _unitOfWork;
private readonly IBlogEntryRepository _blogEntryRepository;

public AddCommentToBlogEntryRequestHandler(IUnitOfWork unitOfWork, IBlogEntryRepository blogEntryRepository)
{
_unitOfWork = unitOfWork;
_blogEntryRepository = blogEntryRepository;
}

public AddCommentToBlogEntryResponse Execute(AddCommentToBlogEntryRequest request)
{
var blogEntry = _blogEntryRepository.BlogEntries.SingleOrDefault(be => be.Id == request.BlogEntryId);
var comment = blogEntry.AddComment(request.Name, request.EmailAddress, request.CommentText);
_unitOfWork.Commit();
return new AddCommentToBlogEntryResponse(comment.Id);
}
}

public class ModifyBlogEntryRequestHandler : IRequestHandler<ModifyBlogEntryRequest>
{
private readonly IUnitOfWork _unitOfWork;
private readonly IBlogEntryRepository _blogEntryRepository;

public ModifyBlogEntryRequestHandler(IUnitOfWork unitOfWork, IBlogEntryRepository blogEntryRepository)
{
_unitOfWork = unitOfWork;
_blogEntryRepository = blogEntryRepository;
}

public void Execute(ModifyBlogEntryRequest request)
{
var blogEntry = _blogEntryRepository.BlogEntries.SingleOrDefault(be => be.Id == request.BlogEntryId);
blogEntry.Modify(request.Title, request.Body);
_unitOfWork.Commit();
}
}

public class PublishBlogEntryRequestHandler : IRequestHandler<PublishBlogEntryRequest>
{
private readonly IUnitOfWork _unitOfWork;
private readonly IBlogEntryRepository _blogEntryRepository;

public PublishBlogEntryRequestHandler(IUnitOfWork unitOfWork, IBlogEntryRepository blogEntryRepository)
{
_unitOfWork = unitOfWork;
_blogEntryRepository = blogEntryRepository;
}

public void Execute(PublishBlogEntryRequest request)
{
var blogEntry = _blogEntryRepository.BlogEntries.SingleOrDefault(be => be.Id == request.BlogEntryId);
blogEntry.Publish();
_unitOfWork.Commit();
}
}

public class UnpublishBlogEntryRequestHandler : IRequestHandler<UnpublishBlogEntryRequest>
{
private readonly IUnitOfWork _unitOfWork;
private readonly IBlogEntryRepository _blogEntryRepository;

public UnpublishBlogEntryRequestHandler(IUnitOfWork unitOfWork, IBlogEntryRepository blogEntryRepository)
{
_unitOfWork = unitOfWork;
_blogEntryRepository = blogEntryRepository;
}

public void Execute(UnpublishBlogEntryRequest request)
{
var blogEntry = _blogEntryRepository.BlogEntries.SingleOrDefault(be => be.Id == request.BlogEntryId);
blogEntry.Unpublish();
_unitOfWork.Commit();
}
}

As you see dependencies like unit of work and the repository are constructor injected.

Note that I used the simplistic approach without exception handling or other validation, because we will implement this later to keep it simple at this point.

At his point we have the application layer in place:

p4_4

Next time we will continue with the infrastructure layer.

Advertisements

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