EF6(代码优先),MVC,Unity和没有存储库的服务层

Sam*_*tar 8 asp.net asp.net-mvc entity-framework entity-framework-6

我的应用程序使用的是SQL Server 2012,EF6,MVC和Web API.

它还使用存储库和各种文件,例如:

DatabaseFactory.cs
Disposable.cs
IDatabaseFactory.cs
IRepository.cs
IUnitOfWork.cs
RepositoryBase.cs
UnitOfWork.cs
Run Code Online (Sandbox Code Playgroud)

我们已经在控制器和存储库之间使用服务层来处理一些复杂的业务逻辑.我们没有计划改变到不同的数据库,并且已经向我指出最近的想法是EF6是一个存储库,所以为什么要在它之上构建另一个存储库以及为什么我拥有上面的所有文件.

我开始认为这是一种明智的做法.

有没有人知道那些实现EF6而没有存储库的服务层的例子.我在网上的搜索揭示了许多复杂的代码示例,这些示例在任何情况下都显得过于复杂.

我的问题也是在使用服务层时,我在哪里放:

context = new EFDbContext()
Run Code Online (Sandbox Code Playgroud)

在控制器,服务层或两者?我读到我可以通过依赖注入来做到这一点.我已经将Unity用作IOC,但我不知道如何做到这一点.

Eri*_*sch 8

实体框架IS已经是工作单元模式实现以及通用存储库实现(DbContext是UoW,DbSet是通用存储库).我同意大多数应用程序在其上设置另一个UoW或Generic Repository的方式有点过分(此外,GenericRepsitory被一些人认为是反模式).

服务层可以充当具体的存储库,它具有封装特定于您的业务需求的数据逻辑的许多好处.如果使用这个,那么就没有必要在它上面构建一个存储库(除非你希望能够改变你的后端服务技术,比如从WCF到WebApi或其他......)

我会将您的所有数据访问权限放在您的服务层中.不要在控制器中进行数据访问.这会将您的数据层泄漏到您的UI层,这只是糟糕的设计.它违反了许多核心SOLID概念.

但是在大多数情况下,除了你的应用程序非常复杂并且打算在多个环境中工作之外,你不需要额外的UnitOfWork或其他层.


Sla*_*uma 6

对于ASP.NET MVC和的WebAPI建立统一,如果你安装和补充是很容易的Unity.Mvc*Unity.WebAPI*的NuGet包到项目中.(这*是一个版本号,如3或4或5.查找适合您项目的版本.例如,Unity.Mvc 5包Untity.WebAPI 5包的链接.)

本博文中介绍了这些软件包的用法.

构建块大致如下:

您构建一个统一容器并在那里注册所有依赖项,尤其是EF上下文:

private static IUnityContainer BuildContainer()
{
    var container = new UnityContainer();

    container.RegisterType<MyContext>(new HierarchicalLifetimeManager());

    container.RegisterType<IOrderService, OrderService>();
    container.RegisterType<ICustomerService, CustomerService>();
    container.RegisterType<IEmailMessenger, EmailMessenger>();
    // etc., etc.

    return container;
}
Run Code Online (Sandbox Code Playgroud)

MyContext是你的派生DbContext类.使用the注册上下文HierarchicalLifetimeManager非常重要,因为它将确保每个Web请求的新上下文将在每个请求结束时由容器实例化和处理.

如果您没有服务的接口,但只有具体的类,您可以删除上面注册接口的行.如果需要将服务注入控制器,Unity将只创建具体服务类的实例.

一旦你建立的容器,你可以在依赖解析器的MVC和的WebAPI它注册Application_Startglobal.asax:

protected void Application_Start()
{
    var container = ...BuildContainer();

    // MVC
    DependencyResolver.SetResolver(
        new Unity.MvcX.UnityDependencyResolver(container));

    // WebAPI
    GlobalConfiguration.Configuration.DependencyResolver =
        new Unity.WebApiX.UnityDependencyResolver(container);
}
Run Code Online (Sandbox Code Playgroud)

一旦DependencyResolvers的设定的框架能够实例化需要在其构造函数的参数,如果该参数可以使用注册类型来解决控制器.例如,您可以创建一个CustomerController获取CustomerServiceEmailMessenger注入的now :

public class CustomerController : Controller
{
    private readonly ICustomerService _customerService;
    private readonly IEmailMessenger _emailMessenger;

    public CustomerController(
        ICustomerService customerService,
        IEmailMessenger emailMessenger)
    {
        _customerService = customerService;
        _emailMessenger = emailMessenger;
    }

    // now you can interact with _customerService and _emailMessenger
    // in your controller actions
}
Run Code Online (Sandbox Code Playgroud)

这同样适用ApiController于WebAPI的派生.

服务可以依赖上下文实例与Entity Framework进行交互,如下所示:

public class CustomerService // : ICustomerService
{
    private readonly MyContext _myContext;

    public CustomerService(MyContext myContext)
    {
        _myContext = myContext;
    }

    // now you can interact with _myContext in your service methods
}
Run Code Online (Sandbox Code Playgroud)

当MVC/WebAPI框架实例化控制器时,它将注入已注册的服务实例并解析它们自己的依赖关系,即将注册的上下文注入服务构造函数.您将注入控制器的所有服务将在单个请求期间接收相同的上下文实例.

使用此设置,您通常不需要a context = new MyContext()或a,context.Dispose()因为IOC容器将管理上下文生命周期.


Saj*_*idQ 1

如果您没有使用存储库,那么我假设您有地方可以编写服务操作将使用的逻辑/处理。我将在该逻辑/流程类方法中创建 Context 的新实例并直接使用其方法。最后,在使用后立即将其丢弃,可能是在“使用”下。

处理方法最终会将返回/处理的数据转换为服务返回给控制器的数据/消息契约。

使数据逻辑与控制器完全分离。还要将视图模型与数据契约分开。