ASP.NET 核心 EF 模糊构造函数
ASP.NET core EF ambiguous constructor
我使用 ASP.NET Core 和 .NET 5,最近想从本地开发更改为 Azure Web 生产模式。
我在本地使用 SQLite,一切正常,在生产环境中我想使用 Azure SQL。
然而,当我想迁移我的数据库时,我得到一个相当长的异常:
System.Exception: Could not resolve a service of type 'Server.Calendars.CalendarDataContext' for the parameter 'calendarDataContext' of method 'Configure' on type 'Server.Startup'.
---> System.InvalidOperationException: Unable to activate type 'Server.Calendars.CalendarDataContext'. The following constructors are ambiguous:
Void .ctor(Microsoft.Extensions.Configuration.IConfiguration)
Void .ctor(Microsoft.EntityFrameworkCore.DbContextOptions`1[Server.Calendars.CalendarDataContext])
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.<>c__DisplayClass7_0.<GetCallSite>b__0(Type type)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.CreateServiceAccessor(Type serviceType)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)
at Microsoft.Extensions.DependencyInjection.AutoRegisterMiddleware.<>c__DisplayClass4_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Server.IIS.Core.IISServerSetupFilter.<>c__DisplayClass2_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
我的 class CalendarDataContext .cs
Azure SQL
public class CalendarDataContext : DbContext
{
public DbSet<CalendarEntry> CalendarEntries { get; set; }
protected readonly IConfiguration Configuration;
public CalendarDataContext(IConfiguration configuration)
{
Configuration = configuration;
}
public CalendarDataContext(DbContextOptions<CalendarDataContext> options)
: base(options)
{ }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
if (!options.IsConfigured)
{
options.UseSqlServer(Configuration.GetConnectionString("CalendarDatabase"));
}
}
}
和 CalendarDataContextSqlite.cs
用于 SQLite
public class CalendarDataContextSqlite : CalendarDataContext
{
public CalendarDataContextSqlite(IConfiguration configuration) : base(configuration) { }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
if (!options.IsConfigured)
{
var databaseName = Configuration.GetConnectionString("CalendarDatabase");
var databasePath = PathHelper.DataPath(databaseName);
options.UseSqlite("Data Source=" + databasePath);
}
}
}
我认为问题出在行 CalendarDataContext(DbContextOptions<CalendarDataContext> options)
上,我需要它来为我的测试创建临时 InMemory 数据库。
如何使这个不明确的构造函数不那么不明确?
编辑:添加startup.cs
public class Startup
{
public IWebHostEnvironment Environment { get; }
public Startup(IConfiguration configuration, IWebHostEnvironment environment)
{
Environment = environment;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
if (Environment.IsProduction())
{
services.AddDbContext<CalendarDataContext>();
}
else if (Environment.IsDevelopment())
{
services.AddDbContext<CalendarDataContext, CalendarDataContextSqlite>();
}
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,
IWebHostEnvironment env,
CalendarDataContext calendarDataContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
calendarDataContext.Database.Migrate();
}
}
首先,将 IConfiguration 添加为本地成员 Startup.cs
IConfiguration Configuration;
public IWebHostEnvironment Environment { get; }
public Startup(IConfiguration configuration, IWebHostEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
然后在 Startup
中注册一个配置的 CalendarDataContext 或 CalendarDataContextSqlite
public void ConfigureServices(IServiceCollection services)
{
if (Environment.IsProduction())
{
services.AddDbContext<CalendarDataContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("CalendarDatabase"));
}
else if (Environment.IsDevelopment())
{
services.AddDbContext<CalendarDataContext, CalendarDataContextSqlite>(options => {
var databaseName = Configuration.GetConnectionString("CalendarDatabase");
var databasePath = PathHelper.DataPath(databaseName);
options.UseSqlite("Data Source=" + databasePath);
});
}
}
然后,CalendarDataContext:
public class CalendarDataContext : DbContext
{
public DbSet<CalendarEntry> CalendarEntries { get; set; }
public CalendarDataContext(DbContextOptions<CalendarDataContext> options)
: base(options) { }
protected CalendarDataContext(DbContextOptions options)
: base(options) { }
}
并且,CalendarDataContextSqlite:
public class CalendarDataContextSqlite : CalendarDataContext
{
public CalendarDataContextSqlite(DbContextOptions<CalendarDataContextSqlite> options)
: base(options) { }
}
现在,
上下文中不需要 OnConfiguring 类。
在生产中,您将有一个配置好的 CalendarDataContext 被注入到构造函数要求 CalendarDataContext 的任何地方。
对于开发,您将拥有一个已配置的 CalendarDataContextSqlite,可以在构造函数要求 CalendarDataContext 的任何地方注入。
配置的上下文也将被注入 Startup.Configure 以便您可以迁移数据库。
我使用 ASP.NET Core 和 .NET 5,最近想从本地开发更改为 Azure Web 生产模式。
我在本地使用 SQLite,一切正常,在生产环境中我想使用 Azure SQL。 然而,当我想迁移我的数据库时,我得到一个相当长的异常:
System.Exception: Could not resolve a service of type 'Server.Calendars.CalendarDataContext' for the parameter 'calendarDataContext' of method 'Configure' on type 'Server.Startup'.
---> System.InvalidOperationException: Unable to activate type 'Server.Calendars.CalendarDataContext'. The following constructors are ambiguous:
Void .ctor(Microsoft.Extensions.Configuration.IConfiguration)
Void .ctor(Microsoft.EntityFrameworkCore.DbContextOptions`1[Server.Calendars.CalendarDataContext])
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.<>c__DisplayClass7_0.<GetCallSite>b__0(Type type)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.CreateServiceAccessor(Type serviceType)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass15_0.<UseStartup>b__1(IApplicationBuilder app)
at Microsoft.Extensions.DependencyInjection.AutoRegisterMiddleware.<>c__DisplayClass4_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Server.IIS.Core.IISServerSetupFilter.<>c__DisplayClass2_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
我的 class CalendarDataContext .cs
Azure SQL
public class CalendarDataContext : DbContext
{
public DbSet<CalendarEntry> CalendarEntries { get; set; }
protected readonly IConfiguration Configuration;
public CalendarDataContext(IConfiguration configuration)
{
Configuration = configuration;
}
public CalendarDataContext(DbContextOptions<CalendarDataContext> options)
: base(options)
{ }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
if (!options.IsConfigured)
{
options.UseSqlServer(Configuration.GetConnectionString("CalendarDatabase"));
}
}
}
和 CalendarDataContextSqlite.cs
用于 SQLite
public class CalendarDataContextSqlite : CalendarDataContext
{
public CalendarDataContextSqlite(IConfiguration configuration) : base(configuration) { }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
if (!options.IsConfigured)
{
var databaseName = Configuration.GetConnectionString("CalendarDatabase");
var databasePath = PathHelper.DataPath(databaseName);
options.UseSqlite("Data Source=" + databasePath);
}
}
}
我认为问题出在行 CalendarDataContext(DbContextOptions<CalendarDataContext> options)
上,我需要它来为我的测试创建临时 InMemory 数据库。
如何使这个不明确的构造函数不那么不明确?
编辑:添加startup.cs
public class Startup
{
public IWebHostEnvironment Environment { get; }
public Startup(IConfiguration configuration, IWebHostEnvironment environment)
{
Environment = environment;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
if (Environment.IsProduction())
{
services.AddDbContext<CalendarDataContext>();
}
else if (Environment.IsDevelopment())
{
services.AddDbContext<CalendarDataContext, CalendarDataContextSqlite>();
}
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,
IWebHostEnvironment env,
CalendarDataContext calendarDataContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
calendarDataContext.Database.Migrate();
}
}
首先,将 IConfiguration 添加为本地成员 Startup.cs
IConfiguration Configuration;
public IWebHostEnvironment Environment { get; }
public Startup(IConfiguration configuration, IWebHostEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
然后在 Startup
中注册一个配置的 CalendarDataContext 或 CalendarDataContextSqlitepublic void ConfigureServices(IServiceCollection services)
{
if (Environment.IsProduction())
{
services.AddDbContext<CalendarDataContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("CalendarDatabase"));
}
else if (Environment.IsDevelopment())
{
services.AddDbContext<CalendarDataContext, CalendarDataContextSqlite>(options => {
var databaseName = Configuration.GetConnectionString("CalendarDatabase");
var databasePath = PathHelper.DataPath(databaseName);
options.UseSqlite("Data Source=" + databasePath);
});
}
}
然后,CalendarDataContext:
public class CalendarDataContext : DbContext
{
public DbSet<CalendarEntry> CalendarEntries { get; set; }
public CalendarDataContext(DbContextOptions<CalendarDataContext> options)
: base(options) { }
protected CalendarDataContext(DbContextOptions options)
: base(options) { }
}
并且,CalendarDataContextSqlite:
public class CalendarDataContextSqlite : CalendarDataContext
{
public CalendarDataContextSqlite(DbContextOptions<CalendarDataContextSqlite> options)
: base(options) { }
}
现在,
上下文中不需要 OnConfiguring 类。
在生产中,您将有一个配置好的 CalendarDataContext 被注入到构造函数要求 CalendarDataContext 的任何地方。
对于开发,您将拥有一个已配置的 CalendarDataContextSqlite,可以在构造函数要求 CalendarDataContext 的任何地方注入。
配置的上下文也将被注入 Startup.Configure 以便您可以迁移数据库。