How to Pass Current User Information to All Layers in Ddd

How to pass Current User Information to all Layers in DDD

I've done this kind of thing before using IoC. The benefit of this is that it's very testable -- you can stub out your user info for testing -- and reasonably readable and easy to follow.

DDD pass filters through multiple layers

DDD and onion architecture share common principles (e.g. domain isolation), however they also draw some different aspects regarding development techniques. It should be pointed out that architectures and designs should serve our goals rather than be the goals themselves.

From your description it seems you have a CRUD-style system. I see no business rules, no domain concepts, no specifications. And that is, of course, not a bad thing.

Isolating domain from other layers (presentation, infrastructure) is beneficial in particular when sophisticated validations are to be applied and business rules are to be enforced within complex entity objects. In your case, however, you map plain object LogRabbitMQFilters (presentation layer) to "itself" (application layer) then to plain object RabbitMQFilters (infrastructure layer). Passing an object as is from presentation layer to application layer is OK in cases like yours (even from a DDD/onion perspective), however:

  1. The second mapping should not exist, since infrastructure layer knows domain and therefore should receive your (presumably) domain entity LogRabbitMQFilters.
  2. LogRabbitMQFilters is actually not a true domain entity since, as mentioned before, it does not apply any business rule.
  3. Flatly mapping objects from one layer to another seems pointless.

I thought of specification pattern but I don't now if it's a good solution

Specification pattern is very useful when we want to pack expressions as business invariants, e.g. having a class named ShortMessage (business invariant) encapsulating an expression such as Message.Length < 42. But with your case I see no use for that, due to the CRUD nature of your application: you simply receive some user properties to function as operands in the context of an ORM object representing a database table, in order to do something like that:

myORMManager
.FetchAll<MyTableObject>()
.Filter(record =>
record.DateDebut == filter.DateDebut &&
record.DateFin == filter.DateFin &&
.
.
record.Message == filter.Message
.
.
.
);

Each of the predicates separated by 'and' operator can be considered as specification, however such specifications are just technical, as they do not convey any business invariant. The object filter can actually be a client request.

To conclude, it is acceptable to develop a single-layer application directly using client properties as operands for database filter expressions, as long as business invariants are out of picture (or at least with low complexity). If you would still like to have a DDD framework, i.e. having an application service (where you may apply simple validations such as DateFin > DateDebut) and a repository object together with the controller object, then I would recommend to have a single class "walking through" all three objects

Including user id in domain events

The most pragmatic way of doing this would probably be to simply store the user's information (along with other session/request info) as event metadata (hopefully your event store supports that) and handle this concern outside the domain.

For instance, in one application I've written an event store implementation that can be configured with an EventMetadataProvider, which gets registered in the application's composition root and uses the current request context to append metadata such as the user's ID, remote IP address, etc.

Note that you could still enrich some domain events with the approver/creator/etc. where it matters the most for event consumers, but ideally not with a generic UserId concept.

How do integrate Users in my DDD model with authenticating users?

Yes - very good question. Like @Andrew Cooper, our team also went through all this.

We went with the following approaches (right or wrong):

Custom Membership Provider

Neither I or the other developer are fans of the built in ASP.NET Membership provider. It's way too bloated for what our site is about (simple, UGC-driven social website). We created a very simple one that does what our application needs, and nothing more. Whereas the built-in membership provider does everything you might need, but most likely won't.

Custom Forms Authentication Ticket/Authentication

Everything in our application uses interface-driven dependency injection (StructureMap). This includes Forms Authentication. We created a very thin interface:

public interface IAuthenticationService
{
void SignIn(User user, HttpResponseBase httpResponseBase);
void SignOut();
}

This simple interface allows easy mocking/testing. With the implementation, we create a custom forms authentication ticket containing: things like the UserId and the Roles, which are required on every HTTP request, do not frequently change and therefore should not be fetched on every request.

We then use an action filter to decrypt the forms authentication ticket (including the roles) and stick it in the HttpContext.Current.User.Identity (for which our Principal object is also interface-based).

Use of [Authorize] and [AdminOnly]

We can still make use of the authorization attributes in MVC. And we also created one for each role. [AdminOnly] simply checks the role for the current user, and throws a 401 (forbidden).

Simple, single table for User, simple POCO

All user information is stored in a single table (with the exception of "optional" user info, such as profile interests). This is mapped to a simple POCO (Entity Framework), which also has domain-logic built into the object.

User Repository/Service

