Регистрация Виндзорского Замка на открытые дженерики
У меня есть 2 класса для обработки данных:
public class SqlDataProvider<T> : IDataProvider<T> where T : IEntity
public class MongoDataProvider<T> : IDataProvider<T> where T : IEntity
и у меня есть много таких моделей:
public class Account : ISqlDbEntity
public class Log : IMongoDbEntity
с этими интерфейсами:
public interface IMongoDbEntity : IEntity
public interface ISqlDbEntity : IEntity
Как мне зарегистрироваться или возможно ли зарегистрировать контейнер Windsor в качестве универсального, но MondoDbEntity можно использовать с MongoDbProvider, а модели MsSQl - с SqlDataProvider.
container.Register(Component.For(typeof(IDataProvider<>))
.ImplementedBy(typeof(SqlDataProvider<>))
.LifestylePerWebRequest()); //I want this work only with ISqlEntity
container.Register(Component.For(typeof(IDataProvider<>))
.ImplementedBy(typeof(MongoDataProvider<>))
.LifestylePerWebRequest()); //I want this work only with IMongoDbEntity
Я пробовал это, но не работал:
container.Register(Component.For(typeof(IDataProvider<ISqlDbEntity>))
.ImplementedBy(typeof(SqlDataProvider<>))
.LifestylePerWebRequest());
container.Register(Component.For(typeof(IDataProvider<IMongoDbEntity>))
.ImplementedBy(typeof(MongoDataProvider<>))
.DependsOn(Dependency.OnAppSettingsValue("databaseName", "MongoDatabaseName"))
.LifestylePerWebRequest());
Спасибо заранее!
4 ответа
Этот фабричный метод работает отлично!
container.Register(Component.For(typeof(IDataProvider<>))
.Forward(typeof(IReadOnlyDataProvider<>))
.UsingFactoryMethod((kernel, model, creationContext) =>
{
var type = creationContext.GenericArguments.First();
if (type.GetInterface("ISqlDbEntity") != null)
{
var sqlProvider = typeof(SqlDataProvider<>);
return Activator.CreateInstance(sqlProvider.MakeGenericType(type), kernel.Resolve<DbContext>());
}
var mongoProvider = typeof(MongoDataProvider<>);
return Activator.CreateInstance(mongoProvider.MakeGenericType(type), kernel.Resolve<MongoClientSettings>(), ConfigurationManager.AppSettings["MongoDatabaseName"]);
})
.IsDefault()
.LifestylePerWebRequest());
Если каждый поставщик использует только один тип объекта, то почему бы не использовать отличительный интерфейс объекта при регистрации типа поставщика?
container.Register(Component.For(typeof(IDataProvider<ISqlDbEntity>))
.ImplementedBy(typeof(SqlDataProvider<>))
.LifestylePerWebRequest());
Вы можете зарегистрироваться с несколькими интерфейсами, такими как:
container.Register(Component.For(typeof(IDataProvider<>),ISqlDbEntity))
.ImplementedBy(typeof(SqlDataProvider<>))
.LifestylePerWebRequest());
container.Register(Component.For(typeof(IDataProvider<>),IMongoDbEntity))
.ImplementedBy(typeof(MongoDataProvider<>))
.LifestylePerWebRequest());
Как вы уже сделали, просто зарегистрируйте оба экземпляра.
container.Register(Component.For(typeof(IDataProvider<ISqlDbEntity>))
.ImplementedBy(typeof(SqlDataProvider<>))
.LifestylePerWebRequest());
container.Register(Component.For(typeof(IDataProvider<IMongoDbEntity>))
.ImplementedBy(typeof(MongoDataProvider<>))
.DependsOn(Dependency.OnAppSettingsValue("databaseName", "MongoDatabaseName"))
.LifestylePerWebRequest());
Затем в конкретных классах, которые используют этот интерфейс, вы можете указать, какую реализацию вы хотите использовать.
https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md Согласно документации:
container.Register(
Component.For<ITransactionProcessingEngine>().ImplementedBy<TransactionProcessingEngine>()
.DependsOn(Dependency.OnComponent<ILogger, SecureLogger>())
);
Или вы можете назвать свои реализации и использовать этот синтаксис.
container.Register(
Component.For<ITransactionProcessingEngine>().ImplementedBy<TransactionProcessingEngine>()
.DependsOn(Dependency.OnComponent(typeof(ILogger), "secureLogger"))
);