Мне нужно внедрить зависимость в мой класс DbContext для моего проекта. Я пытаюсь сделать это так, как следует из «Чистой архитектуры».
Мне нужно иметь возможность использовать пустой конструктор DbContext и по-прежнему ссылаться на строку подключения из файла конфигурации.
Я использую этот универсальный репозиторий и внедряю его в сервисы. Это определено на прикладном уровне.
public class GenericRepository<C, T> : IGenericRepository<C, T> where T : class where C : DbContext, new()
{
private DbContext _entities = new C();
}
В моем классе EF Core Context (определенном на уровне постоянства) у меня есть это:
public partial class MyContext : DbContext
{
private IConnectionStringProvider _connectionStringProvider;
public virtual DbSet<MyEntity> { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(_connectionStringProvider.GetConnectionString());
}
}
}
У меня также есть реализация для IConnectionStringProvider, определенная на уровне постоянства. Я хочу, чтобы эта реализация была легко заменяемой в случае необходимости. На данный момент он читает из App.config и использует пакет nuget ConfigurationManager. Но это может измениться в будущем, поэтому его нужно легко заменить.
IConnectionStringProvider определен на прикладном уровне:
public interface IConnectionStringProvider
{
string GetConnectionString();
}
В моем уровне Presentation у меня есть проект ASP.NET Core MVC. В StartUp.cs я использую стандартный способ внедрения dbContext в мои контроллеры:
services.AddDbContext<ContractsWorkloadContext>();
Я могу заставить это работать нормально, если переопределю OnModelCreatingMethod следующим образом.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
_connectionStringProvider = new ConnectionStringProvider();
optionsBuilder.UseSqlServer(ConnectionStringProvider.GetConnectionString());
}
}
Этот метод позволяет мне использовать значения строки подключения из конфигурации с пустым экземпляром конструктора контекста, который необходим для его работы с моим общим репозиторием, а также все еще иметь возможность использовать конструктор с параметром DbContextOptionsBuilder.
Моя единственная проблема, которую предстоит решить, - это как добиться этого, чтобы контекст не зависел от реализации.
Я попытался внедрить свойство Autofac, зарегистрировав интерфейс и реализацию IConnectionStringProvider, а также зарегистрировав класс Context со свойствами "Autowired". Но свойство всегда равно нулю.
И да, я понимаю, что выше это поле, а не собственность. Я пытался изменить класс контекста, чтобы иметь свойство вместо поля. Я попытался даже создать метод для установки поля и использовать метод инъекции с автофаком. Но свойство / поле всегда равно нулю в каждом случае.
builder.RegisterType<ConnectionStringProvider>().As<IConnectionStringProvider>()();
builder.RegisterType<MyContext>().PropertiesAutowired();
И
builder.RegisterType<ContractsWorkloadContext>().OnActivated(e =>
{
var provider = e.Context.Resolve<IConnectionStringProvider>();
e.Instance.SetConnectionstringProvider(provider);
});
В итоге мне нужно:
- Вставить строку подключения в контекст
- Разрешить создание пустого экземпляра конструктора
- Поддерживать дизайн "Чистая архитектура"
Любая помощь здесь будет оценена.
Спасибо.