Injecting application instance variable using unity

Sep 23, 2009 at 2:31 PM

Hi, I'm looking at crating objects via unity(with some dependency) where I can push some instance variable into its constructer which are not registered with unity. For example in below code, when I ask unity to create classA it is erroring  out. Are there any ways to archive this simple requirements with uniy. Currently I'm having some properties in classA to set some variable values as work around

 UnityContainer container = new UnityContainer();
           
            container.RegisterType<classA>();
            container.RegisterType<classB>();
            int value = 100;
            classA a = container.Resolve<classA>(); // here i want to send some value into constructer. Are there any methods to achive this?

public class classA
    {
        
        classB _b;
        int _i;
        public classA(classB b,int i)
        {
            _b = b;
            _i = i;
        }
       
    }
    public class classB
    {
        
    }
Sep 25, 2009 at 12:34 AM

Hello ,I can recommend you to do this via configuration if you find this suited for your needs.Here's how:

Suppose you have a main contract you're classA needs to implement.Just to show this implementation works the contract will have the following method:

 

public interface IContract
{
int increment();
}


now your classes ClassA and ClassB :

 class ClassA : IContract
{
private int a;
private ClassB b;
public ClassA(ClassB b, int a)
{
this.a = a;
this.b = b;
}

#region IContract Members

public int increment()
{
return a + 1;
}

#endregion
}


class ClassB
{
public ClassB()
{

}


}

for the sake of simplicity ClassB does not implement any contract nor does it do something special

you can add a config file with the name "unity.config" or whatever name you want ( i find it useful to have a separate config file just for unity )

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<configSections>

 

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

 

</configSections>

 

 

<unity>

 

<typeAliases>

<typeAlias alias="string" type="System.String, mscorlib" />

<typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />

<typeAlias alias="IContract" type ="Contracts.IContract, Contracts" />

</typeAliases>

 

<containers>

<container name="container">

<types>

<type type="IContract" mapTo="UnityTest.ClassA, UnityTest">

<typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">

<constructor>

 

<param name="b" parameterType="UnityTest.ClassB, UnityTest" >

<dependency/>

</param>

 

 

<param name="a" parameterType="System.Int32" >

<value value="1" type="System.Int32"/>

</param>

</constructor>

</typeConfig>

 

</type>

</types>

</container>

</containers>

 

</unity>

</configuration>

 

with this configuration file you can resolve the type ClassA like this :

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
using System.Configuration;
using Microsoft.Practices.Unity.Configuration;
using Contracts;


namespace UnityTest
{
class Program
{
static void Main(string[] args)
{
IUnityContainer container = GetContainer();
var ClassAResolved = container.Resolve();

Console.WriteLine(ClassAResolved.increment());
Console.ReadKey();
}

private static IUnityContainer GetContainer()
{
var map = new ExeConfigurationFileMap();
map.ExeConfigFilename = "unity.config";
 var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
var section = (UnityConfigurationSection)config.GetSection("unity");
var container = new UnityContainer();


section.Containers["container"].Configure(container);
return container;
}
}
}

if your container is not named unity.config you can just change it's name to 

map.ExeConfigFilename = "whatever.config"; Also make sure your config file is in the same directory as the executable or else 
section.Containers["container"].Configure(container) will throw a null object exception

To show it works, the ClassA type is resolved and it outputs the correct number 2 as a result of the incrementation of int 1 passed in the configuration file.

I hope this helps,

 

Doru.

Sep 25, 2009 at 12:53 AM

Or directly from code if you don't feel like a configuration-man

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
using System.Configuration;
using Microsoft.Practices.Unity.Configuration;
using Contracts;


namespace UnityTest
{
    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            ClassB b = new ClassB();
            int val = 1;
            container.RegisterType<IContract, ClassA>().Configure<InjectedMembers>().
              ConfigureInjectionFor<ClassA>(new InjectionConstructor(new object[] { b, val }));
            var ClassAResolved = container.Resolve<IContract>();
            Console.WriteLine(ClassAResolved.increment());
            Console.ReadKey();
        }
    }
}

 

with the following specification : you need to change you ClassA from the previous example like this :

 

class ClassA : IContract
    {
        private int a;
        private ClassB b;

        [InjectionConstructor()]
        public ClassA(ClassB b, int a)
        {
            this.a = a;
            this.b = b;
        }

        #region IContract Members

        public int increment()
        {
            return a + 1;
        }

        #endregion
    }

 

You add the [InjectionConstructor()] attribute to the constructor of your ClassA type to specify to unity that the these dependencies will be injected

Sep 25, 2009 at 12:22 PM

Hi Doru; many thanks for your response. Looks this as what I’m looking at. Further in my project I need to inject common overseeing controller object instance to most of the views, presenters and preseantermodels so that controller can co-ordinate views creation. I'm on vacation next week, will try out this once I’m back to work.

Regards,

Ram