从 .NET Core 2.1 中的 DbContext 访问服务

Access services from DbContext in .NET Core 2.1

我有 .NET Core 2.1 WebAPI 项目。我创建了名称为 DataContext.cs 的基础 DbContext。我想从 IAuditHelper 开始 DataContext。当项目开始时,我可以从我的 Startup.cs.

设置 AuditHelper

但是,在项目启动并执行 SaveChangesAsync 方法后,它为空。 我如何才能从我的 DataContext 中获取 AuditHelper? (我知道,如果我在我的 DataContext 构造函数中注入 IAuditHelper,那么我可以接受。但是,在那种情况下,Datacontext 到处都需要 IAuditHelper。

DataContext.cs

 public class DataContext : DbContext,IDataContext
 {
     public IAuditHelper AuditHelper { get; set; }

     public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
     {
         auditHelper.LogMyChangesToDatabase()
         return (await base.SaveChangesAsync(true, cancellationToken));
     }
 }

我DataContext.cs

public interface IDataContext : IDisposable
{
    IAuditHelper AuditHelper{ get; set; }
    Task<int> SaveChangesAsync(CancellationToken cancellationToken);
    Task<int> SaveChangesWithoutAuditAsync(CancellationToken cancellationToken);
}

UniversityDbContext.cs

 public class UniversityDbContext: DataContext
 {      
    override protected void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      optionsBuilder.UseSqlServer("server=.; database=.; user id=.; 
            password=.;");
    }

    public UniversityDbContext() : base()
    {
    }
 }

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IAuditHelper, AuditHelper>();
    services.AddScoped<IDataContext, DataContext>();
    services.AddScoped<DataContext, UniversityDbContext>();
    services.AddDbContext<UniversityDbContext>();
       

    var sp = services.BuildServiceProvider();
    var dataContext = sp.GetService<IDataContext>();
    dataContext.AuditHelper = sp.GetService<IAuditHelper>();
}

ASP.NET 核心依赖注入不支持 属性 注入,您可以将依赖注入到构造函数中,如下所示。另一种选择是使用支持 属性 注入的容器,例如 Unity or Autofac.

public class DataContext : DbContext, IDataContext
{
    public DataContext(IAuditHelper auditHelper, DbContextOptions options)
        : base(options)
    {
        AuditHelper = auditHelper;
    }

    public IAuditHelper AuditHelper { get; private set; }

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
    {
        AuditHelper.LogMyChangesToDatabase();
        return base.SaveChangesAsync(true, cancellationToken);
    }

    ...
}

public interface IDataContext : IDisposable
{
    IAuditHelper AuditHelper { get; }

    Task<int> SaveChangesAsync(CancellationToken cancellationToken);

    ...
}

public class UniversityDbContext : DataContext
{
    public UniversityDbContext(IAuditHelper auditHelper, DbContextOptions options)
        : base(auditHelper, options)
    {
    }
}

我不太明白为什么你需要在 IDataContext 接口中使用 AuditHelper,我会把它保存在 DataContext 的私有文件中,不会公开它。

AuditHelper class:

public class AuditHelper : IAuditHelper
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public AuditHelper(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public void LogMyChangesToDatabase()
    {
        //_httpContextAccessor.HttpContext.
    }
}

在启动中class:

public class Startup
{
    ...

    public void ConfigureServices(IServiceCollection services)
    {
        ...

        services.AddHttpContextAccessor();
        services.AddDbContext<UniversityDbContext>(options
            => options.UseSqlServer("Server=(localdb)\mssqllocaldb;Database=TestUniversity;Trusted_Connection=True;MultipleActiveResultSets=true"));
        services.AddScoped<IAuditHelper, AuditHelper>();

        ...
    }

    ...
}

您可以在 the link.

找到范围之间的差异

一个控制器:

public class SomeController : ControllerBase
{
    private readonly UniversityDbContext _context;

    public SomeController(UniversityDbContext context)
    {
        _context = context;
    }

    [HttpPost]
    public async Task Post([FromBody] string value)
    {
        ...
        await _context.SaveChangesAsync();
    }
}

我还建议遵循 TAP 并更改 LogMyChangesToDatabase:

    public async Task LogMyChangesToDatabase()
    {
        //_httpContextAccessor.HttpContext.
        //await 
    }

SaveChangesAsync 将相应地:

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
    {
        await AuditHelper.LogMyChangesToDatabase();
        return await base.SaveChangesAsync(true, cancellationToken);
    }

而cause的连接字符串应该在配置里,see tutorial.