从.net Core WebApi中的startup.cs访问HttpContextAccessor [英] Access HttpContextAccessor from startup.cs in .net Core WebApi
问题描述
我正在将异常记录到asp.net核心中的数据库. MyDbContext使用HttpContextAccessor参数.因此,我将HttpContextAccessor发送到MyDbContext.cs以访问我的JWT.但是,我无法从Startup.cs访问HttpContextAccessor.我该如何实现?
I'm logging exceptions to database in asp.net 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!