【问题标题】:N-Tier Architecture with Service Layer, Business Layer, and Entity Framework具有服务层、业务层和实体框架的 N 层架构
【发布时间】:2023-03-27 07:12:01
【问题描述】:

只是想在我构建应用程序的方式上获得一些反馈/帮助。我当前的解决方案结构如下所示:

  • UI(实际 MVC 应用程序)
  • 核心(仅限控制器和视图模型)
  • 服务
  • BLL
  • 数据(实体框架 DbContext,映射到域对象)
  • 域(简单 POCO 对象)
  • 接口

其他东西

  • Ninject 将 DbContext 注入控制器(每个请求)
  • AutoMapper 将域对象映射到 ViewModel

所有程序集都有一个对 Interfaces 项目的引用,顾名思义,它只不过是简单的接口(即 IDbContext、IRepository 等)。

“服务”项目将其他所有内容“联系”在一起。它是唯一直接引用数据访问层(实体框架)的程序集。

我在下面提供了一些代码:

Controller 的示例如下所示:

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));
        }
        ...

UserService 类:

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();
        }
        ...

最后是业务层类:

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();
        }
        ...

我正在寻找一些反馈/改进方法。我注意到对于基本任务,我的服务层方法将与业务层方法完全相同(即“通过”功能)。我希望这种抽象有助于更复杂的任务,这些任务可能需要调用多个业务层方法。在服务层中包含业务逻辑会更好吗?

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-3 entity-framework asp.net-mvc-2


    【解决方案1】:

    快速浏览一下,我认为您的服务和控制器/核心层不应该以这种方式将数据库上下文注入其中。他们实际上并不直接依赖它,并且以这种方式进行操作会导致一些不理想的耦合。核心层应该注入用户服务,用户服务和 BLL 应该注入存储库。存储库应具有由您的 DI 框架注入的 dbcontext,而不是作为依赖项传入。

    【讨论】:

    • @stephen.vakil - 你能给出如何做的代码示例吗?我想要实现的是,在控制器中,我想使用 DI 创建 biz 对象的实例。在 biz 层内,我想使用 DI 创建 DAL 的实例。我如何在 ASPCore 中做到这一点?如果我在 startup.cs 中添加上下文对象,它是否可用于所有类,即使该类位于不同的项目中(如用于 biz 逻辑的单独项目)。请帮忙,谢谢。
    • @stephen.vakil 你能给我一些代码示例来实现你的评论吗?谢谢。
    【解决方案2】:

    为什么直接在服务中创建依赖时使用依赖注入?

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

    顺便说一句。当它们实际上什么都不做时,为什么要使用这么多层?您的示例代码只是表明,直接在控制器中使用上下文会产生相同的结果,而无需三个无用的包装层。这可能只是您的示例的问题,但每一层都应该带来一些额外的逻辑。如果您只是使用它来调用较低层的某些内容,那么您很可能会过度构建您的代码。这称为洋葱架构。这也是为什么在需要时添加层并不是一个坏习惯的原因 - 而不是预先添加。

    【讨论】:

    • 但大多数应用程序都遵循相同的架构模式。他们只是包装了下面的层,示例业务层只是包装了数据访问层并检查了一些业务条件的结果。但是我对 Entity Framework DB first 方法感到困惑,因为它生成 POCO(域)和数据访问层。那么我们适合这个 .edmx 文件的哪一层呢?
    【解决方案3】:

    请查看:http://www.primaryobjects.com/CMS/Article122.aspx EF 存储库模式 + 工作单元模式。至于您的其他层,它实际上取决于应用程序及其需要完成的任务。请提供有关您尝试执行的操作的更多详细信息。

    【讨论】:

      【解决方案4】:

      在组织项目和层设计方面的一些改进可以通过专注于使域对象正确来完成。

      您说您有简单的 POCO 对象作为域,但域对象应该是具有业务所有“状态和行为”的对象。这意味着您不需要将 BLL 和域程序集分开。 定义域对象后,可以使用 EF 创建上下文和实体类(它们不是域类,除非与域对象相比没有其他行为,但它们仍然不同可能有利于未来的需求)。

      另一个小问题是,我认为将接口分布在域和服务层中对于任何人来说都更好地理解每个层。

      【讨论】:

        猜你喜欢
        • 2014-04-13
        • 2017-07-05
        • 1970-01-01
        • 1970-01-01
        • 2012-03-04
        • 2012-03-08
        • 2012-12-17
        • 1970-01-01
        • 2023-03-25
        相关资源
        最近更新 更多