Регистрация Виндзорского Замка на открытые дженерики

У меня есть 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"))
);
Другие вопросы по тегам