Jean Hibbert's Blog

.NET Framework, SQL Server and other random thoughts.

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.

internal class TypeFinder

    {

        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();

            }

        }

 

        public string[] LoadTypes(string assemblyFilename)

        {

            AppDomain appDomain = AppDomain.CreateDomain("TypeFinder");

            try

            {

                AssemblyReflector ar = (AssemblyReflector)appDomain.CreateInstanceAndUnwrap(typeof(AssemblyReflector).Assembly.FullName, typeof(AssemblyReflector).FullName);

                return ar.LoadTypes(assemblyFilename);

            }

            finally

            {

                AppDomain.Unload(appDomain);

            }

        }

    }