Building Domain Driven Architecture in .NET – Part 5 (ASP.NET Core App)

In part 4, I detailed the way I went about creating application services for my expense tracking application. In this final post, I will talk about the ASP.NET Core MVC application that I built with HTML5/Razor front end views on top of the application services.

Remember the application services consumption model sketch from the last post? The web application will need to take a dependency on the application services and the domain model at the very least. Then, in the MVC controllers’ constructor signature, I will declare the dependency using the application service interface and in the controller actions, use that instance to call various use cases methods against the application services. That’s pretty much it!

I decided to use ASP.NET Core MVC to build the server application and front end since it is a complete rewrite of the ASP.NET MVC framework with a completely different request processing pipeline and much more modular design. It offers an inbuilt Dependency Injection container which means I don’t have to set one up by hand for most cases. The whole request processing pipeline can be configured and customised in code. The framework is cross platform and can be self-hosted or IIS hosted. ASP.NET Core applications use Kestrel web server which is an extension of another open source library called “libuv“. Kestrel is in the process of maturing (as of ASP.NET Core 2.0) but since my application is built on ASP.NET Core 1.1, it sits behind IIS and processes requests proxied to it by IIS. You can read more about ASP.NET Core and Kestrel architecture and libuv architecture.

The application references the application services, domain model and repository assemblies at a minimum but can reference more as needed.

Dep
Project Dependencies for the web app

The reason for including the repository assemblies is not so that I can use them directly from the controller but so that I can configure the dependency injection for them. The ASP.NET Core application sets up a Startup.cs file where I can configure all the dependencies that my application needs. This is always done at the composition root level i.e. the executable application level. If this were a WinForms app, it would be done at the WinForms project level. That’s just how DI containers work.

// This method gets called by the runtime. Use this method to add
// services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Set up the DbContext
services.AddDbContext(options =>     options.UseSqlServer(Configuration.GetConnectionString("TraxpenseConnection")), 							 ServiceLifetime.Scoped);

services.AddSession(options =>
{
options.CookieSecure = CookieSecurePolicy.Always;
});

services.AddSingleton();

services.AddAuthentication(
SharedOptions => SharedOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);

// the Sql Server repository implementations are set-up to be scoped by
// request
services.AddScoped();
services.AddScoped();

// the application service implementation is also set-up to be scoped by
// request
services.AddScoped();

//.. other services
}

The code above shows how the various implementations are injected into the application at runtime. This allows me to declare dependency in the consuming controllers using only interfaces as the actual implementation will be provided at runtime thereby decoupling the policy from mechanism.

The controller can now take the required dependency on the application services and call the use case methods on it and act upon the data returned:

[Authorize]
public class ExpensesController : Controller
{
private IPeriodService periodService;

// the implementation of IPeriodService will be injected
// by the DI container at runtime.
public ExpensesController(IPeriodService periodService)
{
this.periodService = periodService;
}

public async Task GetExpensesAsync(Guid potId)
{
var expenses = await this.periodService.GetAllExpensesForPotAsync(SessionHelper.GetCurrentlyActivePeriodFromSession().PeriodId, potId);

// convert the returned domain objects to ViewModel objects
// appropriate for the view.
return PartialView("_ViewPotExpensesPartial", expenses.ToModel());
}

[HttpPost]
public async Task AddNewExpenseAsync(ExpenseViewModel expenseModel)
{
await this.periodService.AddNewExpenseAsync(expenseModel.Date,
expenseModel.Spend,
expenseModel.Description,
expenseModel.PotId,
SessionHelper.GetCurrentlyActivePeriodFromSession().PeriodId);

return Json("Done");
}

//.. more actions
}

