3

I've been trying to refactor an old design in to an Onion Architecture in DDD style. To that point, the project went from a monolith to 4 sub-projects:

/src
    /Project.Application
        /Services
    /Project.Core
        /Domain
        /RepositoryInterfaces
    /Project.Infrastructure
        /DataModels
        /DataServiceInterfaceAndImplementations
        /RepositoryImplementations
    /Project.Web
        /Controllers
        /ViewModels
        /Views
/test
    /Project.Core.Tests
    /Project.Infrastructure.Tests
    /Project.Web.Tests

Core

Core contains my domain objects - named after the actual conceptual objects in the system the way the business user might understand it.

class SaleType { 
    string Name { get; set; } 
}

Core also contains my repository interfaces - named after the domain model the repository is supposed to return.

interface ISaleTypeRepository {
    SaleType GetSaleTypeForADepartmentSale(int departmentSaleId);
    IList<SaleType> GetAllowedSaleTypesForADepartment(int departmentId);
}

Infrastructure

Infrastructure contains dataservices and implementations specific to our AS400 back end.

Datamodels exist to facilitate communication between the domain and the database.

class SaleTypeModel
{
    public int Id { get; set; }
    public string Name { get; set; }
}

And the interfaces are how we return the datamodels from the database tier:

interface ISaleTypeDataService
{
    SaleTypeModel GetSaleType(int departmentSaleId);
}
interface IDepartmentAllowableSaleTypesDataService
{
    DepartmentAllowableSaleTypeModel GetDepartmentAllowableSaleType(int departmentAllowedSaleId);
}

The repositoryimplementations folder then contains implementations of the repositories from core, delegating to the dataservices in infrastructure to get the data, and map to the appropriate domain object (in this case, SaleType from earlier). Though my dataservices in the Infrastructure tier might be returning different datamodel types that represent an aspect of a sale type - for instance a "DepartmentAllowedSaleTypeModel", the repository will delegate to the data service then map them back to the SaleType domain object internally.

class SaleTypeRepository : ISaleTypeRepository
{
    private readonly ISaleTypeDataService _saleTypeDataService;
    private readonly IDepartmentAllowableSaleTypesDataService _departmentAllowableSaleTypesDataService;

    public SaleTypeRepository(ISaleTypeDataService saleTypeDataService, IDepartmentAllowableSaleTypesDataService departmentAllowableSaleTypesDataService)
    {
        _saleTypeDataService = saleTypeDataService;
        _departmentAllowableSaleTypesDataService = departmentAllowableSaleTypesDataService;
    }

    public IList<SaleType> GetAllowedSaleTypesForADepartment(int departmentId)
    {
        var departmentAllowedSaleTypes =
            _departmentAllowableSaleTypesDataService.GetAllowableSaleTypesForDepartment(departmentId);

        return departmentAllowedSaleTypes.Select(model => new SaleType { Name = model.SaleTypeName}).ToList();
    }

    public SaleType GetSaleTypeForADepartmentSale(int departmentSaleId)
    {
        var saleTypeForDepartmentSale = _saleTypeDataService.GetSaleType(departmentSaleId);

        return new SaleType {Name = saleTypeForDepartmentSale.Name};
    }
}

Web

Web is where everything comes together as a normal MVC project. Controllers reference IRepository from core, the dependency injection ties in to the repository implementations in infrastructure and out pops a bouncing baby website.

This seems fairly straightforward to me - the concept of where the data is coming from is on the outer edge of the onion in infrastructure. The interfaces to the data reside beside the dataservices in the dataservices folder while the core repository and domain info exist in the core project.

I feel this also gives me a good way to approach implementations of UnitOfWork patterns like Entity Framework and NHibernate in the future as these libs can sit pretty in infrastructure, map out to the domain models, and everyone is happy.

As to my understanding of onion architecture, the 'dependencies' should be pushed out to the furthest layers. But then we have weird situations like in EF, where it generates a list of database-models which must then be mapped down to the domain, then those domain models must be mapped again to the viewmodel tier in the UI layer. It seemed wrong so I am looking for feedback on whether or not I am in line with the tenets of the architecture.

The monolith project isn't working for me and my coworkers and now I'm investigating alternate architectures.

closed as too broad by Robert Harvey, durron597, GlenH7, Ixrec, user40980 Aug 27 '15 at 15:15

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    You had me until your last paragraph. These kinds of questions are not answerable without more specifics about what you consider "correct." – Robert Harvey Aug 14 '15 at 18:07
  • Well, as to my understanding of onion architecture, the 'dependencies' should be pushed out to the furthest layers. But then we have weird situations like in EF, where it generates a list of database-models which must then be mapped down to the domain, then those domain models must be mapped again to the viewmodel tier in the UI layer. It seemed wrong so I was hoping for some feedback on whether or not I am in line with the tenets of the architecture. – C Bauer Aug 14 '15 at 18:15
  • The "right" approach is the one that best meets your software's functional and non-functional requirements. – Robert Harvey Aug 14 '15 at 18:47
  • The monolith project isn't working for me and my coworkers and now I'm investigating alternate architectures. If you would like to discuss the architecture by all means I would like your input, but I don't feel like this is very constructive. – C Bauer Aug 14 '15 at 19:12
  • It feels like you're trying to meet the expectations of the people who invented onion architecture, rather than trying to do the thing that best meets your needs. Some of those people may or may not be here. – Robert Harvey Aug 14 '15 at 19:15