c# - 无法使用 EF 6 为 PostgreSQL DbContext 注册作用域或临时服务
问题描述
我们尝试在带有 EF Core 的 ASP .Net Core 项目上使用 PostgreSQL(通过 Npgsql)。通过依赖注入,我们可以将 DbContext 添加为单例,但尝试将其用作瞬态或范围服务会在应用程序启动时触发 500.30 错误。
问题是,作为单例,当服务器上的并发查询同时使用 DbContext 时会失败,然后在执行控制器和服务时生成 500 个错误。正如下面在评论中所说,这是一个重大错误,不可行。
因此,我们尝试将其添加为瞬态,但未能将其正确插入服务集合中。这是我们没有使用单例(悲惨)方法的启动配置代码:
public void ConfigureServices(IServiceCollection services)
{
try
{
services.AddHttpContextAccessor();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
// initiating database service for DI
DbContextOptions<EFCoreContext> optionsBuilder = new DbContextOptions<EFCoreContext>();
OurDbContext context = new OurDbContext (optionsBuilder);
services.AddDbContext<OurDbContext >(
options => options.UseNpgsql(
Configuration["ConnectionStrings:ConnectionString"]
)
);
// initiating session service with in memory store
Services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(
Double.Parse(
Configuration["Session:DurationInMinutes"]
)
);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.Name = ".api.myAccess-TDF";
});
services.AddControllers();
// adding localization, with customized PO file finder
services.AddMvc().
AddViewLocalization(
LanguageViewLocationExpanderFormat.Suffix
);
services.AddPortableObjectLocalization(
options => options.ResourcesPath = "Localization"
);
// adding application services
services.AddSingleton<ILocalizationFileLocationProvider, TranslatorFileLocationProvider>();
services.AddSingleton<ISiteService, SiteService>();
services.AddSingleton<IQueryService, QueryService>();
services.AddSingleton<IQueryStatusService, QueryStatusService>();
services.AddSingleton<IAccountService, AccountService>();
services.AddSingleton<ISnowService, SnowService>();
// adding HttpContextAccessor dependency injection
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// configurating application cultures
services.Configure<RequestLocalizationOptions>(options => {
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("fr-FR"),
new CultureInfo("fr")
};
options.DefaultRequestCulture = new RequestCulture("fr-FR");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
// adding translation service (which use Localizer by D.I.)
services.AddSingleton<ITranslator, Translator>();
// adding swagger interface
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(
"v1", new OpenApiInfo {Title = "WebApi", Version = "v1"}
);
});
// adding super permissive CORS,
// since this is an open API server, anybody can access it
services.AddCors(options => {
options.AddDefaultPolicy(builder => {
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
// Create a MapperConfiguration instance with profiles
// and add the mapper as a service for Dependency Injection
var mappingConfig = new MapperConfiguration(mc => {
mc.AddProfile(new MappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
} catch (Exception e) {
Console.WriteLine(e)
}
}
OurDbContext 是一个派生自 EFCoreContext 的类,即使我们手动执行 Scaffold-DbContext (我们首先使用数据库,所以当我们执行脚手架时它会重写 EFCoreContext 并且我们不能放置),它让我们可以从 appsettings.json 文件配置我们的连接字符串我们在此类中的配置参考)。这是该类的代码:
namespace App_DAL
{
public partial class OurDbContext : EFCoreContext
{
private readonly DbContextOptionsBuilder OptionBuilder;
public OurDbContext(DbContextOptions<EFCoreContext> options)
: base(options)
{
OptionBuilder = new DbContextOptionsBuilder();
}
public OurDbContext(
DbContextOptions<EFCoreContext> options,
DbContextOptionsBuilder optionBuilder
) : base(options)
{
OptionBuilder = optionBuilder;
}
/// <summary>
/// Executes the database connection string definition when the context is configured
/// The connection string is read from the main application appsettings.json file
/// This file is defined in the starting project of the solution
/// </summary>
/// <param name="optionsBuilder">Optional context builder options</param>
protected override void OnConfiguring(
DbContextOptionsBuilder optionsBuilder
){
if (!optionsBuilder.IsConfigured) {
// getting the connection string from configuration files
// two configuration files can be used :
// appsettings.json and appsettings.Development.json,
// both placed in the main project root directory
string testingProjectDir = Directory.GetCurrentDirectory();
string configPath = Path.Combine(
testingProjectDir, "appsettings.json"
);
string configPathDev = Path.Combine(
testingProjectDir, "appsettings.Development.json"
);
IConfigurationBuilder builder = new ConfigurationBuilder()
.AddJsonFile(
configPath, optional: false,
reloadOnChange: true
);
// if we have a development configuration file
// in the project then we add it to the main one,
// so it can redefine properties linked to the
// development platform
if (File.Exists(configPathDev))
{
builder.AddJsonFile(
configPathDev, optional: false,
reloadOnChange: true
);
}
// now we read the connection string inside the configuration
IConfigurationRoot configuration = builder.Build();
string connectionString = configuration.GetSection(
"ConnectionStrings:ConnectionString"
).Value;
// unable to get the connection string :/
// trigering an exception
if (string.IsNullOrEmpty(connectionString))
{
string msg = "<ERROR> DemandesAccesContext.OnConfiguring - Unable to read connection string in application settings. Please check settings file content";
Console.WriteLine(msg);
throw new System.Exception(msg);
}
else
{
// the connection string is defined to access the database
optionsBuilder.UseNpgsql(
connectionString,
options => options.EnableRetryOnFailure()
);
}
}
}
}
}
因此,从那里启动 API 应用程序将触发默认打开的 Swagger 页面上显示的 500.30 错误。当尝试访问 API 时,我们得到同样的错误:
IIS Express 日志中未跟踪任何异常,但数据库中的应用程序日志 (Serilog) 包含指向此的异常:
Error while validating the service descriptor 'ServiceType: App_DAL.OurDbContext Lifetime: Scoped ImplementationType: App_DAL.OurDbContext':
No constructor for type 'App_DAL.OurDbContext' can be instantiated using services from the service container and default values.
完整的异常堆栈包含 5 个内部异常,但它们都达到了这一点: OurDbContext 无法验证,因为它的构造函数和我们在服务集合中添加它的方式之间缺少某些东西。但坦率地说,我不明白如何纠正这一点。对不起,我在这里缺乏理解。有人知道如何使这件事起作用吗?
谢谢,弗朗索瓦
解决方案
推荐阅读
- git - 更新了 .gitignore 并重置了 git 缓存,但目录不会被 git 忽略
- django - 如何从模板接收 django-html 动态“div-id”标签到views.py
- r - R 公式是否跨包将函数和变量滞后视为变量?
- javascript - 是否可以在新标签 Chrome 扩展中预缓存 index.html、样式和脚本?
- c# - 在按键上更改 WinForm DataGridView 中的颜色
- amazon-web-services - 获取 athena 数据库中所有表的表名和行数
- bash - 如何获取便携式TOR浏览器的真实PID?
- ffmpeg - ffmpeg / python 脚本 - 它实际上在做什么吗?
- jquery - load() 和 ajax 类型 GET 有什么区别?
- react-native - navigation.navigate() 在本机反应中与 setState() 不同时工作