Notice that in the GetExpensesAsync() method above, I am converting the returned domain objects to ViewModel objects most appropriate for the view in questions. These ViewModels are just POCO (Plain Old C# Objects) data structures (as shown below) with public getters and setters with no logic in them. They are meant to be a read-only view of the data, I could make them truly read-only by removing the setter and the application would still work because I don’t use ViewModels to perform update operations of any kind so those properties don’t need to be writable:

public class ExpenseViewModel
{
private DateTime date;
private string description;
private string formattedDate;
private Guid expenseId;
// .. more private variables

public ExpenseViewModel(DateTime date, string description, Guid expenseId)
{
this.Date = date;
this.Description = description;
this.expenseId = expenseId;
// more assignments
}

public ExpenseViewModel()
{
}

public DateTime Date
{
get => date;

set
{
date = value;
this.FormattedDate = value.ToString("d");
}
}

public string Description
{
get => description;
set => description = value;
}

[DisplayName("Expense Date")]
public string FormattedDate
{
get => formattedDate;
set => formattedDate = value;
}

public Guid ExpenseId
{
get => expenseId;
}
//.. more properties
}

The view model represents a flatter world view of the rich domain object model. It can contain properties that don’t form the part of the core domain model but are essential from user’s perspective. For e.g. FormattedDate property is one such property. The domain model doesn’t care if I want to display the expense date as a nicely formatted string, its a UI concern so it should lie with the view representation of the domain object. I can also put properties that can help me identify an entity for e.g. in the above code I have included the ExpenseId read only property because when I bind the list of expenses to a grid view, I want to be able to reverse an expense (still honouring the “via root only” access paradigm of DDD) I can easily do that if I have a handle of the identity of that expense object. The use case methods defined in the application services will ensure I don’t do anything that I am not supposed to do with the expense object that I know the identity of for e.g. I can’t delete the expense even though I know the id because neither the application service nor the UI allow for that functionality because its not one of the use cases of the domain model.

The view-model approach also tends to eliminate the data that’s not needed for a view allowing me to create view specific domain representations that are light-weight and quickly serialised and deserialised. I never expose my domain objects directly to the UI because it introduces a tight coupling between the domain and the UI which is not good for maintainability. The obvious downside to the ViewModel/DTO approach (in case of REST APIs) is that I now have to maintain 2 types of structures and translate back and forth for most use cases thereby adding some latency. But if I can ensure loose coupling and separation of concerns, then that little bit of latency is worth it. Besides since DTOs/ViewModels are only a sub-set of the domain models, this latency should be small. Either way its a trade off that I as an architect/developer have to keep in mind and ensure that I am gaining something of value in return.

On the other hand, if the view model is exact one to one replica of the domain object then I can just eliminate the view models completely and expose the domain objects out to the UI directly provided there is no business logic behaviour in those objects and they are just CRUD type data structures. In this application however, that’s not the case.

I also like to create adaptor classes exposing extension methods that allow me to conveniently convert domain model objects to view model structures. As an example:

public static class ExpenseToViewModelAdaptor
{
public static IEnumerable ToModel(this IEnumerable expenses)
{
List models = new List();

foreach (var expense in expenses)
{
models.Add(expense.ToModel());
}

return models.AsEnumerable();
}

public static ExpenseViewModel ToModel(this Expense expense)
{
ExpenseViewModel model = null;

if (expense != null)
{
model = new ExpenseViewModel(expense.ExpenseDate,
expense.Description,
expense.Id);
}

return model;
}
}

This can now be easily called from within a controller like so:

public async Task GetExpensesAsync(Guid potId)
{
var expenses = // rerieve the expenses

return PartialView("_ViewPotExpensesPartial", expenses.ToModel());
}

Its as if the “ToModel()” method is available against the expenses collection, such is the power of extension methods. I can re-use this method across the application without doing any code duplication.

Once the data is bound on the view, I use jQuery AJAX to handle the UI events and invoke the controller actions:


$(document).ready(function () {
$("[id^=btnReverse]").click(function (e) {
var potId = $("#potIdForExpenses").val();
var expenseId = $(this).attr("data-expenseid");
var expenseHandler = new ExpenseHandler();
expenseHandler.ReverseExpense(potId, expenseId);
});
});
}

In this code above, I am handling the click event of the “Reverse” button on the expenses grid view and invoking the JavaScript module that handles expense interactions. These JavaScript modules are ES6 compliant modules that use the “class” keyword and OO semantics:

class ExpenseHandler {
constructor() {
}

CreateExpense(expense) {
$.ajax({
url: 'Expenses/AddNewExpenseAsync',
cache: false,
method: 'POST',
data: { ... }
}).done(function (result) {
_RaiseExpenseEvent("expense:created");
}).fail(function (errorResult) {
ShowError(errorResult.responseJSON);
});
}

ReverseExpense(potId, expenseId) {
$.ajax({
url: 'Expenses/ReverseExpenseAsync',
cache: false,
method: 'POST',
data: { ... }
}).done(function (result) {
_RaiseExpenseEvent("expense:reversed");
}).fail(function (errorResult) {
ShowError(errorResult.responseJSON);
});
}
}

function _RaiseExpenseEvent(eventName) {
var expenseCreatedEvent = new CustomEvent(eventName);
document.dispatchEvent(expenseCreatedEvent);
}

In order to keep these JS modules fairly loosely coupled from the DOM, I use events. I raise an event when something happens (for e.g. “expense:created” and “expense:reversed” events in the above JS code) passing in all the relevant information to successfully handle the event in the view and in the view I attach the event handler to the main document root using jQuery semantics which are cleaner to follow:


$(document).ready(function () {
$(document).on("expense:reversed", RefreshExpensesForThisPot);
// other code
});

function RefreshExpensesForThisPot(){
// handle the event appropriately
}
}

My general strategy for writing JavaScript code is that if the JS code needs to do something specific to the view (for e.g. invoke the click action handler for the expense grid button) it will be declared within the view itself, otherwise, if its sufficiently generic global level action (for e.g. show AJAX loading gif or display errors in the UI etc) then it sits in a global script file such as the site.js file that comes with the ASP.NET Core MVC web application project template. I also create application specific JS modules (either ES6 classes or IIFE) to deal with application specific code for e.g. Expense.js handles all expense related call-outs. I am sure there are better patterns for writing JS code for the UI but so far this has worked for me. The key thing for me is to keep coupling as low as possible between UI elements and JS code and communicate between the 2 using events and callbacks. I will probably do another post at some point detailing a “Chaos Coordinator Pattern” that I implemented on one of my projects at work some time ago.

Back in ASP.NET Core, once the base application is up and running, I will then go and add things like global error handling using custom action filters, error logging using some kind of logging mechanism (ASP.NET Core out of the box provides AppInsights, Console and Debug window logging). For my application, I wrote an implementation of a text file based logging using the abstractions provided by .NET Core framework. The reason for this was that my application is not hosted on Azure because I want to keep deployment and storage costs zero, I am just using my home server i.e. internal network to host the application on IIS and here I only have access to server’s hard disk.

I can easily configure the application to be hosted on Azure, all I will need to do remove the components that rely on server hard disk and add a logger that uses Azure’s AppInsights for telemetry and logging. As for authentication, I decided to use Azure AD since this application is hosted internally and is only a single user app for now but could support multiple users with a custom membership provider or social login integration.

One more thing, I have recently started following the Task Based Asynchronous Pattern for writing code that deals with network I/O, CPU and/or disk I/O. Especially for web applications it can be useful since the request threads are no longer blocked waiting for a response from an external interface instead, they can immediately return to the thread pool to serve other requests and when the blocked request finishes, that request thread can resume processing where it left off. This is the essence of Task-based Async Pattern is achieved fairly simply by using “async-await” keywords. Most of Microsoft’s Azure APIs are increasingly becoming asynchronous so to take advantage of those, most application code will have to be asynchronous itself. This is sometimes called “Async All the Way“.

This whole project which is still a work in progress, has given me enough confidence and understanding in Domain Driven Design to take it further and expand on it. Unfortunately, many companies still don’t understand domain driven design or are not willing to make a time investment into it. Perhaps they think its only for some hypothetical super-complex domains and that their project doesn’t qualify. What they are failing to understand is that DDD is about object orientation and if they do OO then they are more than half way there. It might take some time before DDD becomes a bit more main stream but in the mean time we as developers and architects should start preparing our case for using it backed up by our own experiences and knowledge with it. Its just another tool in an architect’s toolbox but its a pretty darn good one.

I hope this 5 part series has been of some help and/or insight into how one can start delving into DDD by practice.

3 Replies to “Building Domain Driven Architecture in .NET – Part 5 (ASP.NET Core App)”

    1. Cheers Gary! I am not quite sure what happened there because I certainly remember publishing it. Sorry about that! It should be up now although will appear after part 5 in the list so a little counter-intuitive.

      Aman

Leave a Reply to Gary Raley Cancel 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 )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.