The DomainAspects library introduced here may be the birth of an open source project that could add real value to the .NET stack. On the other hand, it could be just a small exploration of Castle Windsor's aspect oriented programming construct called the Interceptor. Time will tell but I felt it would be worth sharing the bits at this early stage to gauge interest and get some preliminary feedback.
DomainAspects is an aspect oriented infrastructure library for domain driven .NET projects. It uses Castle Windsor's Interceptor to provide configurable aspect oriented audit logging, authorization and exception handling to domain operations. Service classes in the domain can take advantage of DomainAspects using a custom attribute, avoiding the clutter of infrastructure code in the business logic.
There are many variations for the definitions of aspect oriented programming and domain driven design. I'll let Wikipedia contributors sort out the "pure" definitions. I'm not a purist or self-declared expert on either of these topics. But for the record, I'll share my definitions of these two as succinctly as I can.
Aspect Oriented Programming - The separation of cross cutting concerns, such as logging, authorization, and exception handling, from the business logic core of the application. AOP can allow the business application developer to focus on implementing business requirements without worrying about consistently applying and debugging repetitive infrastructure code throughout the application.
Domain Driven Design - An approach to writing applications where the domain is the core of the application. The domain defines the data, data persistence and business operations available to a user interface or service host of which it has no knowledge. DDD seeks to separate the mechanical concerns of the application host from the core business operations and data in order to maximize the potential for application developer specialization and code re-use. Common constructs seen in the domain are entities, services and repositories with a dependency on a persistence framework or data access layer.
DomainAspects brings AOP to DDD to make it easier to write the domain layer. Now I can write my acceptance criteria driven tests for a business operation and then implement that business operation with pure business logic while one or two simple attributes assure the consistent execution of infrastructure code every time that method is called. Here's a simplistic example:
[InterceptOperation, Authorize(RolesRule = "!Guest")]
public string GetUserPhoneNumber(int userId)
{
var userRepository = new UserRepository();
return userRepository.GetUser(userId).PhoneNumber;
}
And using that operation is just as easy. Here's the code to call that operation using the DomainProxy (normal UI exception handling not shown):
private void ShowPhoneButton_Clicked(object sender, EventArgs e)
{
using (var proxy = new DomainProxy<IUserService>())
{
var phone = proxy.Service.GetUserPhoneNumber(userId);
this.txtPhone.Text = phone;
}
}
The client or host code uses the DomainProxy wrapper to get an IDisposable instance of a Castle Windsor container instance of the service class which is in turn wrapped by the Interceptor proxy. Here’s a look at these three important classes:
Under the covers, three specific DomainAspects infrastructure things are happening via the auditor and authorizer objects injected into the interceptor along with the principal provider object injected into the authorizer object. Here’s a look at the classes in question.
The first two things that happen occur before the proxy proceeds with calling the business operation. The third only happens if the business operation code throws an exception.
- The OperationAuditor's LogOperationInvoked method is called allowing the invokation to be logged by your implementation of IOperationAuditor.
- The OperationAuthorizer's Authorize method is called where the authorize attribute's rule is enforced. In this case, the logged in user cannot be in the role "Guest" or an exception will be thrown. Note that the IPrincipal used to determine this is provided by the injected PrincipalProvider implementation.
- The OperationAuditor's LogOperationException method is called if the business operation throws an exception.
In future posts, I'll write about each of these parts and how they work, but for now, download the code and let me know what you think. You will need to download the Castle Windsor library and correct the references in the solution depending on where you have installed the Castle project library.
Download the code here: DomainAspects.zip (29.39 KB)