Доступ к сервисам из DbContext в.Net Core. 2,1
У меня есть проект.Net Core 2.1 Web Api. Я создаю базу DbContext, имя которой DataContext.cs
, Я хочу начать DataContext
от IAuditHelper
, Когда старт проекта, я могу установить AuditHelper
из моего автозагрузки.
Но после запуска проекта и выполнения SaveChangesAsync
метод, это ноль. Как можно получить AuditHelper из My DataContext? (Я знаю, что если я добавлю IAuditHelper в свой конструктор DataContext, я смогу принять. Но в этой ситуации 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));
}
}
IDataContext.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>();
}
1 ответ
Внедрение зависимостей ASP.NET Core не поддерживает внедрение свойств, вместо этого вы можете внедрить зависимости в конструктор, как показано ниже. Другой вариант - использовать контейнеры, поддерживающие внедрение свойств, такие как Unity или 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)
{
}
}
Я не совсем понимаю, зачем вам нужен AuditHelper в интерфейсе IDataContext, я бы сохранил его в приватном файле в DataContext и не стал бы его выставлять.
AuditHelper класс:
public class AuditHelper : IAuditHelper
{
private readonly IHttpContextAccessor _httpContextAccessor;
public AuditHelper(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void LogMyChangesToDatabase()
{
//_httpContextAccessor.HttpContext.
}
}
В классе Startup:
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>();
...
}
...
}
Разницу между областями вы можете найти по ссылке.
Контроллер:
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);
}
И строка подключения причины должна быть в конфигурации, см. Учебник.