Доступ к HttpContextAccessor из файла startup.cs в .net Core WebApi - PullRequest
0 голосов
/ 22 октября 2018

Я регистрирую исключения в базе данных в ядре asp.net.MyDbContext принимает параметр HttpContextAccessor. Итак, я отправляю HttpContextAccessor в MyDbContext.cs для доступа к моему JWT.Но я не могу получить доступ к своему HttpContextAccessor из 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

 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));
    }
}

1 Ответ

0 голосов
/ 22 октября 2018

Вы можете ввести все, что вам нужно, в метод Configure.Вы уже добавили его в коллекцию сервисов со следующей строкой:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

Поэтому все, что вам нужно сделать, это добавить его в список аргументов метода, подобного следующему:

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

В качестве отступления: я также хотел бы отметить, что это немного пахнет кодом, когда вы вручную создаете экземпляр вашего 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...
    }
}

Затем вы можете удалить метод .GetOptions() из MyDbContext и изменить конструктор на:

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 объектов.

...