简体   繁体   中英

N-Tier Architecture with Service Layer, Business Layer, and Entity Framework

Just wanted some feedback/help with the way I'm architecturing my application. My current solution structure looks something like this:

  • UI (Actual MVC application)
  • Core (only Controllers & ViewModels)
  • Services
  • BLL
  • Data (Entity framework DbContext, mapped to Domain objects)
  • Domain (Simple POCO objects)
  • Interfaces

Other stuff

  • Ninject to inject DbContext into Controller (per request)
  • AutoMapper to map Domain objects to ViewModel

All assemblies have a reference to the Interfaces project, which, as the name suggests, is nothing more than simple interfaces (ie IDbContext, IRepository, etc).

The Services project "ties" together everything else. It is the only assembly which has a direct reference to the Data access layer (Entity Framework).

I've provided some code below:

An example of a Controller looks like this:

namespace Core.Controllers
{
    public class HomeController : Controller
    {
        private IDbContext dbContext;

        public HomeController(IDbContext dbContext)
        {
            this.dbContext = dbContext;
        }

        public ActionResult Users()
        {
            UserService userService = new UserService(dbContext);
            var users = userService.GetAllUsers();
            return View(Mapper.Map<IEnumerable<UserListViewModel>>(users));
        }
        ...

The UserService class:

namespace Services
{
    public class UserService
    {
        private readonly IDbContext dbContext;

        public UserService(IDbContext dbContext)
        {
            this.dbContext = dbContext;
        }

        public IEnumerable<User> GetAllUsers()
        {
            IRepository<User> userRepository = new Repository<User>(dbContext);
            UserBLL userBLL = new UserBLL(userRepository);
            return userBLL.GetAllUsers();
        }
        ...

Finally, the business layer class:

namespace BLL
{
    public class UserBLL
    {
        private readonly IRepository<User> userRepository;

        public UserBLL(IRepository<User> userRepository)
        {
            this.userRepository = userRepository;
        }

        public IEnumerable<User> GetAllUsers()
        {
            return userRepository.Get();
        }
        ...

I'm looking for some feedback/ways to improve. I notice that for basic tasks, my service layer methods will be exactly the same as the business layer methods (ie "pass through" functions). What I'm hoping is that this abstraction will be helpful for more complex tasks which may require calls to multiple business layer methods. Would it just be better to include business logic in the service layer?

From a quick glance, I don't think your service and controller/core layer should have the db context injected into them in this manner. They don't actually directly depend on it and doing it in this manner causes some coupling that is not ideal. The core layer should have the user service injected and the user service and BLL should have the repository injected. The repository should have the dbcontext injected by your DI framework and not passed in as a dependency.

Why are you using dependency injection when you are creating dependencies directly in the service?

public IEnumerable<User> GetAllUsers()
{
    IRepository<User> userRepository = new Repository<User>(dbContext);
    UserBLL userBLL = new UserBLL(userRepository);
    return userBLL.GetAllUsers();
}

Btw. why are you using so many layers when they actually do nothing? Your example code just shows that using context in controller directly would produce the same result without three wrapper useless layers. It may be just problem of your example but each layer should bring some added logic. If you just use it to call something on lower layer you are most probably overarchitecting your code. This is called onion architecture. That is also a reason why it is not a bad practice to add layer once you need it - not upfront.

Please check this out: http://www.primaryobjects.com/CMS/Article122.aspx EF Repository pattern + Unit Of Work pattern. As for your other layers, it really depends on the application and what it needs to accomplish. Please provide more details on what you're trying to do.

Some of the improvements in organizing projects and design of the layers can be done by focusing on getting the Domain objects correct.

You said you have simple POCO objects as Domain, but the Domain objects should be the one having all the "State and behaviour" of the business. That means you do not need to have BLL and Domain assemblies separate. Once the Domain objects are defined, EF can be used to create the context and entity classes (which are not Domain classes unless there is no additional behaviour compared to your domain object, but still having them different might be good for future requirements).

Other minor point is, I think having interfaces distributed within the Domain and Services layer is better in terms of anyone understanding each layer in isolation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM