我编写了我添加的自定义中间件
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//...
app.UseAutologin();
app.UseMvc(routes =>
{
//...
所以它是Mvc发挥作用之前的最后一个中间件。
在我的中间件的Invoke
方法中,我想(间接)访问DbContext
。
public async Task Invoke(HttpContext context)
{
if (string.IsNullOrEmpty(context.User.Identity.Name))
{
var applicationContext = _serviceProvider.GetService<ApplicationDbContext>();
var signInManager = _serviceProvider.GetService<SignInManager<ApplicationUser>>();
var result = await signInManager.PasswordSignInAsync(_options.UserName, _options.Password, true, false);
}
await _next(context);
}
几乎每次我收到以下异常:
InvalidOperationException
:尝试使用上下文 正在配置它。无法使用DbContext
实例 在OnConfiguring
内,因为此时仍在配置。
现在PasswordSignInAsync
方法明显提出了这一点。但是,如何确保在执行此类操作之前创建模型?
也许我并不完全清楚:我不想自己使用DbContext
- PasswordSignInAsync
在验证用户和密码时使用它。
答案 0 :(得分:7)
如果您通过ApplicationDbContext
方法注入SignInManager<ApplicationUser>
和Invoke
该怎么办:
public async Task Invoke(HttpContext context, ApplicationDbContext applicationContext, SignInManager<ApplicationUser> signInManager)
{
if (string.IsNullOrEmpty(context.User.Identity.Name))
{
var result = await signInManager.PasswordSignInAsync(_options.UserName, _options.Password, true, false);
}
await _next(context);
}
这样您就可以从正确的范围解析服务。我注意到你实际上并没有在任何地方ApplicationDbContext
使用SignInManager
。你真的需要吗?
答案 1 :(得分:2)
可能会发生此错误,因为任何中间件都充当单例。您必须避免在中间件中使用成员变量。随意注入任务调用,但不要将注入值存储到成员对象中。
请参阅:Saving HttpContext Instance in Middleware, Calling services in Middleware
我能够自己解决这个问题,创建一个类,然后我可以将其传递给我的中间件中的其他方法:
public async Task Invoke(HttpContext context, IMetaService metaService)
{
var middler = new Middler
{
Context = context,
MetaService = metaService
};
DoSomething(middler);
}
答案 2 :(得分:0)
这是一个非常适合我的用例的简单解决方案。 我创建了一个简单的方法,我可以从应用程序的任何地方调用它来轻松获取数据库上下文:
public class UtilsApp
{
public static MyDbContext GetDbContext()
{
DbContextOptionsBuilder<MyDbContext> opts =
new DbContextOptionsBuilder<MyDbContext();
optionsBuilder.UseSqlServer(Program.MyDbConnectionString); // see connection string below
return new MyDbContext(opts.Options);
}
}
然后,在应用程序的任何地方使用它:
MyDbContext dbContext = UtilsApp.GetDbContext();
我在 Program.MyDbConnectionString
内设置了 public static string
(一个 Startup.ConfigureServices()
字段)(这是一个通过 Program.Main()
从 CreateHostBuilder(args).Build()
内调用的回调)。这样我就可以在应用程序的任何地方使用该连接字符串,而不必从 appsettings.json
或环境变量中重复检索它。