C# – Domain Driven Design in Net – Project Structure

cdomain-driven-designprojects-and-solutions

I'm getting my head around DDD and how to build up an C# Project structure for an .Net Core WebApp.
I searched quite a bit around the web, for example How to structure a Domain Driven Design in an Onion Architecture?, https://github.com/zkavtaskin/Domain-Driven-Design-Example and several Pluralsight courses.

What bogs me is the fact, that this HelloWorld-examples don't seem to work very well in the real life:
Let's say we build the propagated onion structure of Application, Domain and Infrastructure. Application would in this case be the WebApi-part, Domain the Domain-Services, Entities, Value Objects etc. and Infrastructure the implementation of the Interfaces defined in the Domain-Assembly.

So far so good, but with this approach, I'd need to define every bit of helping code in the Domain-Layer. For Services, Handlers, etc. I could define just the Interfaces and let the implementation inject from the Infrastructure-layer. But as soon as I started coding like this, I had folders like Attributes, Handlers (low level services for REST, Files etc.) and a ton of other technical stuff in my domain-layer.
For the sake of testing, I tried to revert the dependency, so the Domain targets the Infrastructure. This allows to move all the supporting code and low-level handlers to the Infrastructure, but makes communication awkward: Since the entities and value objects are still in the Domain, the Infrastructure doesn't know them anymore, so I'd need to map them to DTOs, adding another mapping layer just for this communication.

From reading Eric Evans book, I took the idea, that the Domain-Layer should be written in the ubiquitous language, be technical agnostic and be the communcation platform with the domain experts. But I can't find a good solution to have the both of best worlds. Am I missing something crucial here?

Best Answer

I think that we often out-think ourselves when we are trying to learn a new way of doing things. Instead of boiling the problem down to the smallest thing that can possibly work, we think about things that aren't important right now. Onion architecture and DDD work together to provide a way of letting you define that simplest way of doing things.

What's really your domain?

That's the question you need to be asking yourself. The most core concepts are:

  • How domain objects interact with other domain objects
  • How domain objects interact with primary services

Everything else is completely outside the domain. Whether you use a Repository pattern for persistence or something else is beside the point. There will be points where your domain object needs to interact with a service. That's OK.

  • Stub your services using interfaces and domain terminology

And stop. You can have a fully unit tested domain driven design with these two concepts.

Services from the inside out

In an Onion architecture, the implementation of your services are done at a layer outside of your domain model. That keeps the domain clean, and separated from the concerns of your service.

One example would be using a SQL database for persistence. If you need to change that in the future, or add other types of databases (graph, search, etc) to facilitate your system, you can localize those changes behind the service you defined in the domain model.

Common things that are not central to the domain:

  • Authentication
  • Persistence
  • Rendering (i.e. REST services, full web application, desktop app, etc)
  • Internationalization
  • Messaging

That is not a full and exhaustive list.

Your domain may have users, and those users have roles... but how the user is authenticated and those roles supplied are things that will change over time.

Modes of messaging may change over time, as well as specific content, but the types of messages and triggers that kick them off are related to the domain.

Feel free to apply the same concepts to implementing your services as you did for the core domain. The only difference is the domain for a persistence service is different than for your core application.

Project Structure

It really depends on how granular you want to go, but at the very least you should have one library as your core domain model. You can have service implementations in separate projects, or group some things together.

+ Solution
  + Project.Domain (or Core if you prefer)
  + Project.Domain.Test
  + Project.Persistence.Service
  -- etc.
  * WebAPI

Don't be overly religious about your project organization. It only needs to be reasonably clear where to look for things. Your core domain library has the domain objects and interfaces for services as necessary. The only rule I'd recommend is to have a clear hierarchy of project dependencies. Project.Domain shouldn't depend on anything outside of your standard library for the language you are using.

Related Topic