Assembly Loading its own external validation.xml configuration?

Sep 18, 2007 at 5:43 PM
Edited Sep 18, 2007 at 5:44 PM
I am wondering if there is some method whereby the external validation configuration file for a domain class assembly can be loaded by the assembly itself rather than having to rely on some sort of application startup code.

For sake of discussion, lets say I have an assembly called DomainObjects inside which are the Person and Department classes. Colocated in the filesystem with that assembly I would like to have a DomainObjects.validation.xml file. When the assembly is loaded, I would like the validation configuration for that assembly to be loaded.

I should also be able to set up multiple assemblies this way, with each loading their own validation.xml file.

I would like to maintain the .xml file outside of the assembly rather than embedding it.

Doable?

Thanks
Rich


Coordinator
Sep 19, 2007 at 1:59 AM
Edited Sep 19, 2007 at 2:01 AM
Unfortunately what you want to do is limited (at least as far as i know) by the restrictions of the .net framework. I know of no way, without external code, for an assembly to be aware of itself when it is first loaded into memory. So now you move onto what is the minimum external code you need.

You could place some code in your application startup that listens to AppDomain.AssemblyLoad events. When this fires you could then load the validation for that assembly. You would derive the validation xml file name from the Assembly.Location. Unfortunately this would only work if you are dynamically loading assemblies. In the common scenario you program would reference you business assembly (in your case DomainObjects). Hence as soon as your program assembly loads, and before you get to attach to the Load event, your business assembly would load. If, however, you are using dynamic assembly loading the Assembly.Load would work. Some examples of dynamic assembly loading are using CAB, you have a proxy program that launches your application or you are using some kind of plugin based architecture.

Your other option is to make use of the fact that a type knows when it is first loaded. You do this through a static constructor on the type. It is fired once per type per appdomain. So if you place one line in the static constructor of each of your types you can get the desired effect. Each of those calls would pass a type, check if the assembly for that type has been loaded, if not then load the validation for that assembly.

Code for loading the validation
using System;
using System.Collections.Generic;
using System.IO;
using ValidationFramework.Configuration;
 
namespace ConsoleApplication1
{
    public static class AssemblyValidationLoader
    {
        private static readonly List<string> loadedAssemblies;
        static AssemblyValidationLoader()
        {
            loadedAssemblies = new List<string>();
        }
 
        public static void Load(Type type)
        {
            string location = type.Assembly.Location;
            if (!loadedAssemblies.Contains(location))
            {
                string pathWithoutExtension = location.Remove(location.Length - 3, 3);
                string configFilePath = pathWithoutExtension + "validation.xml";
                if (File.Exists(configFilePath))
                {
                    ConfigurationService.AddXmlFile(configFilePath);
                }
                loadedAssemblies.Add(location);
            }
        }
    }
}

Code for a business object
namespace ConsoleApplication1
{
 
    public class Person
    {
 
        static Person()
        {
            AssemblyValidationLoader.Load(typeof(Person));
        }
 
        private string name;
        private int age;
 
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
 
        public int Age
        {
            get
            {
                return age;
            }
            set
            {
                age = value;
            }
        }
    }
}

Xml validation file (in this case would be named "ConsoleApplication1.validation.xml")
<?xml version="1.0" encoding="utf-8" ?>
<validationMapping xmlns="urn:validationFramework-validationDefinition-1.5">
  <class typeName="ConsoleApplication1.Person, ConsoleApplication1">
    <property name="Name">
      <rule typeName="RequiredStringRuleConfigReader" initialValue="aaaa"/>
    </property>
    <property name="Age">
      <rule typeName="RangeRuleConfigReader" minimum="18" maximum="80" errorMessage="Age is invalid" />
      <rule ruleSet="a" typeName="RangeRuleConfigReader" minimum="18" maximum="80" errorMessage="Age is invalid" />
      <rule ruleSet="b" typeName="RangeRuleConfigReader" minimum="18" maximum="80" errorMessage="Age is invalid" />
    </property>
  </class>
</validationMapping>
Note: you can put the validation for multiple types in the xml by having multiple "class" nodes.

Let me know if you find a better solution.

Regards

Simon
Sep 21, 2007 at 8:05 AM

{quote}
SimonCropp wrote:
Unfortunately what you want to do is limited (at least as far as i know) by the restrictions of the .net framework.,,,

Thanks for such an informative response. The static constructor is perfectly fine. If I recall this a fairly popular method also used by log4j/log4Net.

I'm surprised .NET doesn't seem to have an assembly load event. .NET is so interface and event driven, you would think that event would have been rather obvious to include.