Simple User Repository that is domain-specific. Things like changing password, updating profile, retrieving users, etc. The repository calls into domain logic on the User object i mentioned above. The service is a thin wrapper on top of the repository, which seperates single repository methods (e.g Find) into more specialized ones (FindById, FindByNickname).

Domain seperated from security

Our "domain" the User and his/her's association information. This includes name, profile, facebook/social integration, etc.

Things like "Login", "Logout" are dealing with authentication and things like "User.IsInRole" deals with authorization and therefore do not belong in the domain.

So our controllers work with both the IAuthenticationService and the IUserService.

Creating a profile is a perfect example of domain logic, that is mixed with authentication logic also.

Here's what our's looks like:

[HttpPost]
[ActionName("Signup")]
public ActionResult Signup(SignupViewModel model)
{
if (ModelState.IsValid)
{
try
{
// Map to Domain Model.
var user = Mapper.Map<SignupViewModel, Core.Entities.Users.User>(model);

// Create salt and hash password.
user.Password = _authenticationService.SaltAndHashPassword();

// Signup User.
_userService.Save(user);

// Save Changes.
_unitOfWork.Commit();

// Forms Authenticate this user.
_authenticationService.SignIn(user, Response);

// Redirect to homepage.
return RedirectToAction("Index", "Home", new { area = "" });
}
catch (Exception exception)
{
ModelState.AddModelError("SignupError", "Sorry, an error occured during Signup. Please try again later.");
_loggingService.Error(exception);
}
}

return View(model);
}

Summary

The above has worked well for us. I love having a simple User table, and not that bloated madness that is the ASP.NET Membership provider. It's simple and represents our domain, not ASP.NET's representation of it.

That being said, as i said we have a simple website. If you're working on a banking website then i would be careful about re-inventing the wheel.

My advice to use is create your domain/model first, before you even think about authentication. (of course, this is what DDD is all about).

Then work out your security requirements and choose an authentication provider (off the shelf, or custom) appropriately.

Do not let ASP.NET dictate how your domain should be designed. This is the trap most people fall into (including me, on a previous project).

Good luck!

Communicate from Domain Model back down to Application Layer

I can think of different options which are - depending on your concrete requirements - more or less suited and it is also OK to choose different approaches for different use cases and mix them in your solution.

To illustrate this I want to look into different options based on an operation of a product application which I simply call AddPriceToProduct(AddProductPriceCommand pricingCommand). It represents the use case where a new price for a product is added. The AddProductPriceCommand is a simple DTO which holds all required data to perform the use case.


Option (A): Inject the corresponding service (for instance, an email service) you need to call when executing your domain logic into your domain object's methods (here AddPrice).

If you choose this approach always pass in an interface (which is defined in your domain layer) rather than the actual implementation (which should be defined in the infrastructure layer). Also, I would not choose this approach if several things should happen after something has happened in your domain operation.

public void AddPriceToProduct(AddProductPriceCommand pricingCommand)
{
var product = _productRepository.findById(pricingCommand.productId);
product.AddPrice(pricingCommand.price, _emailService);
_productRepository.Update(product);
}

And the corresponding AddPrice method might look like this:

public void AddPrice(int price, IEmailService emailService)
{
var currentPrice = _prices.LastOrDefault();

if(price < currentPrice)
{
_prices.add(price);
// call email service with whatever parameters required
emailService.Email(this, price);
}
}

Option (B): Let the application service (which orchestrates the use cases) call the corresponding service(s) after you called the corresponding aggregate (or domain service) method which needs to be executed for the application use case.

This can be a simple and valid approach if this should always happen after a specific domain model operation has been executed. By that I mean, after calling the method on your aggregate (or domain service), in your case the AddPrice method, there is no conditional logic if the other services (e.g. email) should be called or not.

public void AddPriceToProduct(AddProductPriceCommand pricingCommand)
{
var product = _productRepository.findById(pricingCommand.productId);
product.AddPrice(pricingCommand.price);
_productRepository.Update(product);
// always send an email as part of the usual workflow
_emailService.Email(product, pricingCommand.price);
}

In this case we assume that the normal workflow will always include this additional step. I do not see a problem with being pragmatic here and just call the corresponding service in the application service method.


Option (C): Similar to Option (B) but there is conditional logic to be executed after AddPrice has been called. In this case this logic can be wrapped into a separate domain service which would take care of the conditional part based on the current state of the Product or the result - if there is any - of the domain operation (AddPrice).

