Problem with injecting multiple instances of an interface

Jun 10, 2009 at 8:47 PM
Edited Jun 10, 2009 at 9:12 PM

I'm trying to set up an object which has two arguments to its constructor.  Both arguments are the same interface, "IDataSource", and I would like to inject two different instances of the same concrete class, "LocalRcxmlDataSource", which implements "IDataSource".  Unfortunately, when I using the following configuration, I get the "can't instantiate an interface, are you missing a type mapping" error:

                    <type name="Crawler" type="Seahorse.Crawler">
                        <typeConfig>
                            <constructor>
                                <param name="dataSource" parameterType="Seahorse.IDataSource">
                                    <dependency name="LocalSource"/></param>
                                <param name="dataTarget" parameterType="Seahorse.IDataSource">
                                    <dependency name="LocalTarget"/></param>
                            </constructor>
                        </typeConfig>
                    </type>

                    <type type="Seahorse.IDataSource" mapTo="Seahorse.LocalRcxmlDataSource" name="LocalSource">
                        <typeConfig><!-- Define some properties... --></typeConfig>
                    </type>

                    <type type="Seahorse.IDataSource" mapTo="Seahorse.LocalRcxmlDataSource" name="LocalTarget">
                        <typeConfig><!-- Define some properties... --></typeConfig>
                    </type>

Hmm.  Maybe I need to include the generic mapping before I can use these named ones.  So, I add the following:


                    <type type="Seahorse.IDataSource" mapTo="Seahorse.LocalRcxmlDataSource"/>

 

Well... that *seems* better (no errors during instantiation), except that both the "dataSource" and "dataTarget" parameter have been injected with completely clean instances of "LocalRcxmlDataSource".  In particular, neither instance has the parameters specified in the named types for "LocalSource" and "LocalTarget".  After reading and re-reading the documentation and the forums here, I'm still completely baffled.  Does anyone have any advice?

Jun 10, 2009 at 9:07 PM
Edited Jun 10, 2009 at 9:12 PM

After a bit more reading, I tried to switch to having multiple "typeConfig" elements instead of multiple "type" mappings:

                    <type type="Seahorse.IDataSource" mapTo="Seahorse.LocalRcxmlDataSource">
                        <typeConfig name="LocalSource"><!-- Define some properties... --></typeConfig>
                        <typeConfig name="LocalTarget"><!-- Define some properties... --></typeConfig>
                    </type>

Unfortunately, this resulted in a parse error, despite being explictly called out in the documentation as correct[1]

                     Unexpected Exception: (ConfigurationErrorsException) Unrecognized attribute 'name'. Note that attribute names are case-sensitive.

 

[1] http://msdn.microsoft.com/en-us/library/dd203230.aspx#config_typeconfig

Jun 11, 2009 at 7:56 AM

It would help if you posted your full configuration for typemappings.  Anyway, let's say your IDataSource implementations both have a single parameter named "dataSource" in their constructor of type string, your type mapping should look like:

 <type type="Seahorse.IDataSource, Searhorse" mapTo="Seahorse.LocalRcxmlDataSource, Searhorse" name="LocalSource">
         <typeConfig>
                <constructor>
                         <param name="dataSource" parameterType="System.String">
                                    <value value="Local Source String"/></value>
                </constructor>
          </typeConfig>
</type>

 <type type="Seahorse.IDataSource, Searhorse" mapTo="Seahorse.LocalRcxmlDataSource, Searhorse" name="LocalTarget">
         <typeConfig>
                <constructor>
                         <param name="dataSource" parameterType="System.String">
                                    <value value="Local Target String"/></value>
                </constructor>
          </typeConfig>
</type>

Is this what you have before?  What are the parameters to your LocalRcxmlDataSource constructor?  If it's a class or an interface, it should have a corresponding type mapping in the unity configuration in order for the container to resolve those parameters.

 

Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.

entlib.support@avanade.com

 

Jun 11, 2009 at 7:04 PM

Thanks, Sarah!  Actually, Chris provided the answer offline...   The problem was that my code was asking for the "Crawler" type with no name, but my XML only contained a definition of "Crawler" named "Crawler".  The engine didn't find anything named "Crawer, null", so it just created a new instance.  That new instance didn't have the "dependency" tags to help it resolve the "IDataSource", and therefore it was giving me that error.

I further verified (by reading the code), that the "typeConfig" element does not accept a "name" attribute (which Chris also confirmed).  My remaining question (of much lower urgency) is: "Why would a 'type' tag have multiple 'typeConfig' tags, and how would you access one or the other?"

Jun 12, 2009 at 8:02 AM

The <typeConfig> tag is actually an extension point. If you wanted to provide custom configuration information associated with a type (if you're writing a custom extension, for example), you could implement the right configuration element and then specify the type of element in the type attribute of the <typeConfig> tag.

This is actually how it's implemented under the hood, but we default to the element that lets you specify injection settings if you don't put any type in.

-Chris