从.net Core WebApi中的startup.cs访问HttpContextAccessor [英] Access HttpContextAccessor from startup.cs in .net Core WebApi

查看:178
本文介绍了从.net Core WebApi中的startup.cs访问HttpContextAccessor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将异常记录到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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