Domanda

I am having trouble connecting the dots from many posts I have read (and coming to realize I probably need to buy Eric Evans book instead of relying on loads of internet material) I am trying to adhere to domain driven design, but I am having trouble on the best method to communication from the presentation layer to my domain before saving my data back to the database. To keep it simple, right now I have a user class that can have a list of jobs. When a user opens the application their active directory information is queried and this class is populated with their data as long as they have the app open. Then, the user can edit an existing job if they own it or create a new one. I started creating a service class that uses my UnitOfWork class thinking this would act as my communication, but that is where I am stuck.

Current Setup:

DAL - EF 6 generated POCOs and DbContext, Repository, Unit of Work

Domain - Entities, Repository & Unit of Work interface, domain interface services I refer to in this post?

Presentation - MVC (intranet), concrete service?

Questions:

  1. Is the service class the best class to implement for this type of communication (and for creating new instances of my domain classes (e.g. a method to create a new job)? I realize I could use a factory pattern, but I did not want to get too complicated yet)? Would the service reside in the domain layer or do I create a separate project for an application layer? Then would the interface go in the domain layer and the concrete implementation go into the application layer? I feel like that could be over complicating the app. Also, is the service WCF or can I just create my own classes?

  2. How do I map the ViewModel in my MVC layer back to the domain using this service (if that is the best way) without the presentation layer leaking in to the service? I've read up on DTOs, but then is that overkill in the service layer? Or is it okay to expose my domain entities as the ViewModel? I must be thinking about this incorrectly. I cannot picture how this interaction would look in a controller without some leakage. Sorry for all the questions, and thanks.

    public class User
    {
        public int Id{ get; set; }
        public string WindowsId{ get; private set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string FullName { get { return FirstName + " " + LastName; } }
        public string Email { get; set; }
        public string WorkPhone { get; set; }
    
        public List<Job> Jobs { get; private set; }
    
        public void AddJob(Job job)
        {
            if(job == null)
            throw new Exception("Job is null");
    
            var newJob = new Job(this) //tell the job that this user is creating the job
            {
                Description = job.Description,
                DueDate = job.DueDate,
                Name = job.Name,
                Reason = job.Reason
            };
    
        Jobs.Add(newJob);
        }
    
    }
    

UPDATE: My Solution

I ended up taking a little bit from everybody's answers.

@granadaCoder - I used my EF POCOs as the classes to pass around as DTOs because most of the time that is the data I was displaying to the user in my ViewModel. So it allowed me to use the DTOs as the ViewModels

@ChrisPratt - you are correct. Doing this prevented a lot of extra work. All I did was create a service that had all the queries I needed. And if I ever had to change the EF it would still not bother my other layers. All I would have to do is create the repository and UOW

@MilivojMilani - I did have repeating logic in the controller so the service layer kept me aligned with the DRY principal

@Yorro - I used your points and references to reinforce the design since I was still unsure about the service layer setup. Since this is a smaller project, I setup another folder with my service and interface that I created, no WCF

È stato utile?

Soluzione

Stay away from the Repository/Unit of Work pattern if you're using Entity Framework. EF is itself an implementation of this pattern. If you want to abstract Entity Framework, then implement a service pattern that returns fully-baked data exactly how you need it. It's best illustrated with an example:

With EF/Repository

IQueryable<Post> posts = db.Posts.Where(m => m.BlogId == blog.Id && m.Status == PostStatuses.Published && m.PublishDate <= DateTime.Now).OrderBy(m => m.PublishDate);

With Service

List<Post> posts = service.GetPublishedPostsForBlog(blog);

The two key differences here are:

  1. You're returning data already pulled from the database with the service; a repository/EF will return a queryable that may or may not have been executed against the database yet.

  2. All your logic goes into the service method with a service. Whereas, with a repository/EF you build your query in place.

That said, don't get so hung up on the layers of your application. It's not about how many layers you have and what you call them, but rather about abstracting logic away from pieces of your application that shouldn't need to know how to construct that logic. A controller action to return a list of published blog posts, for example, shouldn't need to know what qualifies a post as being "published". That's domain logic that should go somewhere else (like the service method that returns this dataset). The idea is simply to follow the single-responsibility principle: a class/method/etc. should do one thing and do it well. Your controller action should only concern itself with returning the view (and doing the bare minimal amount of work to fetch what that view needs).

As far as mapping goes, the term explains exactly what you do, so I'm not sure of the confusion here. If you want to map Post to PostViewModel for example:

var model = new PostViewModel
{
    Title = post.Title,
    Content = post.Content,
    ...
}

Or with a list of objects, you can employ LINQ:

var model = posts.Select(m => new PostViewModel
{
    Title = m.Title,
    Content = m.Content,
    ...
}

If you question is simply: how do I do this easier? Then, you can look into a third-party mapping library like AutoMapper.

Altri suggerimenti

The Service Layer

The service layer serves as the application's boundery, it encapsulates your domain entities, in other words, it protects your domain. All communication to the domain must go through the service layer. But the Domain Model (at its purest form) should not have any reference to the Service Layer or any other infrastructure layers (DAL/Presentation).

enter image description here http://martinfowler.com/eaaCatalog/serviceLayer.html

Would the service reside in the domain layer or do I create a separate project for an application layer? Then would the interface go in the domain layer and the concrete implementation go into the application layer?

If you are already segregating your layers into their own projects, then the service layer should have its own project.

Is the service WCF or can I just create my own classes?

The simplest service is just a class, see an example of a service layer straight from Microsoft Tutorials: http://www.asp.net/mvc/tutorials/older-versions/models-(data)/validating-with-a-service-layer-cs

Here is another example on how to refactor an MVC using a service layer http://www.arrangeactassert.com/asp-net-mvc-controller-best-practices-%E2%80%93-skinny-controllers/

How do I map the ViewModel in my MVC layer back to the domain using this service (if that is the best way) without the presentation layer leaking in to the service? I've read up on DTOs, but then is that overkill in the service layer? Or is it okay to expose my domain entities as the ViewModel? I must be thinking about this incorrectly. I cannot picture how this interaction would look in a controller without some leakage.

This question is another topic altogether. DTO is a good way for the service layer to communicate with outside layers.

Your questions are very good, and in fact it is the most frequently asked.

  • Is it overkill to use DTO in the Service Layer?
  • Is it okay to expose the guts(domain) of my application to outside layers?
  • How would the service layer interact with outside layers without leakages?
  • Where should the DTO reside?

I've answered the same questions here: https://stackoverflow.com/a/21569720/1027250

This image provides overhead view on how a service layer fits into a multi-layer architecture. Note that this is not absolute or perfect for every project, you should approach a pattern depending on the need of the project. Additional layers adds complexity, it is a long term investment on a long term project with a large team.

1.If you're using MVC you may or may not have a service layer. Ask yourself a following question - do you use this functionality on more than one place? If the answer is yes - use the application service (not domain service). If no, put it in the MVC controller itself.

Don't put any hydration logic in the domain layer. Domain layer in DDD shouldn't know anything about persistence. Controller/Application service should fetch the data using repository interfaces and save the data using same interfaces. In your case, you should be fetching and saving only the User class, while Job should be below it as aggregate root child. Using UnitOfWork and Repository is perfectly fine. Here is a good article on it =>

http://www.asp.net/mvc/tutorials/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

2.It is perfectly normal to, in some cases, use domain object as ViewModel class. In other more complex cases, you will have to map properties manually. Mapping is usually best done as extension method on ViewModel class. Some use AutoMapper though I'm against using it when mapping presentation classes to domain. All this mapping work should NOT be done in domain layer. You might have a lot of viewmodel classes and it would bloat the domain layer with presentation layer logic.

Hope it helped.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top