如何使用.Net Core 2.1通过依赖项注入配置DbContext?

时间:2018-12-05 12:46:17

标签: c# asp.net-core dependency-injection asp.net-core-mvc asp.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:没有数据库提供者   为此DbContext配置。可以通过以下方式配置提供程序   重写DbContext.OnConfiguring方法或通过使用AddDbContext   在应用程序服务提供商上。如果使用AddDbContext,则   还要确保您的DbContext类型接受   DbContextOptions对象在其构造函数中并将其传递给   DbContext的基本构造函数。在   Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider   scopedProvider,IDbContextOptions contextOptions,DbContext上下文)
  在   Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()   在Microsoft.EntityFrameworkCore.DbContext.get_ChangeTracker()处   Microsoft.Extensions.Internal.PropertyHelper.CallNullSafePropertyGetter [TDeclaringType,TValue](Func`2   getter,对象目标)在   Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.BindModelCoreAsync(ModelBindingContext   bindingContext)在   Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext   actionContext,IModelBinder modelBinder,IValueProvider valueProvider,   ParameterDescriptor参数,ModelMetadata元数据,对象值)
  在   Microsoft.AspNetCore.Mvc.Internal.ControllerBinderDelegateProvider。<> c__DisplayClass0_0。 d.MoveNext()

从上下文中删除空构造函数时发生异常

  

System.InvalidOperationException:无法创建类型的实例   'Skillcheck.Models.TicketsystemContext'。模型绑定的复杂类型   不得为抽象或值类型,并且必须具有无参数   构造函数。另外,给'c'参数一个非空的默认值   值。在   Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.CreateModel(ModelBindingContext   bindingContext)在   Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.BindModelCoreAsync(ModelBindingContext   bindingContext)在   Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext   actionContext,IModelBinder modelBinder,IValueProvider valueProvider,   ParameterDescriptor参数,ModelMetadata元数据,对象值)
  在   Microsoft.AspNetCore.Mvc.Internal.ControllerBinderDelegateProvider。<> c__DisplayClass0_0。 d.MoveNext()

    服务中的
  • cs不为null,并从中读取字符串 appsettings.json成功
  • 在services.AddDbContext之后,上下文位于ServiceCollection中 它不会抛出
  • 使用通用DbContextOptions代替 上下文构造函数中的DbContextOptions 不起作用
  • 明确添加IHttpContextAccessor也不起作用

我通过重写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时有效,但在注入时进行配置时无效。

2 个答案:

答案 0 :(得分:4)

好吧,第一个错误是由于包含无参数的构造函数。那不应该存在。依赖注入将始终选择要满足的依赖关系最少的构造函数,这将是无参数的,但是您需要 Value注入。

第二个错误表示您将上下文作为参数包含在操作方法中。我不确定为什么要这么做,但不应该这么做。您的上下文应注入控制器本身,并在此上设置为ivar,以便您的操作可以利用ivar。您 可以在参数前加上DbContextOptions<TContext>,以指示modelbinder应该忽略它,而应该从服务集合中注入它,但是方法注入是一种反模式。

答案 1 :(得分:1)

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