C# 从.net Core WebApi中的startup.cs访问HttpContextAccessor

C# 从.net Core WebApi中的startup.cs访问HttpContextAccessor,c#,asp.net-core,asp.net-core-webapi,C#,Asp.net Core,Asp.net Core Webapi,我正在asp.net核心中记录数据库的异常。MyDbContext接受HttpContextAccessor参数。因此,我将HttpContextAccessor发送到MyDbContext.cs以访问我的JWT。但是,我无法从Startup.cs访问我的HttpContextAccessor。我怎样才能做到这一点 Startup.cs public void ConfigureServices(IServiceCollection services) { serv

我正在asp.net核心中记录数据库的异常。MyDbContext接受HttpContextAccessor参数。因此,我将HttpContextAccessor发送到MyDbContext.cs以访问我的JWT。但是,我无法从Startup.cs访问我的HttpContextAccessor。我怎样才能做到这一点

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();
    }
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));
    }
}
公共类MyDbContext:DbContext
{
专用只读IHttpContextAccessor\u httpContextAccessor;
公共MyDbContext(DbContextOptions选项,IHttpContextAccessor httpContextAccessor)
:base(GetOptions())
{
_httpContextAccessor=httpContextAccessor;
}
私有静态DbContextOptions GetOptions()
{
返回SqlServerDbContextOptionsExtensions.UseSqlServer(新的DbContextOptionsBuilder(),“服务器=asd;数据库=;用户id=asd;密码=1234”)。选项;
}
公共覆盖异步任务saveChangesSync(CancellationToken CancellationToken=default(CancellationToken))
{
var token=httpContextAccessor.HttpContext.Request.Headers[“Authorization”];
var audits=AuditHelper.AddAuditLog(base.ChangeTracker,token);
返回(wait base.saveChangesSync(true,cancellationToken));
}
}

您可以将所需的任何内容注入
Configure
方法。您已使用以下行将其添加到服务集合:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
顺便说一句:我还想指出,当您使用依赖项注入时,在静态助手类中手动创建
DbContext
的实例有点代码味道

根据评论进行更新

为了稍微整理一下,我将首先更改启动以配置DbContext,如下所示:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IHttpContextAccessor accessor)
{
    // make use of it here
}
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
的实例注入到需要访问它的任何类中。问题是(据我所知)DI不能很好地与静态类/方法一起工作,您正在
HttpResponse
上使用扩展方法来记录错误

我认为最好创建一个类,该类负责记录错误,并且依赖于
MyDbContext
,并将其注入
Configure
方法:

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访问器:

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);
     }));
}
public void配置(IApplicationBuilder应用程序、IHostingEnvironment环境、ErrorLogger)
{
app.UseExceptionHandler(builder=>builder.Run(异步上下文=>
{
var error=context.Features.Get();
logger.LogError(错误);
wait context.Response.WriteAsync(error.error.Message);
}));
}

我还没有测试过这个,而且我不熟悉
.UseExceptionHandler(…)
,因为我使用应用程序洞察来记录异常等(如果您没有看到它,请查看)。需要注意的一件事是依赖关系的范围;默认情况下,DbContext的作用域是
的(我认为您应该保持这种方式),这意味着您不能将其注入
单例对象中。

谢谢@Ben。是的,我想我做错了什么。如何在不始终以HttpContextAccessor的形式发送参数的情况下实现从MyDbContext的访问?因为我需要MyDbContext中的JWT信息。你能修好我的密码吗?都修好了,不过要小心点!请看一下我在这里提出的一些问题的答案,以获取专家的见解。
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);
    }
}
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);
     }));
}