views:

181

answers:

1

2 questions in one, but very much related.

Is it possible with Castle Windsor to resolve a configuration entry such as -

Assembly.Namespace.Object1`2[[${ComponentId1}],[${ComponentId2}]], Assembly

Where ComponentId1 and ComponentId2 are defined as components. Castle Windsor doesn't seem to be resolving the ComponentId, it is just looking for ComponentId1 in the Castle.Windsor assembly.

The second question comes in to play if you can't do the first question. If you have to use a full assembly reference instead of a ComponentId, how can you pass any parameters to the object being created? eg to set ComponentId1.Field1 = "blah", or pass something to the constructor of ComponentId1

Hope that makes sense

Update -

Following the request for code I've knocked together the following -

Objects

public class Wrapper<T, T1> where T : ICollector where T1:IProcessor
{
    private T _collector;
    private T1 _processor;

    public Wrapper(T collector, T1 processor)
    {
        _collector = collector;
        _processor = processor;
    }

    public void GetData()
    {
        _collector.CollectData();
        _processor.ProcessData();
    }

}

public class Collector1 : ICollector
{
    public void CollectData()
    {
        Console.WriteLine("Collecting data from Collector1 ...");
    }
}

public class Processor1 : IProcessor
{
    public void ProcessData()
    {
        Console.WriteLine("Processing data from Processor1  ...");
    }
}

repeated so 3 of each type of object in the example

Config

<components>
<component id="Collector1"
           service="CastleWindsorPlay.ICollector, CastleWindsorPlay"
           type="CastleWindsorPlay.Collector1, CastleWindsorPlay"/>
<component id="Collector2"
           service="CastleWindsorPlay.ICollector, CastleWindsorPlay"
           type="CastleWindsorPlay.Collector2, CastleWindsorPlay"/>
<component id="Collector3"
           service="CastleWindsorPlay.ICollector, CastleWindsorPlay"
           type="CastleWindsorPlay.Collector3, CastleWindsorPlay"/>
<component id="Processor1"
           service="CastleWindsorPlay.IProcessor, CastleWindsorPlay"
           type="CastleWindsorPlay.Processor1, CastleWindsorPlay"/>
<component id="Processor2"
           service="CastleWindsorPlay.IProcessor, CastleWindsorPlay"
           type="CastleWindsorPlay.Processor2, CastleWindsorPlay"/>
<component id="Processor3"
           service="CastleWindsorPlay.IProcessor, CastleWindsorPlay"
           type="CastleWindsorPlay.Processor3, CastleWindsorPlay"/>
<component id="Wrapper1"
           type="CastleWindsorPlay.Wrapper`2[[CastleWindsorPlay.Collector1, CastleWindsorPlay],[CastleWindsorPlay.Processor3, CastleWindsorPlay]], CastleWindsorPlay" />
  </components>

Instantiation

        var wrapper = (Wrapper<ICollector, IProcessor>) container.Resolve("Wrapper1");
        wrapper.GetData();

This brief example errors with this error message though -

Can't create component 'Wrapper1' as it has dependencies to be satisfied. Wrapper1 is waiting for the following dependencies:

Services: - CastleWindsorPlay.Collector1 which was not registered. - CastleWindsorPlay.Processor3 which was not registered.

The curious part about this is that I can get it to resolve Collector1 and Processor3 individually before the call to the wrapper, but the wrapper still can't see them.

This is a basic example, the next thing I'd like to be able to do is when instantiating the Wrapper, set a property on the collector and/or processor. So it could be something like Collector.Id = 10, but set in the config where the wrapper is defined. Setting against the Collector component definition wouldn't work as I'd want to be able to instantiate multiple copies of each Collector, using different Id's

Update 2

What I'm actually trying to do is have -

<components>
<component id="Wrapper1"
           type="CastleWindsorPlay.Wrapper`2[${Collector1}(id=1)],[${Processor3}]], CastleWindsorPlay" />
<component id="Wrapper2"
           type="CastleWindsorPlay.Wrapper`2[${Collector1}(id=3)],[${Processor3}]], CastleWindsorPlay" />
  </components>

Then have another object defined as

<component id="Manager"
           type="CastleWindsorPlay.Manager,CastleWindsorPlay">
  <parameters>
    <wrappers>
      <array>
        <item>${Wrapper1}</item>
        <item>${Wrapper2}</item>
      </array>
    </wrappers>
  </parameters>

Then finally in code just be able to call -

var manager = (Manager)container.Resolve("Manager");

This should return the manager object, with an array of wrappers populated and the wrappers configured with the correct Collector and Convertor.

I know there are errors in the Castle config here, that's why I'm asking the question, I don't know how to set the config up to do what I'm after, or even if it's possible to do it in Castle Windsor

+1  A: 

UPDATE2

Ok it's starting to make sense now :) And like I said from the start, it looks like you're looking for service overrides:

<components>
<component id="Wrapper1" type="CastleWindsorPlay.Wrapper`2[<<closing types go here>>]/>
   <parameters>
      <collector>${collector1WithId1}</collector>
      <collector>${processor3WithId3}</collector>
   </parameters>
</component>

<component id="Wrapper2" type="CastleWindsorPlay.Wrapper`2[<<closing types go here>>]/>
   <parameters>
      <collector>${collector1WithId5}</collector>
      <collector>${processor3WithId8}</collector>
   </parameters>
</component>
</components>

UPDATE

Ok, thanks for the example. The reason why you're getting the error, is that you're registering component Collector1 and component Processor3 as service ICollector and IProcessor respectively. You have no service for Collector1 and Processor3 therefore when Windsor tries to provide them, it can't find them hence the exception message.

You need to register them as appropriate services in order for this to work.


I don't know what you're trying to do here, but I assume you're looking for service overrides and inline parameters

Krzysztof Koźmic
Sorry, service overrides and inline parameters don't answer how to use component id's in the definition of a component using generics, or how to pass parameters to an object passed through generics.
ChoccyButton
hmmmm, interesting. Not sure how to do what I want then, or even if I can with Castle Windsor.The idea is that in the config, I can declare new Wrappers, using Collector and Processor just defined in the config. The only way I can get it to work is to define the Collector in the config, and in the resolve (eg Wrapper<Collector1,Processor3> = resolve etc..). That defeats the object. Second requirement is that I can pass different parameters to each collector defined for the Wrapper. So say Wrapper1 uses Collector1, passing Id=1 to the Collector, Wrapper2 uses Collector1, passing Id=2, etc
ChoccyButton
What I don't understand is - if you want to resolve **classes** `Collector1`, `Processor3` why do you register them as **interfaces**?
Krzysztof Koźmic
I've just said I removed those, it was a mistake. I've added a second update to try again to clear up what I'm actually trying to ask
ChoccyButton
K, think you might have what I'm looking for, I've just been coming at it from the wrong angle by the looks of it. Let me have a quick play with what you've suggested
ChoccyButton
Classic case of can't see the woods for the trees. I didn't need to use generics at all to inject the behaviours into the wrapper, they can easily be passed using services as you've shown in update2. I've updated my play app and it behaves as I was looking for, thanks for your help :)
ChoccyButton