Let's first simply change the application service method by including some domain knowledge:

public void AddPriceToProduct(AddProductPriceCommand pricingCommand)
{
var product = _productRepository.findById(pricingCommand.productId);
product.AddPrice(pricingCommand.price);
_productRepository.Update(product);

if (product.HasNewPrice())
{
_emailService.Email(product, pricingCommand.price;
}
if (product.PriceTargetAchieved())
{
_productUpdater.UpdateRatings(product, pricingCommand.price);
}
}

Now this approach has some space for improvements. As the logic to performed is bound to the AddPrice() method of the product it might be easy missed that the additional logic needs to be called (calling the email service or the updater service under certain circumstances). Of course you could inject all services into the AddPrice() method of the Product entity but in this case we want to look into the option of extracting the logic into a domain service.

At first let's look at a new version of the application service method:

public void AddPriceToProduct(AddProductPriceCommand pricingCommand)
{
var product = _productRepository.findById(pricingCommand.productId);
_productPricingService.AddPrice(product, pricingCommand.price);
_productRepository.Update(product);
}

And now let's look at the corresponding domain service method of a domain service called, e.g. ProductPricingService:

public void AddPrice(Product product, int price)
{
if (product.HasNewPrice())
{
_emailService.Email(product, pricingCommand.price;
}
if (product.PriceTargetAchieved())
{
_productUpdater.UpdateRatings(product, pricingCommand.price);
}
}

Now the logic for handling price updates to a product are handled at the domain layer. In addtion, the domain logic is easier to unit test as there are fewer dependencies (e.g. the repository is not of concern here) and with that fewer test doubles (mocking) need to be used.

It is of course still not the highest degree of business logic encapsulation in combination with the lowest degree of dependencies inside the domain model, but it comes at least a little closer.

To achieve the above mentioned combination domain events will be at service, but of course these could also come with a higher amount of implementation efforts. Let's look at this in the next option.


Option (D): Raise domain events from your domain entities and implement the corresponding handlers which could be domain services or even infrastructure services.

The connection between domain event publishers (your domain entities or domain services) and the subscribers (e.g. email service, product updater, etc.).

In this case I recommend to not immediately dispatch raised events but rather collecting them and only after everything has worked out fine (i.e. no exceptions have been thrown, state has been persisted, etc.) dispatch them to be handled.

Let's look at the AddPrice() method of the Product entity again by using a corresponding domain event.

public void AddPrice(int price, IEmailService emailService)
{
var currentPrice = _prices.LastOrDefault();

if(price < currentPrice)
{
_prices.add(price);
RaiseEvent(
new ProductPriceUpdatedEvent(
this.Id,
price
));
}
}

The ProductPriceUpdateEvent is a simple class which represents the business event that has happened in the past along with the information required by subscribers to this event. In your case the subscribers would be the email service, the product update service, etc.

Consider the RaiseEvent() method as a simple method which adds the created event object to a collection of the product entity in order to collect all events happending during one or more business operations that are called from an application or domain service. This event collecting functionality could also be part of an entity base class but that is an implementation detail.

The important thing is that after the AddPrice() method has been executed the application layer will make sure that all collected events will be dispatched to the corresponding subscribers.

With that the domain model is completely independent of the infrastructure service dependencies as well as from the event dispatching code.

The "Committing before dispatching" approach described in this blog post by Vladimir Khorikov illustrates this idea and is also based on your technology stack.

Note: Unit testing the logic of your Product domain entity is now very simple as opposed to the other solutions as you don't have any dependencies and mocking should not be necessary at all. And testing if the corresponding domain events have been called at the right operations is also easy as you simply have to query the collected events from the Product entity after calling a business method on it.


To get back to your questions:

How can I implement this without making my domain reliant on the services?

To achieve this you can look into options (B), (C) and (D)

Or should I be passing those to my domain?

This can be a valid approach - see option (A) - but be aware that it will make things more complicated if there are several dependencies to be injected in terms of maintainability and testability of your domain model classes.

When I choose between these different options I always try to find out what parts of the performed actions do really belong to that corresponding business operation and what parts are more or less unrelated and are not really required to make the business transaction a valid one.

For instance, if some operation that needs to be performed by a service is required to happen or otherwise the whole operation should not happen at all (in terms of consistency) then option (A) - injecting a service into a domain model method - might be a good fit. Otherwise I would try to decouple any subsequent steps from the domain model logic in which case the other options should be considered.



Related Topics



Leave a reply



Submit