Azure 函数使用了错误的 DbContext 构造函数
Posted
技术标签:
【中文标题】Azure 函数使用了错误的 DbContext 构造函数【英文标题】:Azure Function Uses Wrong DbContext Constructor 【发布时间】:2020-01-04 01:32:25 【问题描述】:我有一个现有的 EF Core 2.2 DbContext
可以在 ASPNET Core 应用程序和 LinqPad 中正常工作。现在我正在尝试将它添加到 Azure 函数中。在 ASPNET 和 Azure 函数中,我都在使用依赖注入。
DbContext
类具有三个构造函数 - 一个为空,一个接受连接字符串,另一个接受 DbOptionsBuilder
实例。 ASPNET Core 应用程序似乎调用了采用 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);
正如我所说,它正在读取连接字符串并似乎将其传递给 AddDbContext 方法。但是某处出了点问题。
编辑 2
这是我的DbContext
子类中的三个构造函数。没什么特别的。还包括OnConfiguring
方法。
public FullContext()
public FullContext(string connectionString)
ConnectionString = connectionString;
public FullContext(DbContextOptions<FullContext> options) : base(options)
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
if (ConnectionString != null)
optionsBuilder.UseSqlServer(ConnectionString);
base.OnConfiguring(optionsBuilder);
编辑 3 在查看了@Jack Jia 建议的链接后,我尝试了以下操作。
首先,我创建自己的DbContextOptionsBuilder
实例并指定提供程序和连接字符串。
var options = new DbContextOptionsBuilder<FullContext>();
options.UseSqlServer(connectionString);
然后我尝试强制 DI 服务使用这些选项。但是,使用 AddDbContext
方法时会失败 - 它仍然尝试使用空字符串作为参数调用错误的构造函数。
换句话说,这失败了:
builder.Services.AddDbContext<FullContext>(x => new FullContext(options.Options), ServiceLifetime.Transient);
但这似乎有效:
builder.Services.AddTransient<FullContext>(x => new FullContext(options.Options));
假设我正确理解了文档,这两个调用都应该强制 DI 服务使用带有 DbContextOptions
参数的构造函数。但这似乎并非如此。
【问题讨论】:
取决于你如何注册上下文(你没有显示) 如果没有minimal reproducible example 明确指出已完成的工作,就很难重现问题,从而更好地理解所询问的内容。 【参考方案1】:连接字符串值存储在哪里? 我会检查来源。开箱即用的 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);
并在 Configure 方法中获取一个值:
string SqlConnectionString = config.GetConnectionString("SqlConnectionString");
这是在public override void Configure(IFunctionsHostBuilder builder)
中完成的。
Here is how to use DI in Azure Functions.
我能想到的另一种可能性是 Azure Key Vault 或环境变量。
【讨论】:
谢谢,但问题与获取连接字符串无关。它可以从 local.settting.json 文件中读取它。问题是 .Net 使用了错误的构造函数。 在 DbContext 中,您的构造函数看起来如何? DbContext 构造器可以覆盖 DI 过程。public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) //do whatever you need here, like Database.EnsureCreated();
【参考方案2】:
您可以参考:Service registration methods
如果有多个构造函数,可以指定如下:
AddLIFETIME<SERVICE>(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);
);
因此,您无需更改 DbContext 类,只需在不同的应用程序中专门使用不同的构造函数即可。
【讨论】:
以上是关于Azure 函数使用了错误的 DbContext 构造函数的主要内容,如果未能解决你的问题,请参考以下文章
使用 DBContext 将 SQL Server 数据库与时间触发的 Azure 函数连接起来
使用身份验证托管的 Blazor Wasm 上出现 Azure 500 错误
Entity Framework DbContext 使用错误的构造函数初始化
通过 HTTP 调用 Azure Function 150 次导致异常