Using a factory method to inject a constructor parameter in Unity

May 15, 2010 at 11:24 AM
Edited May 15, 2010 at 2:22 PM

General problem is: using a factory method to inject a constructor parameter in Unity.

This arises because I need to configure Unity to inject a NHibernate session. Problem is, an instance of a session is the result to a call to a method of a factory object:

 

ISessionFactory sessionFactory = NHConfigurator.CreateSessionFactory();
ISession session = sessionFactory.OpenSession();

How do I inject a new session instance as a constructor parameter for each call to resolve objects that have an ISession as a constructor parameter?

 

May 15, 2010 at 7:38 PM
Giorgio, This used to work in Unity 1.2, at least for basic types (strings, ints, etc): namespace CSW.EAIF.AOP.Extensions { public class MethodCallParameterInjectionElement: InjectionParameterValueElement { #region Protected virtual methods protected virtual Object CreateInstance() { Object configurationValue = this.GetValue(); if ((configurationValue != null) && (this.GetTypeToCreate().IsAssignableFrom(configurationValue.GetType()))) { return (configurationValue); } if (this.GetTypeToCreate() == typeof(String)) { return (configurationValue.ToString()); } TypeConverter converter = this.GetTypeConverter(this.GetTypeToCreate(), this.TypeConverterName, this.TypeResolver); return (converter.ConvertFrom(configurationValue)); } #endregion #region Protected override methods public override InjectionParameterValue CreateParameterValue(Type targetType) { Type type = null; if (String.IsNullOrEmpty(this.TypeName) == true) { type = targetType; } else { type = this.TypeResolver.ResolveType(this.TypeName); } return (new InjectionParameter(type, this.CreateInstance())); } protected override Object GetValue() { Type type = this.GetTargetType(); Object result = null; if (type != null) { Object target = null; MethodInfo mi = type.GetMethod(this.MethodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod); if ((mi != null) && (mi.ReturnType != typeof(void)) && (mi.GetParameters().Length == 0)) { if (mi.IsStatic == false) { target = Activator.CreateInstance(type); } result = mi.Invoke(target, null); } if (target is IDisposable) { (target as IDisposable).Dispose(); } } return (result); } #endregion #region Protected methods protected Type GetTargetType() { return (this.TypeResolver.ResolveType(this.TargetTypeName)); } #endregion #region Public properties [ConfigurationProperty("typeConverter", IsRequired = false, DefaultValue = null)] public String TypeConverterName { get { return ((String) base [ "typeConverter" ]); } set { base [ "typeConverter" ] = value; } } [ConfigurationProperty("typeName", DefaultValue = null)] public String TypeName { get { return ((String) base [ "typeName" ]); } set { base [ "typeName" ] = value; } } [ConfigurationProperty("targetMethodName", IsRequired = true)] public String MethodName { get { return ((String) base [ "targetMethodName" ]); } set { base [ "targetMethodName" ] = value; } } [ConfigurationProperty("targetTypeName", IsRequired = true)] public String TargetTypeName { get { return ((String) base [ "targetTypeName" ]); } set { base [ "targetTypeName" ] = value; } } #endregion #region Protected methods protected TypeConverter GetTypeConverter(Type typeToCreate, String typeConverterName, UnityTypeResolver typeResolver) { if (String.IsNullOrEmpty(typeConverterName) == false) { return ((TypeConverter) Activator.CreateInstance(typeResolver.ResolveType(typeConverterName))); } return (TypeDescriptor.GetConverter(typeToCreate)); } protected Type GetTypeToCreate() { return (this.TypeResolver.ResolveWithDefault(this.TypeName, typeof(String))); } #endregion } } On App.config: ... <unity> <typeAliases> <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <typeAlias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <typeAlias alias="external" type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager, Microsoft.Practices.Unity, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <typeAlias alias="thread" type="Microsoft.Practices.Unity.PerThreadLifetimeManager, Microsoft.Practices.Unity, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </typeAliases> <containers> <container> <extensions> <add type="Microsoft.Practices.Unity.InterceptionExtension.Interception, Microsoft.Practices.Unity.Interception" />--> </extensions> <types> <type type="CSW.EAIF.AOP.ISomeType, CSW.EAIF.AOP" mapTo="CSW.EAIF.AOP.SomeType1, CSW.EAIF.AOP"> <lifetime type="singleton"/> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration"> <constructor> <param name="dependency" parameterType="System.String"> <methodCall elementType="CSW.EAIF.AOP.Extensions.MethodCallParameterInjectionElement, CSW.EAIF.AOP" typeName="System.String" targetTypeName="CSW.EAIF.AOP.Program, CSW.EAIF.AOP" targetMethodName="GetDate"/> ... Regards, Ricardo Peres
May 15, 2010 at 10:12 PM

Thanks Ricardo, but could you post it again putting code in a code snippet tag?

May 16, 2010 at 2:08 AM

This is pretty trivial - use the factory support in the container. I don't know NHibernate, so there's probably details about object lifetime you'll have to tweak.

container.RegisterType<ISession>(
    new InjectionFactory(c => {
        ISessionFactory sessionFactory = NHConfigurator.CreateSessionFactory();
        return sessionFactory.OpenSession();
    });

May 16, 2010 at 2:24 PM

Thank you Chris!

It works and looks good too! (looks better then Castle Windsor, IMHO ;) )

I used a simple custom lifetime manager that keeps objects in HttpContext.Current.

I'll post the details of the solution on my blog.

Thanks again,

Giorgio

May 16, 2010 at 8:47 PM

Complete solution at: http://letsfollowtheyellowbrickroad.blogspot.com/2010/05/nhibernate-sessions-in-aspnet-mvc.html