繁体   English   中英

从.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。 我怎样才能做到这一点?

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

 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

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方法中注入所需的任何内容。 您已使用以下行将其添加到服务集合中:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

所以你需要做的就是将它添加到方法的参数列表中,如下所示:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IHttpContextAccessor accessor)
{
    // make use of it here
}

DbContext说一下:我还要指出,当您使用依赖注入时,您在静态帮助器类中手动创建DbContext的实例时会产生一些代码味道。

更新以回应评论

为了整理一下,我会先改变你的启动来配置DbContext,如下所示:

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()方法,并将构造函数更改为:

public MyDbContext(DbContextOptions<MyDbContext> options, IHttpContextAccessor httpContextAccessor)
    : base(options)
{
    _httpContextAccessor = httpContextAccessor;
}

然后将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);
     }));
}

我没有对此进行测试,并且我不熟悉.UseExceptionHandler(...)因为我使用应用程序洞察来记录异常等(如果你没有看到它,请看看它)。 需要注意的一件事是依赖关系的范围; 你的DbContext默认是Scoped (我认为你应该这样离开),这意味着你不能将它注入Singleton对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM