简体   繁体   中英

Castle Windsor: How do I register a factory method, when the underlying type isn't accessible to my assembly?

I have a project where my business layer is constructed using DI, but I'm trying to go an additional step and use Windsor to manage object construction.

Let's just say I have a pre-existing data layer (that I don't want to modify), that can be accessed via the following interface:

interface IDataFactory {
   IDataService Service { get; }
}

A series of classes in my business layer depend on the services exposed through IDataFactory:

IFactory factory = DataFactory.NewFactory();
IBusinessService service = new ConcreteBusinessService(factory.Service);

I understand that in order to register IBusinessService to the Castle Windsor container, I'd use code similar to this:

IWindsorContainer container = new WindsorContainer();
container.AddComponent("businessService", typeof(IBusinessService), typeof(ConcreteBusinessService));

But for the life of me, I can't figure out how to register services from my data layer, using the my existing factory object. In essence, I'd like to say:

container.AddComponent("dataService", typeof(IDataService), factory.service);

Windsor seems to want me to say container.AddComponent("dataService", typeof(IDataService), typeOf(SomeConcreteDataService) ), but in this instance, ConcreteDataService is internal to that assembly, and thus not accessible in mine.

How would I go about wiring up the data service, given that SomeConcreteDataService isn't known to my assembly?


This question is very similar to my own, except in my case, the AddComponent("calculator", typeof(ICalcService), typeof(CalculatorService), "Create"); call wouldn't work -- CalculatorService would be internal to another assembly, not available to the assembly wiring up the container.

Using Windsor 2.0:

[TestFixture]
public class WindsorTests {
    public interface IDataService {}

    public class DataService: IDataService {}

    public interface IDataFactory {
        IDataService Service { get; }
    }

    public class DataFactory: IDataFactory {
        public IDataService Service {
            get { return new DataService(); }
        }
    }

    [Test]
    public void FactoryTest() {
        var container = new WindsorContainer();
        container.AddFacility<FactorySupportFacility>();
        container.AddComponent<IDataFactory, DataFactory>();
        container.Register(Component.For<IDataService>().UsingFactory((IDataFactory f) => f.Service));
        var service = container.Resolve<IDataService>();
        Assert.IsInstanceOfType(typeof(DataService), service);
    }
}

See the fluent API wiki page for more information.

Got it. The answer is, you don't need to worry about the implementation type:

    IWindsorContainer container = new WindsorContainer();
    container.AddFacility("factories", new FactorySupportFacility());
    container.AddComponent("standard.interceptor", typeof(StandardInterceptor));
    container.AddComponent("factory", typeof(DataFactory));

    MutableConfiguration config = new MutableConfiguration("dataService");
    config.Attributes["factoryId"] = "factory";
    config.Attributes["factoryCreate"] = "get_Service";
    container.Kernel.ConfigurationStore.AddComponentConfiguration("dataService", config);
    container.Kernel.AddComponent("dataService", typeof(IDataService));

    IDataService dataService = (IDataService) container["dataService"];

I had a "whoa" moment when I saw it execute successfully, because I hadn't passed in the specific implementation type to Kernel.AddComponent()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM