Is there a way to look up a value in the appSettings?

May 8, 2009 at 9:10 PM

Hello,

I am using Unity and sometimes I would like to use a value which is defined in the <appSettings> section of the config file for the value of a parameter.

This provides a separation between the environment-specific config and the unity logic.

Is there a way to look up a value in appSettings from unity config section ?

The "TypeConverter" solution (see below) doesn't seem to work when the type to convert to is a string. My converter which looks up the value is never called.

Thanks for your suggestions.

--------------------------------------------------

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

  <configSections>
    <section name="unity"
              type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
                 Microsoft.Practices.Unity.Configuration, Version=1.2.0.0,
                 Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  </configSections>

  <appSettings>
    <add key="address" value="127.0.0.1" />
  </appSettings>

  <unity>
    <containers>
      <container>
        <types>
          <type type="Connection" name="Connection" >
            <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement,
                                     Microsoft.Practices.Unity.Configuration">
              <constructor>
                <param name="Address" parameterType="System.String">
                  <value value="Address" type="System.String" typeConverter="Test.AppSettingTypeConverter, Test"/>
                </param>
              </constructor>
            </typeConfig>
          </type>
      </container>
    </containers>
  </unity>

</configuration>

 

May 12, 2009 at 3:21 PM

In the Microsoft.Practices.Unity.Configuration.InstanceValueElement class, in the CreateInstance() method, I commented out the following lines:

            //if (TypeToCreate == typeof(string))
            //{
            //    return Value;
            //}

and my converter is now called.

I had to rebuild Unity of course...

 

May 13, 2009 at 2:21 PM

Another way to handle this is to implement IDependencyResolverPolicy and a couple of configuration classes so you can declare it like:

<type type="MyLibrary.InjectedType,MyLibrary">
    <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement,Microsoft.Practices.Unity.Configuration">
        <constructor>
            <param name="theParam" parameterType="System.String">
                <appSettingValue key="anAppSettingKey" elementType="MyUnityLibrary.AppSettingParameterValueElement, MyUnityLibrary" />
            </param>
        </constructor>
    </typeConfig>
</type>

This would resolve the dependency for the parameter by retrieving the appSetting value for key "anAppSettingKey", first converting the value to the type of the parameter. This does not require modification of the Unity code.

I have created a similar set of classes for the connectionStrings values. This has greatly simplified configuring our applications -- it is much easier to hunt down and change an appSetting or configurationString than it is to wade through the Unity configuration.

Hope this helps.

 AppSettingParameterValueElement.cs ---

using System.Text;
using System.Configuration;
using Microsoft.Practices.Unity.Configuration;
using Microsoft.Practices.Unity;

namespace MyUnityLibrary
{
    public class AppSettingParameterValueElement : InjectionParameterValueElement
    {
        /// <summary>
        /// Key of the appSetting to resolve.
        /// </summary>
        [ConfigurationProperty("key", IsRequired = true)]
        public string Key
        {
            get { return (string)this["key"]; }
            set { this["key"] = value; }
        }

        /// <summary>
        /// Type of the dependency to resolve.
        /// </summary>
        [ConfigurationProperty("type", IsRequired = false, DefaultValue = null)]
        public string TypeName
        {
            get { return (string)this["type"]; }
            set { this["type"] = value; }
        }

        public override InjectionParameterValue CreateParameterValue(Type targetType)
        {
            Type dependencyType;
            if (string.IsNullOrEmpty(TypeName))
            {
                dependencyType = targetType;
            }
            else
            {
                dependencyType = TypeResolver.ResolveType(TypeName);
            }
            return new AppSettingParameterValue(dependencyType, Key);
        }
    }
}

 

AppSettingParameterValue.cs --

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

namespace MyUnityLibrary
{
    public class AppSettingParameterValue : InjectionParameterValue
    {
        #region Constructors
        public AppSettingParameterValue(Type type, string key)
        {
            Type = type;
            Key = key;
        }
        #endregion

        #region Member Properties
        private Type Type { get; set; }
        private string Key { get; set; }
        #endregion

        #region InjectionParameterValue Implementation
        public override IDependencyResolverPolicy GetResolverPolicy()
        {
            return new AppSettingParameterResolver(Type, Key);
        }

        public override Type ParameterType
        {
            get { return Type; }
        }
        #endregion
    }
}

 

AppSettingParameterResolver.cs --

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ObjectBuilder2;
using System.ComponentModel;

namespace MyUnityLibrary
{
    public class AppSettingParameterResolver : IDependencyResolverPolicy
    {
        #region Contructors
        public AppSettingParameterResolver(Type type, string key)
        {
            Type = type;
            Key = key;
        }
        #endregion

        #region Property Members
        private string Key { get; set; }
        private Type Type { get; set; }
        #endregion

        #region IDependencyResolverPolicy Members
        public object Resolve(IBuilderContext context)
        {
            var value = System.Configuration.ConfigurationManager.AppSettings[Key];
            var converter = TypeDescriptor.GetConverter(Type);
            return converter.ConvertFromInvariantString(value);
        }
        #endregion
    }

May 14, 2009 at 9:06 PM

That's definitely a much better solution than my hack.

Thanks for posting.

Feb 3, 2010 at 10:16 AM

Hi, swheaton!

It is possible to do the same for properties (not constructor arguments)?

From what I've seen in the Unity configuration file schema, it doesn't allow custom elements in the <property> tag. Is it not so?

Thanks,

RP

Feb 3, 2010 at 5:42 PM

It seems to work if you ignore the documentation. The config looks like:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<configSections>
		<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
	</configSections>
	<unity>
		<typeAliases>
			<typeAlias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager,Microsoft.Practices.Unity" />
		</typeAliases>
		<containers>
			<container>
				<types>
					<type name="InjectedClass" type="DemoUnity.AppSettingParameterValueElement.InjectedClass, DemoUnity.AppSettingParameterValueElement">
						<lifetime type="transient" />
						<typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
							<constructor/>
							<property name="IntProperty" propertyType="System.Int32">
								<appSettingValue key="injectionProperty" elementType="MyUnityLibrary.AppSettingParameterValueElement, DemoUnity.AppSettingParameterValueElement" />
							</property>
						</typeConfig>
					</type>
				</types>
				<instances>
				</instances>
			</container>
		</containers>
	</unity>
	<appSettings>
		<add key="injectionProperty" value="123"/>
	</appSettings>
</configuration>

The client code looks like:

            using (var container = new UnityContainer())
            {
                var configSection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
                configSection.Containers.Default.Configure(container);

                var injected = container.Resolve<InjectedClass>("InjectedClass");
            }

And the injected class is pretty simple:

namespace DemoUnity.AppSettingParameterValueElement
{
    public class InjectedClass
    {
        public int IntProperty { get; set; }
    }
}

hth!

 

Feb 3, 2010 at 7:02 PM

You're right, thanks!

It means, though, that the published schema for Unity 1.2 is wrong! :-(

RP