unity 1.2 open generic types & IChannelFactory

Sep 22, 2010 at 11:21 AM

hi guys,

i'm trying to use unity to resolve an generic instance of the IChannelFactory<ISomeType> to create channels to a service i have written.

My config is as such:         

          <type name="customerChannelFactory"
                type="System.ServiceModel.Channels.IChannelFactory`1[[Namespace.Interfaces.ISomeType, Interfaces], System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
                mapTo="System.ServiceModel.ChannelFactory`1[[Namespace.Interfaces.ISomeType, Interfaces]], System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
            <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
              <constructor>
              </constructor>
            </typeConfig>
          </type>         

The exception i get is that it cannot construct the type because it is an interface, even though the mapping to a concrete type is clearly there. Notice i am trying to constrict the type resolution to specific types so it only works with IChannelFactory<ISomeType> and not IChannelFactory<ISomeOtherType>, for instance. perhaps this isn't the correct way to do things?

Any ideas or pointers what i am doing wrong here peeps? Or perhaps even a solution ;-)

Thanks,

Nick

Sep 22, 2010 at 5:16 PM

Could you show the resolve call that's failing and the full error message & stack trace? My first guess is that you registered with a name and then resolved without it.

 

Sep 24, 2010 at 10:51 AM

We use a wrapper around the UnityContainer, but it effectively just passes the call straight to it:

var factory = IoC.Resolve <IChannelFactory<ISomeType>>();
the exception i am getting is:

Resolution of the dependency failed, type = "IChannelFactory`1", name = "". Exception message is: The current build operation (build key Build Key[System.ServiceModel.Channels.IChannelFactory`1[Namespace.Interfaces.ISomeType], null]) failed: The current type, System.ServiceModel.Channels.IChannelFactory`1[Namespace.Interfaces.ISomeType], is an interface and cannot be constructed. Are you missing a type mapping? (Strategy type Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy, index 2)

 

does that help in the diagnosis?

Sep 24, 2010 at 3:34 PM

Yep.

In your config, you've done the equivalent of this API call:

 

container.RegisterType<IChannelFactory<ISomeType>, ChannelFactory<ISomeType>>("customerChannelFactory", new InjectionConstructor());

Then you resolve by doing this:

container.Resolve<IChannelFactory<ISomeType>>();

You've got a registration with a name, and a resolve without one. If the names don't match it doesn't fall back or anything - they have to be the same.

To fix your problem, do:

container.Resolve<IChannelFactory<ISomeType>>("customerChannelFactory");

or remove the name="" attribute from your registration XML.

 

Sep 24, 2010 at 3:53 PM
Edited Sep 24, 2010 at 3:54 PM

ok thanks for that, it now works :-) However that was the most basic example, and not what i actually needed to do.. What i ideally want to do is to pass in a binding to the constructor as such:

        <type name="customerBinding" type="System.ServiceModel.BasicHttpBinding, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
          <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
            <constructor>
              <param name="configurationName" parameterType="System.String, mscorlib">
                <value value="CustomerAccountService" />
              </param>
            </constructor>
          </typeConfig>
        </type>

I then modify the IChannelFactory config as such, to pass in the binding:

          <type name="customerChannelFactory" 
                type="System.ServiceModel.Channels.IChannelFactory`1[[Namespace.Interfaces.ISomeType, Interfaces]], System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL" 
                mapTo="System.ServiceModel.ChannelFactory`1[[Namespace.Interfaces.ISomeType, Interfaces]], System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
            <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
              <constructor>
                <param name="binding" parameterType="System.ServiceModel.Channels.Binding, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
                  <dependency name="customerBinding" />
                </param>
              </constructor>
            </typeConfig>
          </type>   

And now i get the following exception:

Resolution of the dependency failed, type = "IChannelFactory`1", name = "customerChannelFactory". Exception message is: The current build operation (build key Build Key[System.ServiceModel.ChannelFactory`1[Namespace.Interfaces.ISomeType], customerChannelFactory]) failed: The parameter binding could not be resolved when attempting to call constructor System.ServiceModel.ChannelFactory`1[[Namespace.Interfaces.ISomeType, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]](System.ServiceModel.Channels.Binding binding). (Strategy type Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy, index 2)

I guess this is something to do with how i have registered the binding? My guess is that there is no mapping from interface to concrete class with the binding as no such relationship exists, but i cannot think how else to achieve this (i have tried to achieve with the <instance> node but i cannot directly convert string -> binding, so this was fruitless)

Thanks again for your help, it's very much appreciated

Sep 24, 2010 at 10:44 PM

Yes, the problem is in your mapping for the binding.

You've got this:

<type name="customerBinding" type="System.ServiceModel.BasicHttpBinding...

but you're assigning the parameter as:

parameterType="System.ServiceModel.Channels.Binding...

 

So the container is trying to look up a mapping for Binding, and it doesn't find one (because it isn't there.)

The best solution is probably to modify your registration for the binding to do the type mapping too, like so:

 

<type name="customerBinding" 
  type="System.ServiceModel.Binding, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL" 
  mapTo="System.ServiceModel.BasicHttpBinding, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
  <typeConfig>
    <constructor>
      <param name="configurationName" parameterType="System.String, mscorlib">
        <value value="CustomerAccountService" />
      </param>
    </constructor>
  </typeConfig>
</type>

Also, you can use aliases to shorten those type names, and you don't need the extensionType attribute on the <typeConfig> element if you're just doing standard stuff (what you're using was made the default in Unity 1.20.

That should do the trick.

(And XML config is a lot easier to use in Unity 2. Just sayin'. :-) )

 

 

Sep 27, 2010 at 9:16 AM

i will try this over the coming days (i'm a bit pushed for time at the moment and it is unlikely i'll be able to do it today or tomorrow), but i would like to thank you ever so much for your help :-)

worse yet, we're using unity 1.1 in our apps (EEK! only realised this the other day!). I have full intentions of using unity 2 in future for the cleaner syntax, believe me! Just have to try and get the business to agree for me to spend time on this!

huge thanks again, i'm sure i'll be back with other questions soon enough ;-)