Dynamically loading assemblies for reflection without locking the files.

I was recently asked to write a class which dynamically loaded assemblies, and perform reflection on them, without permanently loading the files into the application domain and without locking the files. Unfortunately, and surprisingly the Assembly.ReflectionOnlyLoadFrom(string filename) method also locks files, which in my opinion defeats the purpose. So I had to fall back on the strategy of loading the assembly into a temporary application domain, reflect on the assembly and unload the application domain thus unlocking the file and unloading it from memory.

By using the LoadTypes method in the TypeFinder class you can query an assembly for a particular attribute.

 

        // The attribute class you are looking for within external assemblies
        private class SomeAttribute : Attribute
        {
        }

        public class TypeFinder
        {

            public string[] LoadTypes(string assemblyFilename)
            {
                AppDomain appDomain = AppDomain.CreateDomain("TypeFinder");
                try
                {
                    // Load and query asseblies in domain and return results
                    AssemblyReflector ar = (AssemblyReflector)appDomain.CreateInstanceAndUnwrap(typeof(AssemblyReflector).Assembly.FullName, typeof(AssemblyReflector).FullName);
                    return ar.LoadTypes(assemblyFilename);
                }
                finally
                {
                    // unload the temporary domain
                    AppDomain.Unload(appDomain);
                }
            }

            /// <summary>
            /// Class used to load and query assemblies within "TypeFinder" Domain
            /// </summary>
            private class AssemblyReflector : MarshalByRefObject
            {
                private IEnumerable<string> EnumerateTypes(string assemblyFilename)
                {
                    Assembly asm = Assembly.LoadFile(assemblyFilename);
                    if (asm == null) throw new Exception("Assembly not found");
                    foreach (Type t in asm.GetTypes())
                    {
                        if (t.GetCustomAttributes(typeof(SomeAttribute), true).FirstOrDefault() != null)
                        {
                            yield return t.AssemblyQualifiedName;
                        }
                    }
                }

                public string[] LoadTypes(string assemblyFilename)
                {
                    return EnumerateTypes(assemblyFilename).ToArray();
                }
            }
        }

 

Published 12 May 2009 06:35 by jean
Filed under:

Comments

No Comments