我正在将异常记录到asp核心中的数据库. MyDbContext使用HttpContextAccessor参数.因此,我将HttpContextAccessor发送到MyDbContext.cs以访问我的JWT.但是,我无法从Startup.cs访问HttpContextAccessor.我该如何实现?
I'm logging exceptions to database in asp core. MyDbContext take HttpContextAccessor parameter.So, I'm sending HttpContextAccessor to MyDbContext.cs for access my JWT. But, I can't access my HttpContextAccessor from Startup.cs. How can I achieve this?
Startup.cs
Startup.cs
public void ConfigureServices(IServiceCollection services) { services.AddHttpContextAccessor(); services.AddMvc(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddDbContext<MyDbContext>(); services.AddTransient<IUnitOfWork, UnitOfWork>(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseExceptionHandler(builder => builder.Run(async context => { var error = context.Features.Get<IExceptionHandlerFeature>(); context.Response.AddApplicationError(error,???????);//I want access HttpContextAccessor await context.Response.WriteAsync(error.Error.Message); })); app.UseHttpsRedirection(); app.UseMvc(); }ExceptionHelper.cs
ExceptionHelper.cs
public static class ExceptionHelper { public static async Task AddApplicationError(this HttpResponse response, IExceptionHandlerFeature error, IHttpContextAccessor httpContextAccessor) { Log log = new Log(); log.Message = error.Error.Message; MyDbContext context = new MyDbContext(null, httpContextAccessor); UnitOfWork uow = new UnitOfWork(context); uow.LogRepo.AddOrUpdate(log); await uow.CompleteAsync(false); } }MyDbContext
MyDbContext
public class MyDbContext : DbContext { private readonly IHttpContextAccessor _httpContextAccessor; public MyDbContext(DbContextOptions<MyDbContext> options, IHttpContextAccessor httpContextAccessor) : base(GetOptions()) { _httpContextAccessor = httpContextAccessor; } private static DbContextOptions GetOptions() { return SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), "server=asd; database=; user id=asd; password=1234").Options; } public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)) { var token = _httpContextAccessor.HttpContext.Request.Headers["Authorization"]; var audits = AuditHelper.AddAuditLog(base.ChangeTracker, token); return (await base.SaveChangesAsync(true, cancellationToken)); } }推荐答案
您可以将所需的任何内容注入Configure方法.您已经通过以下这一行将其添加到服务集合中:
You can inject whatever you need into the Configure method. You have already added it to the service collection with this line:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();所有您需要做的就是将其添加到方法的参数列表中,如下所示:
So all you need to do is add it to the list of arguments on the method like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IHttpContextAccessor accessor) { // make use of it here }顺便说一句:我还要指出,当您使用依赖项注入时,您是在静态帮助器类中手动创建DbContext的实例,这有点代码味道.
As an aside: I would also point out that it's a bit of a code smell that you are manually creating an instance of your DbContext inside your static helper class when you are using dependency injection.
根据评论进行更新
为了整理一些东西,我将从更改启动方式开始,为您配置DbContext,如下所示:
In order to tidy things up a bit I would start by changing your startup to configure you DbContext something like this:
public class Startup { private readonly IConfiguration configuration; public Startup(IConfiguration configuration) { this.configuration = configuration; } public void ConfigureServices(IServiceCollection services) { // register other things here... services.AddDbContext<DataContext>(o => o.UseSqlServer( config.GetConnectionString("MyConnectionString") // from appsettings.json )); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // set up app here... } }然后可以从MyDbContext中删除.GetOptions()方法,并将构造函数更改为:
You can then remove the .GetOptions() method from MyDbContext, and change the constructor to:
public MyDbContext(DbContextOptions<MyDbContext> options, IHttpContextAccessor httpContextAccessor) : base(options) { _httpContextAccessor = httpContextAccessor; }然后将MyDbContext的实例注入到需要访问它的任何类中.问题是(据我所知)DI无法与静态类/方法一起很好地工作,并且您正在使用HttpResponse上的扩展方法记录错误.
Then you inject an instance of MyDbContext into whatever class needs access to it. The problem is that (to my knowledge) DI does not work well with static classes/methods, and you are using an extension method on the HttpResponse to log your error.
我认为最好创建一个类,该类负责记录错误并依赖于您的MyDbContext并将其注入到Configure方法中:
In my opinion it would be better to create a class that is responsible for logging the error with a dependency on your MyDbContext and have that injected into the Configure method:
public class ErrorLogger { private MyDataContext db; public ErrorLogger(MyDataContext db) => this.db = db; public void LogError(IExceptionHandlerFeature error) { Log log = new Log(); log.Message = error.Error.Message; UnitOfWork uow = new UnitOfWork(this.db); uow.LogRepo.AddOrUpdate(log); await uow.CompleteAsync(false); } }像在其他地方一样,将其注册到DI容器中,然后将其注入到Configure而不是HTTP访问器中:
Register it with the DI container as you have with other things, then inject it into Configure instead of the HTTP accessor:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ErrorLogger logger) { app.UseExceptionHandler(builder => builder.Run(async context => { var error = context.Features.Get<IExceptionHandlerFeature>(); logger.LogError(error); await context.Response.WriteAsync(error.Error.Message); })); }我还没有测试过,并且我不熟悉.UseExceptionHandler(...),因为我使用应用程序见解来记录异常等(如果您没有看到它,请查看它).要注意的一件事是依赖项的范围.默认情况下,您的DbContext将为Scoped(我认为您应该使用这种方式),这意味着您无法将其注入到Singleton对象中.
I have not tested this, and I am not familiar with .UseExceptionHandler(...) as I use application insights to log exceptions etc (take a look at it if you've not seen it). One thing to be aware of is the scope of your dependencies; your DbContext will be Scoped by default (and I think you should leave it that way), which means you cannot inject it into Singleton objects.
更多推荐
从.net Core WebApi中的startup.cs访问HttpContextAccessor
发布评论