Asp.net core Azure函数使用了错误的DbContext构造函数
我有一个现有的EF Core 2.2Asp.net core Azure函数使用了错误的DbContext构造函数,asp.net-core,entity-framework-core,azure-functions,Asp.net Core,Entity Framework Core,Azure Functions,我有一个现有的EF Core 2.2DbContext,它在ASPNET核心应用程序和LinqPad中都能正常工作。现在我正试图将其添加到Azure函数中。在ASPNET和Azure函数中,我都使用依赖项注入 DbContext类有三个构造函数-一个空构造函数,一个接受连接字符串,另一个接受DbOptionsBuilder实例。ASPNET核心应用程序似乎调用了获取DbOptionsBuilder实例的应用程序,而LinqPad使用了获取连接字符串的应用程序。正如我所说,这两种方法都很好 Azu
DbContext
,它在ASPNET核心应用程序和LinqPad中都能正常工作。现在我正试图将其添加到Azure函数中。在ASPNET和Azure函数中,我都使用依赖项注入
DbContext
类有三个构造函数-一个空构造函数,一个接受连接字符串,另一个接受DbOptionsBuilder
实例。ASPNET核心应用程序似乎调用了获取DbOptionsBuilder
实例的应用程序,而LinqPad使用了获取连接字符串的应用程序。正如我所说,这两种方法都很好
Azure函数应用程序尝试使用接受字符串的函数,但它传递的是null而不是值。这会导致一个错误,即未配置提供程序
通过删除带字符串的构造函数,我可以强制函数应用程序使用DbOptionsBuilder
构造函数。当我这样做时,功能应用程序工作正常。但是,如果我这样做,我就不能再在LinqPad中使用上下文
我的问题是,首先,我如何使Azure函数调用适当的构造函数而不删除其他构造函数?其次,也不太重要的是,为什么ASPNET运行时和Azure函数运行时的行为不同
编辑
此时我只在本地运行AZ函数,因此它正在从“local.settings.json”文件读取连接字符串。这部分工作正常
下面是函数项目的Startup.Configure方法
public class Startup : FunctionsStartup
{
/// <summary>
/// This method gets called by the runtime. Use this method to add services to the DI container.
/// </summary>
/// <param name="builder">The function host builder</param>
public override void Configure(IFunctionsHostBuilder builder)
{
// Add database context
string env = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT");
string connectionString = Environment.GetEnvironmentVariable($"ConnectionStrings:{env}");
builder.Services.AddDbContext<FullContext>(x => x.UseSqlServer(connectionString), ServiceLifetime.Transient);
}
}
编辑3
查看链接后@Jack Jia建议我尝试以下方法
首先,我创建自己的DbContextOptionsBuilder
实例,并指定提供程序和连接字符串
var options = new DbContextOptionsBuilder<FullContext>();
options.UseSqlServer(connectionString);
但这似乎是可行的:
builder.Services.AddTransient<FullContext>(x => new FullContext(options.Options));
builder.Services.AddTransient(x=>newfullcontext(options.options));
假设我正确理解了文档,那么这两个调用都应该强制DI服务使用构造函数,并使用DbContextOptions
参数。但情况似乎并非如此。您可以参考:
如果有多个构造函数,您可以指定一个,如下所示:
Add{LIFETIME}<{SERVICE}>(sp => new {IMPLEMENTATION})
Add{LIFETIME}(sp=>new{IMPLEMENTATION})
例如:
// Constructor1
builder.Services.AddScoped<IMyDep>(sp => new MyDep());
// Constructor2
builder.Services.AddScoped<IMyDep>(sp => new MyDep("A string!"));
// Constructor3
builder.Services.AddScoped<IClass1, Class1>();
builder.Services.AddScoped<IMyDep>(sp =>
{
IClass1 class1 = sp.GetRequiredService<IClass1>();
//class1.doSomething(...);
return new MyDep(class1);
});
//构造函数1
addScope(sp=>newmydep());
//构造器2
AddScoped(sp=>newmydep(“一个字符串!”);
//构造器3
builder.Services.addScope();
builder.Services.addScope(sp=>
{
IClass1 class1=sp.GetRequiredService();
//类别1.剂量测定法(…);
返回新的MyDep(类别1);
});
因此,您不需要更改DbContext类,只需在不同的应用程序中使用不同的构造函数即可 连接字符串值存储在哪里? 我会查来源。开箱即用的asp.net核心具有配置为注入的application.settings.json文件。AZ函数不这样做。 如果您使用的是application.settings.json,则必须将其配置为从该文件加载设置 下面是如何在DI中加载配置文件的示例,该文件允许您具有与asp.net core中类似的内容访问权限:
var config = new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("application.settings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
builder.Services.AddSingleton<IConfiguration>(config);
var config=new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory)
.AddJsonFile(“application.settings.json”,可选:false,reloadOnChange:true)
.AddenEnvironmentVariables()
.Build();
builder.Services.AddSingleton(配置);
并在Configure方法中获取一个值:
string SqlConnectionString=config.GetConnectionString(“SqlConnectionString”)代码>
这是在公共覆盖无效配置(IFunctionsHostBuilder)
中完成的。
我能想到的另一种可能性是Azure Key Vault或环境变量。取决于您注册上下文的方式(您没有显示),如果没有突出显示所做的事情,则很难重现问题,允许更好地理解所询问的内容。谢谢,但问题与获取连接字符串无关。它可以从local.setting.json文件中读取它。问题是.Net使用了错误的构造函数。在DbContext中,构造函数看起来如何?DbContext构造函数可以覆盖DI进程。public ApplicationDbContext(DbContextOptions):base(options){//在这里执行您需要的任何操作,如Database.EnsureCreated();}
// Constructor1
builder.Services.AddScoped<IMyDep>(sp => new MyDep());
// Constructor2
builder.Services.AddScoped<IMyDep>(sp => new MyDep("A string!"));
// Constructor3
builder.Services.AddScoped<IClass1, Class1>();
builder.Services.AddScoped<IMyDep>(sp =>
{
IClass1 class1 = sp.GetRequiredService<IClass1>();
//class1.doSomething(...);
return new MyDep(class1);
});
var config = new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("application.settings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
builder.Services.AddSingleton<IConfiguration>(config);