Matchingrules through configuration

Oct 23, 2008 at 1:27 AM
I am trying to translate the following code into a config file

.AddMatchingRule(new PropertyMatchingRule("*", PropertyMatchingOption.Set))
.AddMatchingRule(new CustomAttributeMatchingRule(typeof(DirtyAttribute), true))

So far I have the following config below. For the SetPropertyRule it works fine, but I have no idea how to pass the Type of DirtyAttribute to the DirtyAttributeRule through configuration.

 <policy name="DirtyPolicy">
    <matchingRules>
        <matchingRule name="SetPropertyRule" type="PropertyMatchingRule">
            <injection>
                <constructor>
                    <param name="propertyName" parameterType="string">
                        <value value="*"/>
                    </param>                                                
                    <param name="option" parameterType="int">
                        <value value="1" type="PropertyMatchingOption"/>
                    </param>
                </constructor>
            </injection>
        </matchingRule>                  
        <matchingRule name="DirtyAttributeRule" type="CustomAttributeMatchingRule">
            <injection>
                <constructor>
                    <param name="attributeType" parameterType="Type">
                        <value value="????"/>
                   </param>
                    <param name="inherited" parameterType="bool">
                        <value value="true"/>
                    </param>
                </constructor>
            </injection>
        </matchingRule>                  
    </matchingRules>
</policy>
Oct 23, 2008 at 2:22 AM
You need a TypeConverter that will read a string and generate the appropriate type object. Check out the unit tests for configuration, there's a few examples of using TypeConverters in there.
I'll cook up a better example tomorrow hopefully.


Oct 23, 2008 at 12:43 PM
Thanx for the tip! I created two TypeConverters and now it works. Would it not be usefull to have such converters as part of the unity block?
Below you find the resulting code and config file:

public class PropertyMatchingOptionConverter : System.ComponentModel.TypeConverter
{
    public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        return (PropertyMatchingOption)Enum.Parse(typeof(PropertyMatchingOption), value.ToString());            
    }
}

public class GetTypeConverter : System.ComponentModel.TypeConverter
{
    public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {            
         return Type.GetType(value.ToString());         
    }
}

<policy name="DirtyPolicy">
    <matchingRules>
        <matchingRule name="SetPropertyRule" type="PropertyMatchingRule">
            <injection>
                <constructor>
                    <param name="propertyName" parameterType="string">
                        <value value="*"/>
                    </param>
                    <param name="option" parameterType="PropertyMatchingOption">
                        <value value="Set" type="PropertyMatchingOption" typeConverter="PropertyMatchingOptionConverter"/>
                    </param>
                </constructor>
            </injection>
        </matchingRule>                                   
        <matchingRule name="DirtyAttributeRule" type="CustomAttributeMatchingRule">
            <injection>
                <constructor>
                    <param name="attributeType" parameterType="Type">
                        <value value="SampleApp.DirtyAttribute, SampleApp" type="Type" typeConverter="GetTypeConverter"/>
                    </param>
                    <param name="inherited" parameterType="bool">
                        <value value="true" type="bool"/>
                    </param>
                </constructor>
            </injection>
        </matchingRule>
    </matchingRules>
</policy>

Jan 19, 2009 at 8:31 PM
Edited Jan 19, 2009 at 8:32 PM

I am trying to use the typeConverter to simplify my config files. I want to create a typeConverter to retrieve values from the appSettings for a couple of reasons:

  • I would like to pull the environment-specific settings out of the unity configuration sections to simplify deployment for our system admins
  • I would like to use EntLib's delta configuration feature to automate generation of the environment-specific configs -- which works on appSettings but not Unity config.

I would like to do something like:

 

 

 

public class MyAppSettingConverter : TypeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        
return ConfigurationManager.AppSettings[value.ToString()];
    }
}

 

 

 

Using a configuration like:

 <

configuration>
    <
configSections>
        <
section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
    </
configSections>
    <
unity>
        <
containers>
            <
container>
                <
instances>
                    <add name="myInstanceOfStringAsAppSetting" type="System.String" value="appSettingKey" typeConverter="UnityUsingTypeConverterDemo.MyAppSettingConverter, UnityUsingTypeConverterDemo" />
                </
instances>
            </
container>
        </
containers>
    </
unity>
    <
appSettings>
        <
add key="appSettingKey" value="Here is the value I really want to use!"/>
    </
appSettings>
</
configuration>

 

 

 

 

 

 

My converter never gets called, though -- my configuration seems to be ignored for string to string conversions (despite my fervent wishes).

Thanks for you attention!

Jan 20, 2009 at 3:53 AM
Edited Jan 20, 2009 at 8:24 AM
I tried to repro your solution and I was able to get my typeconverter to work.  Could you post your code on how did you configure your container and your call to resolve the instance?


Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com


Jan 20, 2009 at 12:57 PM
Edited Jan 20, 2009 at 1:05 PM
Here is the code and config file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;
using System.ComponentModel;
using System.Globalization;

namespace UnityUsingTypeConverterDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            var container = new UnityContainer();
            var config = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            config.Containers[0].Configure(container);

            // Correctly returns 2
            var instanceOfInt = container.Resolve<int>("instanceOfInt");

            // Correctly returns 3
            var myInstanceOfInt = container.Resolve<int>("myInstanceOfInt");

            // I want it to return "HERE IS A STRING VALUE!" but returns "Here is a string value!"
            var myInstanceOfString = container.Resolve<string>("myInstanceOfString");

            // I want it to return "Here is the value I really want to use!" but returns "appSettingKey"
            var myInstanceOfStringAsAppSetting = container.Resolve<string>("myInstanceOfStringAsAppSetting");
        }
    }

    public class MyInt32Converter : TypeConverter
    {
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            return int.Parse(value.ToString());
        }
    }

    public class MyUpperStringConverter : TypeConverter
    {
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            return value.ToString().ToUpper(culture);
        }
    }

    public class MyAppSettingConverter : TypeConverter
    {
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            return ConfigurationManager.AppSettings[value.ToString()];
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  </configSections>
  <unity>
    <containers>
      <container>
       <instances>
          <add name="instanceOfInt" type="System.Int32" value="2" typeConverter="System.ComponentModel.Int32Converter, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
          <add name="myInstanceOfInt" type="System.Int32" value="3" typeConverter="UnityUsingTypeConverterDemo.MyInt32Converter, UnityUsingTypeConverterDemo" />
          <add name="myInstanceOfString" value="Here is a string value!" typeConverter="UnityUsingTypeConverterDemo.MyUpperStringConverter, UnityUsingTypeConverterDemo" />
          <add name="myInstanceOfStringAsAppSetting" type="System.String" value="appSettingKey" typeConverter="UnityUsingTypeConverterDemo.MyAppSettingConverter, UnityUsingTypeConverterDemo" />
        </instances>
      </container>
    </containers>
  </unity>
  <appSettings>
    <add key="appSettingKey" value="Here is the value I really want to use!"/>
  </appSettings>
</configuration>



I tried sneaking up on the problem by creating a couple of different converters.
Thanks!!!

 

 

 

Jan 21, 2009 at 2:55 AM

Hi ,

Sorry,  I was missing something when I tried out your solution, my mistake.  It indeed doesn't work.  I haven't checked out the source code yet but by trying to specify different types for the instance, I was able to confirm that only if you use the System.String type, it is the only time the typeconverter doesn't get called.  It makes sense because if you don't specify the type, by default, it will be considered of type string.  I think you may have to resort to register the instances via code.


Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com