5

I'm creating a project with Asp.net MVC 5, Web Api 2, and Entity Framework. I'm designing it with an Onion architecture, so I have a DAL, Service and UI layers.

My DAL layer contains a UnitOfWork and Repositories, my Service layer contains services for business cases.

But I have the following questions:

  1. Where do I use unit of work save (or commit) method?, in Services layer or in UI layer? if I use it in Services layer how do I deal with cases that span multiple Services?

  2. I'm using DTOs for webapi operations, should the Services layer return DTOs or the mapping should be done in the UI layer?

  3. Should DTOs be in a separate project or in the UI project? If they are in a separate project should I use MVC attributes for validation?

Escobar5
  • 3,941
  • 8
  • 39
  • 62
  • 1
    Repositories on top of EF are bad, mkaaaay? – Inspector Squirrel Mar 05 '15 at 15:12
  • I don't think the OP is specifically saying thats how it is setup. – Charlie Brown Mar 05 '15 at 15:15
  • 6
    @Sippy If you've ever had a manager/architect change his/her mind mid-project about your data access technology, then you know the value of having an abstraction layer over your data access framework. So, no, repositories on top of EF (or any ORM) are not bad if they encapsulate the ORM. – Brian Driscoll Mar 05 '15 at 15:20
  • 2
    @Sippy It's not bad, it's not necessary most of the times, but I do need to abstract all Entity Framework implementation, as BrianDriscoll says there could be data access changes eventually. – Escobar5 Mar 05 '15 at 15:23
  • 1
    @BrianDriscoll Agreed. I often create the same thing so I can swap between Mongodb and SQL Azure. I think Sippy may have been referring to the bad practice of repository per type pattern. – Charlie Brown Mar 05 '15 at 15:23
  • 1
    Perhaps a hint towards question 1, in DDD (domain-driven design) you distinguish between *application services* and *domain services*. The *application services* would represent individual use cases, while the *domain services* express operations on your domain model. In this space, the unit of work would typically be managed in the *application service* which could compose multiple *domain services* to implement a given use case in your application. – PermaFrost Mar 05 '15 at 15:26
  • I tend to find every time I say something vague or stupid I learn something here. – Inspector Squirrel Mar 05 '15 at 15:27
  • @PermaFrost thanks, I would explore more on that – Escobar5 Mar 05 '15 at 15:28

1 Answers1

6

Your unit of work should exist in your service layer. Each call to the service contains a business transaction inside a single unit of work.

    public ServiceResponse<Patient> Save(Patient patient, string userName)
    {
        Func<Patient> func = delegate
        {
            Authorize(patient, userName);
            Validate(patient, new PatientValidator());

            using (var context = _contextFactory())
            {
                return context.Save(patient, userName);
            }
        };
        return this.Execute(func);
    }

The services layer should return your business entities, any mapping for the purpose of network communication/json formatting should be done in web api. This allows maximum reuse of your services.

If by DTO's you are referring to the objects you use for across the wire/json serialization, then they should stay in the same project as the Web Api. That may or may not be the same project where you have your UI. If your using Web Api, I recommend using a validation library like FluentValidation.

An example of Onion architecture https://github.com/carbonrobot/FullStackEF using C#, EF, Web Api

Charlie Brown
  • 2,817
  • 2
  • 20
  • 31
  • Thanks, one more question, why do you wrap all the save function in a delegate? – Escobar5 Mar 05 '15 at 15:25
  • 2
    So I can have one try...catch for all methods and return a standard formatted response object. It makes the calls from the client like WebApi much cleaner and you can handle the response with common methods. In that try...catch can be logging as well. Since all operations happen inside that method, all errors will be caught, logged, and handled. – Charlie Brown Mar 05 '15 at 15:31
  • I would add that your business objects are not the same thing as your Entity Framework models. http://blog.8thlight.com/uncle-bob/2013/10/01/Dance-You-Imps.html – Chris McKenzie Mar 06 '15 at 16:50
  • 1
    @ChrisMcKenzie I would disagree with that. Having separate models is not neccessary b/c you can model your domain any way that you want, and EF will take care of the mapping details. There should be no impedence mismatch. – Charlie Brown Mar 06 '15 at 17:05