ASP.NET Core 2.0:为什么不提供services.AddDbContext接受接口?

时间:2017-10-09 18:52:09

标签: c# asp.net dependency-injection inversion-of-control asp.net-core-2.0

我的理解是,使用依赖注入的一个关键优势是您不会紧密绑定到类型,因此您可以稍后用较少的工作来交换您的架构的各个部分。如果是这样的话,为什么我看到这样的代码:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

...
}

我很好奇的方法是:

public static IServiceCollection AddDbContext<TContext>([NotNullAttribute] this IServiceCollection serviceCollection, [CanBeNullAttribute] Action<DbContextOptionsBuilder> optionsAction = null, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContext : DbContext;

因此,当我想访问此类型时,我将AppDbContext类类型放在构造函数中,而不是IAppDbContext接口。但为什么?这太抽象了吗?如果是这样,为什么还要用接口向容器注册任何内容呢?

2 个答案:

答案 0 :(得分:2)

  

因此,当我想访问此类型时,我将AppDbContext类类型放在构造函数中,而不是IAppDbContext接口。但为什么?这太抽象了吗?

泛型类型约束表示可以注册任何DbContextApplicationDbContext是该抽象的具体实现。添加另一个抽象并不能完成任何事情。

  

如果是这样,为什么还要用接口向容器注册任何内容?

我们没有在DI容器中注册 interfaces ,我们注册了抽象。抽象包括抽象类和接口,并且用于在使用依赖注入时解耦的目的。

在这种特殊情况下,还有其他目标。

  1. 我们希望唯一标识DbContext的特定实例。这使得在应用程序中使用多个数据库上下文变得容易。
  2. DbContext需要在正确的生命周期内注册,以便在每次请求后进行处理,并将其注册到DI容器是最简单的方法。
  3. DbContext也必须是请求的单个实例。打开多个实例可能会导致数据库同步问题甚至运行时错误。注册DI容器是获取每个请求生命周期的便捷方式。
  4. 那就是说,这是一个特例,绝不是完成工作的唯一方法 - 如果你对确保它被注册为抽象而不是具体类型的狂热,你可以随时使用{ {3}}这样做(尽管如果你实际上不需要在运行时间在数据库之间切换,我认为它已经过顶了。)

    对于应用程序的其余部分,最佳做法是注册为抽象而不是具体类型,以便轻松交换/模拟依赖项。

答案 1 :(得分:0)

要解决此问题,请使用具有 2 个泛型类型参数的重载之一,这允许您指定要注册的服务接口/类以及实现它的 DbContext 派生类。

services.AddDbContext<IMyDbContext, MyDbContext>(options =>
     options.UseSqlServer(...));