HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpModerate

Onion Architecture

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
onionarchitecturestackoverflow

Problem

After doing a whole bunch of research on Onion Architecture, I have made an attempt at implementing this in a new system that we are developing.

We have the Layers as per below:

  • Domain



  • Domain.Entities



  • Domain.Interfaces



  • Infrastructure



  • Infrastructure.Data



  • Infrastructure.DependencyResolution



  • Infrastructure.Interfaces



  • Infrastructure.Logging



  • Services



  • Services.Interfaces



  • Tests



  • Tests.Core



  • Web



  • Web.UI



Domain.Entities - All the domain models are kept here.

Base Entity

namespace Domain.Entities
 {
    public class BaseEntity
    {
        public virtual Guid ID { get; set; }

        public virtual DateTime DateCreated { get; set; }

        public virtual DateTime? DeletedDate { get; set; } 

        public override bool Equals (object obj)
        {
            if (obj == null)
                return false;  
            var t = obj as BaseEntity;  
            if (t == null)
                return false;  
            if (ID == t.ID)
                return true;  
            return false;  
        }

        public override int GetHashCode ()
        {
            int hash = GetType ().GetHashCode ();
            hash = (hash * 397) ^ ID.GetHashCode ();
            return hash;
        }
    }
}


Company Entity

namespace Domain.Entities
{
    public class Company : BaseEntity
    {
        public virtual string Name { get; set; }

        public virtual IEnumerable Users { get; set; }

        public virtual IEnumerable Branches { get; set; }

        public virtual IEnumerable Departments { get; set; }

        public class CompanyCollection : List
        {

        }
    }
}


Domain.Interfaces - I have a bunch of generic interfaces programmed here.

  • IReadRepository



  • IReadWriteRepsitory



  • IUnitOfWork



  • IWriteRepository



IReadRepository

```
namespace Domain.Interfaces
{
public interface IReadRepository where TEntity : class
{
IQueryable All ();

TEnti

Solution

Let me know if I went wrong somewhere. This is the first time I set up an application with a proper architecture.

I'm afraid there is no such thing as general "proper" architecture. Relevant architecture is the one that enables/assists developers in implementing new functionality or adjusting your solution to new requirements.

In your implementation I don't see the reason to define your own logging and repository/UoW patterns:

  • logging - there is NLog/log4net/whatever, why abstract from them? Even if you may want to switch the implementation, use Common.Logging. All these frameworks do not (and should not) use dependency injection, so having ILoggingService injected will only make your life harder.



  • repository/UnitOfWork pattern - It's a long-running discussion between those who think repository is a must, and those who see it as a redundant layer that only makes your life harder, and leads to leaked abstractions in all but most simple scenarios. I'm in the latter camp, so here are a couple of links from one of the NHibernate core devs:



  • Repository is the new Singleton



  • Refactoring toward frictionless & odorless code: The baseline



  • Refactoring toward frictionless & odorless code: Hiding global state



  • Refactoring toward frictionless & odorless code: Limiting session scope



  • Refactoring toward frictionless & odorless code: A broken home (controller)



  • Refactoring toward frictionless & odorless code: The case for the view model



  • Refactoring toward frictionless & odorless code: Getting rid of globals



  • Refactoring toward frictionless & odorless code: What about transactions?



Note that the series of articles "Refactoring toward frictionless & odorless code" actually show how you can move the transaction/session management to infrastructure level, leaving your business logic clean an tidy.

And a couple of small comments:

  • I don't see any reason to have public class CompanyCollection : List {}



  • Repository - why do you return true in Update methods? If there is a failure - throw exception, not return false.



  • IConfigService/ConfigService breaks Open/Closed principle, as would need to edit this class (add properties) whenever a new configuration parameter is needed. Classes that require configuration should expect specific configuration values in constructor instead of consuming the general IConfigService. Inject these parameters at the DI registration time. If you need a dynamic configuration which can be changed during software execution - then some sort of IConfigService can be implemented, but I would suggest to have a general T GetValue(string configName) in this case.

Context

StackExchange Code Review Q#83261, answer score: 10

Revisions (0)

No revisions yet.