Register type with more than one name

Oct 30, 2011 at 10:43 PM

Is it possible to configure the unity XML file with a "regular" register element, such as:

<configuration>

  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <alias alias="ILogger" type="MyApp.ILogger, MyApp" />
    <namespace name="MyApp.Implementations" />
    <assembly name="MyApp" />
    
    <container>
      <register type="ILogger" name="special" mapTo="SpecialLogger" />    
    </container>

  </unity>

</configuration>

But, in addition to a successful "Resolve<ILogger>("special") invocation, I'd like to have the same resolve to Resolve<ILogger>("foo").

I know I can copy-paste the elements like so:

<register type="ILogger" name="special" mapTo="SpecialLogger" />
<register type="ILogger" name="foo" mapTo="SpecialLogger" />

 

But then I repeat myself. Think about a complex scenario (constructor, dependency by name, etc.) - I'll have to duplicate the configuration code, and then I violate the DRY principle.

I thought about a config block that goes like this:

<register type="ILogger" name="special" mapTo="SpecialLogger" />
<register type="ILogger" name="foo" mapToName="special" />
Is it possible in Unity 2.0?

Oct 31, 2011 at 2:42 AM

As far as I know this approach is not currently supported.  I find that when dealing with configuration there can be quite a bit of duplication.  If you have complicated scenarios perhaps a code based approach where you can reuse common objects would be better.  I guess it all comes down to how much you value the runtime flexibility of configuration files.

 

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com

Oct 31, 2011 at 1:29 PM

That's not good news :-(

I'll add a feature request if there's a wishlist somewhere...

Nov 1, 2011 at 6:21 PM

Apperently this can be done with extentions and InjectionFactory.

I created a new element called addRegister that can be used as follows:

 

<unity>
    <sectionExtension type="MyNameSpace.NameMapingExtention,MyAssembly" />
    
    <container>
      <register name="instance1" type="IWorker" mapTo="WorkerImpl1">
        <constructor>
          <param name="data" value="first worker"/>
        </constructor>
      </register>
      <addRegister name="instance2" type="IWorker" dependencyName="instance1"/>
      <addRegister name="instance3" type="IWorker" dependencyName="instance2"/>
    </container>
  </unity>

 

The Implementation is as follows:

class NameMapingExtention : SectionExtension
    {
        public override void AddExtensions(SectionExtensionContext context)
        {
            context.AddElement<NameMappingElement>("addRegister");
        }
    }

    class NameMappingElement : ContainerConfiguringElement
    {
        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get { return (string)base["name"]; }
            set { base["name"] = value; }
        }

        [ConfigurationProperty("dependencyName", IsRequired = true, IsKey = true)]
        public string DependencyName
        {
            get { return (string)base["dependencyName"]; }
            set { base["dependencyName"] = value; }
        }

        [ConfigurationProperty("type", IsRequired = true, IsKey = true)]
        public string TypeName
        {
            get { return (string)base["type"]; }
            set { base["type"] = value; }
        }

        protected override void ConfigureContainer(IUnityContainer container)
        {
            Type registeringType = GetRegisteringType();
            container.RegisterType(registeringType, Name, new InjectionFactory(c=>c.Resolve(registeringType, DependencyName)));
        }

        private Type GetRegisteringType()
        {
            if (!string.IsNullOrEmpty(TypeName))
            {
                return TypeResolver.ResolveType(TypeName);
            }
            return null;
        }

class NameMapingExtention : SectionExtension
    {
        public override void AddExtensions(SectionExtensionContext context)
        {
            context.AddElement<NameMappingElement>("addRegister");
        }
    }

    class NameMappingElement : ContainerConfiguringElement
    {
        [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
        public string Name
        {
            get { return (string)base["name"]; }
            set { base["name"] = value; }
        }

        [ConfigurationProperty("dependencyName", IsRequired = true, IsKey = true)]
        public string DependencyName
        {
            get { return (string)base["dependencyName"]; }
            set { base["dependencyName"] = value; }
        }

        [ConfigurationProperty("type", IsRequired = true, IsKey = true)]
        public string TypeName
        {
            get { return (string)base["type"]; }
            set { base["type"] = value; }
        }

        protected override void ConfigureContainer(IUnityContainer container)
        {
            Type registeringType = GetRegisteringType();
            container.RegisterType(registeringType, Name, new InjectionFactory(c=>c.Resolve(registeringType, DependencyName)));
        }

        private Type GetRegisteringType()
        {
            if (!string.IsNullOrEmpty(TypeName))
            {
                return TypeResolver.ResolveType(TypeName);
            }
            return null;
        }
Nov 1, 2011 at 11:35 PM

@RenanaYacobi, thanks for the cool solution!

However, I think I'd name the element as "registerAlias" or something like that, since other elements sound more like nouns, and your naming suggestion, "addRegister", is more like a verb.

But that's just cosmetics.

Great work!