Vajda Endre
Vajda Endre

Reputation: 1570

Castle Windsor Complex Registration for Opened generic types

I have 2 classes for data handling:

public class SqlDataProvider<T> : IDataProvider<T> where T : IEntity
public class MongoDataProvider<T> : IDataProvider<T> where T : IEntity

and I have a lots of model like these:

public class Account : ISqlDbEntity
public class Log : IMongoDbEntity

with those interfaces:

public interface IMongoDbEntity : IEntity
public interface ISqlDbEntity : IEntity

How should I register or is that possible to register the Windsor container as generics but the MondoDbEntity be used with MongoDbProvider, and the MsSQl models be used with the 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

I have tried these, but was not working:

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());

Thx in advance!

Upvotes: 1

Views: 393

Answers (4)

Vajda Endre
Vajda Endre

Reputation: 1570

This factory method works perfect!

        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());

Upvotes: 0

Ehsan Sajjad
Ehsan Sajjad

Reputation: 62488

You can register with multiple interfaces like:

container.Register(Component.For(typeof(IDataProvider<>),ISqlDbEntity))
        .ImplementedBy(typeof(SqlDataProvider<>))
        .LifestylePerWebRequest());


container.Register(Component.For(typeof(IDataProvider<>),IMongoDbEntity))
    .ImplementedBy(typeof(MongoDataProvider<>))
    .LifestylePerWebRequest()); 

Upvotes: 1

Edwin van Vliet
Edwin van Vliet

Reputation: 567

As you already did just register both instances.

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());

Then in the concrete classes which use this interface you could specify which implementation you want to use.

https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md According to the documentation:

container.Register(
    Component.For<ITransactionProcessingEngine>().ImplementedBy<TransactionProcessingEngine>()
        .DependsOn(Dependency.OnComponent<ILogger, SecureLogger>())
);

Or you can name your implementations and use this syntax.

container.Register(
    Component.For<ITransactionProcessingEngine>().ImplementedBy<TransactionProcessingEngine>()
        .DependsOn(Dependency.OnComponent(typeof(ILogger), "secureLogger"))
);

Upvotes: 1

brainboost
brainboost

Reputation: 379

If each provider uses only one type of entity then why not use the distinctive entity interface in the provider type registration?

container.Register(Component.For(typeof(IDataProvider<ISqlDbEntity>))
    .ImplementedBy(typeof(SqlDataProvider<>))
    .LifestylePerWebRequest()); 

Upvotes: 2

Related Questions