IReadOnlyDictionary`2 是接口,不能构造

Sip*_*nya 0 unity-container entity-framework-core

调用 API 时出现以下异常:

InvalidOperationException - The current type, System.Collections.Generic.IReadOnlyDictionary`2[System.Type,Microsoft.EntityFrameworkCore.Infrastructure.IDbContextOptionsExtension], is an interface and cannot be constructed. Are you missing a type mapping?

这是完整的错误:

{
  "Message": "An error has occurred.",
  "ExceptionMessage": "An error occurred when trying to create a controller of type 'TechnicianController'. Make sure that the controller has a parameterless public constructor.",
  "ExceptionType": "System.InvalidOperationException",
  "StackTrace": "   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
  "InnerException": {
    "Message": "An error has occurred.",
    "ExceptionMessage": "Resolution of the dependency failed, type = \"BackendApp.Controllers.TechnicianController\", name = \"(none)\".\r\nException occurred while: while resolving.\r\nException is: InvalidOperationException - The current type, System.Collections.Generic.IReadOnlyDictionary`2[System.Type,Microsoft.EntityFrameworkCore.Infrastructure.IDbContextOptionsExtension], is an interface and cannot be constructed. Are you missing a type mapping?\r\n-----------------------------------------------\r\nAt the time of the exception, the container was:\r\n\r\n  Resolving BackendApp.Controllers.TechnicianController,(none)\r\n  Resolving parameter \"helper\" of constructor BackendApp.Controllers.TechnicianController(Events_Tenant.Common.Core.Interfaces.ITechnicianRepository technicianRepository, Events_Tenant.Common.Helpers.IHelper helper)\r\n    Resolving Events_Tenant.Common.Helpers.Helper,(none) (mapped from Events_Tenant.Common.Helpers.IHelper, (none))\r\n    Resolving parameter \"tenantsRepository\" of constructor Events_Tenant.Common.Helpers.Helper(Events_Tenant.Common.Core.Interfaces.ICountryRepository countryRepository, Events_Tenant.Common.Core.Interfaces.ITenantsRepository tenantsRepository, Events_Tenant.Common.Core.Interfaces.IProviderRepository venuesRepository, Events_Tenant.Common.Core.Interfaces.IVenueTypesRepository venueTypesRepository)\r\n      Resolving Events_Tenant.Common.Core.Repositories.TenantsRepository,(none) (mapped from Events_Tenant.Common.Core.Interfaces.ITenantsRepository, (none))\r\n      Resolving parameter \"catalogDbContext\" of constructor Events_Tenant.Common.Core.Repositories.TenantsRepository(Events_TenantUserApp.EF.CatalogDB.CatalogDbContext catalogDbContext)\r\n        Resolving Events_TenantUserApp.EF.CatalogDB.CatalogDbContext,(none)\r\n        Resolving parameter \"options\" of constructor Events_TenantUserApp.EF.CatalogDB.CatalogDbContext(Microsoft.EntityFrameworkCore.DbContextOptions`1[[Events_TenantUserApp.EF.CatalogDB.CatalogDbContext, Events-TenantUserApp.EF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] options)\r\n          Resolving Microsoft.EntityFrameworkCore.DbContextOptions`1[Events_TenantUserApp.EF.CatalogDB.CatalogDbContext],(none)\r\n          Resolving parameter \"extensions\" of constructor Microsoft.EntityFrameworkCore.DbContextOptions`1[[Events_TenantUserApp.EF.CatalogDB.CatalogDbContext, Events-TenantUserApp.EF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]](System.Collections.Generic.IReadOnlyDictionary`2[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[Microsoft.EntityFrameworkCore.Infrastructure.IDbContextOptionsExtension, Microsoft.EntityFrameworkCore, Version=1.1.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]] extensions)\r\n            Resolving System.Collections.Generic.IReadOnlyDictionary`2[System.Type,Microsoft.EntityFrameworkCore.Infrastructure.IDbContextOptionsExtension],(none)\r\n",
    "ExceptionType": "Microsoft.Practices.Unity.ResolutionFailedException",
    "StackTrace": "   at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides)\r\n   at Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides)\r\n   at Microsoft.Practices.Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides)\r\n   at Unity.WebApi.UnityDependencyScope.GetService(Type serviceType)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)",
    "InnerException": {
      "Message": "An error has occurred.",
      "ExceptionMessage": "The current type, System.Collections.Generic.IReadOnlyDictionary`2[System.Type,Microsoft.EntityFrameworkCore.Infrastructure.IDbContextOptionsExtension], is an interface and cannot be constructed. Are you missing a type mapping?",
      "ExceptionType": "System.InvalidOperationException",
      "StackTrace": "   at Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.ThrowForAttemptingToConstructInterface(IBuilderContext context)\r\n   at lambda_method(Closure , IBuilderContext )\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey)\r\n   at Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context)\r\n   at lambda_method(Closure , IBuilderContext )\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey)\r\n   at Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context)\r\n   at lambda_method(Closure , IBuilderContext )\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey)\r\n   at Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context)\r\n   at lambda_method(Closure , IBuilderContext )\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey)\r\n   at Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context)\r\n   at lambda_method(Closure , IBuilderContext )\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey)\r\n   at Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context)\r\n   at lambda_method(Closure , IBuilderContext )\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)\r\n   at Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides)"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

任何想法如何解决这个问题?

Ran*_*ica 5

问题是 Unity 正在尝试解决CatalogDbContext哪个是DbContext. 默认情况下,Unity 会选择参数最多的构造函数。在这种情况下,构造函数是:

public DbContext(DbContextOptions options);
Run Code Online (Sandbox Code Playgroud)

这需要一个DbContextOptions对象,因此 Unity 将再次选择一个构造函数并尝试实例化任何依赖项,这DbContextOptions恰好是IReadOnlyDictionary<Type, IDbContextOptionsExtension>. 不幸的是 Unity 不知道如何实例化接口的具体实例IReadOnlyDictionary<Type, IDbContextOptionsExtension>

当控制器无法实例化时,WebApi 会提供“确保控制器具有无参数的公共构造函数”消息,这有点牵强附会,因为真正发生的情况是非无参数构造函数失败,而您可能没有想要提供一个无参数的构造函数。

以上描述了正在发生的事情。

之所以会出现这种情况,是因为控制器所需的依赖项尚未使用 Unity 进行配置。

无法使用任何细节(除了“配置容器”)给出如何解决问题,因为没有代码显示依赖项是如何连接的。我猜你可能不想使用DbContextOptions构造函数重载DbContext- 也许指定 Unity 使用默认构造函数DbContext就足以解决问题?

根据下面的评论,(至少)有几种方法可以解决填充连接字符串的问题。

选项 1 - 连接字符串

注入连接字符串并在 DbContext 中使用它:

public class CatalogDbContext  : DbContext
{
    private readonly string connectionString;

    public CatalogDbContext (string connectionString)
    {
        this.connectionString = connectionString;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(this.connectionString);
    }
}

var container = new UnityContainer();
container.RegisterType<CatalogDbContext>(new InjectionConstructor(GetCatalogConnectionString()));
Run Code Online (Sandbox Code Playgroud)

选项 2 - 选项生成器

public class CatalogDbContext  : DbContext
{
    public CatalogDbContext(DbContextOptions options)
        : base(options)
    {
    }
}

var container = new UnityContainer();

var contextOptions = new DbContextOptionsBuilder()
    .UseSqlServer(GetCatalogConnectionString())
    .Options;

container.RegisterType<CatalogDbContext>(new InjectionConstructor(contextOptions));
Run Code Online (Sandbox Code Playgroud)