如何使用 .Net Core 2.1 配置具有依赖注入的 DbContext?

How do I configure a DbContext with dependency injection with .Net Core 2.1?

服务

public void ConfigureServices(IServiceCollection services)
{
    string cs = Configuration.GetConnectionString("Skillcheck"); 
    services.AddDbContext<TicketsystemContext>(options => options.UseSqlServer(cs));
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

上下文

public TicketsystemContext()
{
}

public TicketsystemContext(DbContextOptions<TicketsystemContext> options)
    : base(options)
{
}

// ... rest of the context

异常

System.InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext. at Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, IDbContextOptions contextOptions, DbContext context)
at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() at Microsoft.EntityFrameworkCore.DbContext.get_ChangeTracker() at Microsoft.Extensions.Internal.PropertyHelper.CallNullSafePropertyGetter[TDeclaringType,TValue](Func`2 getter, Object target) at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.BindModelCoreAsync(ModelBindingContext bindingContext) at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)
at Microsoft.AspNetCore.Mvc.Internal.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<g__Bind|0>d.MoveNext()

当我从上下文中删除空构造函数时出现异常

System.InvalidOperationException: Could not create an instance of type 'Skillcheck.Models.TicketsystemContext'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the 'c' parameter a non-null default value. at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.CreateModel(ModelBindingContext bindingContext) at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.BindModelCoreAsync(ModelBindingContext bindingContext) at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)
at Microsoft.AspNetCore.Mvc.Internal.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<g__Bind|0>d.MoveNext()

我通过覆盖 OnConfiguring 暂时解决了它,但我想了解它为什么不起作用。 我在 VS2017 上使用 .Net Core 2.1。

解决方案

错误是

private TicketsystemContext _c;

public HomeController(TicketsystemContext c)
{
    _c = c;
}

public IActionResult Index()
{
    return View(_c.User.First());
}

我用过

public IActionResult Index(TicketsystemContext c)
{
    return View(c.User.First());
}

在覆盖 OnConfiguring 时有效,但在注入时配置时无效。

好吧,第一个错误是由于包含了无参数构造函数。那不应该存在。依赖注入总是会选择满足最少依赖的构造函数,这将是无参数的,但是你 need DbContextOptions<TContext> injected.

第二个错误表明您将上下文作为参数包含在操作方法中。我不确定你为什么这样做,但你不应该这样做。你的上下文应该被注入到控制器本身并设置为一个ivar,这样你的动作就可以利用这个ivar。您 可能 可以在参数前面加上 [FromServices] 以指示模型绑定器应该忽略它并且应该从服务集合中注入它,而不是,但是方法注入是一种反-模式。

您正在将 TicketsystemContext 直接注入到 Index 操作中。

一般来说,你应该像下面这样将 TicketsystemContext 作为依赖项注入到构造函数中:

public class HomeController : Controller
{
    private readonly TicketsystemContext context;
    public HomeController(TicketsystemContext context)
    {
        this.context = context;
    }
    public IActionResult Index()
    {
        return View(context.User.First());
    }
}

如果您希望将 TicketsystemContext 注入到操作中,您可以通过以下代码尝试@Chris Pratt 的建议:

public IActionResult Index([FromServices]TicketsystemContext c)
{
    return View(c.User.First());
}