Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Reflection: Get list of types from assembly 1

Status
Not open for further replies.

MadJock

Programmer
May 25, 2001
318
GB
Hi,

I would like to get a list of public types that are in an assembly. The complicating factor is that I do not wish to load the assembly into my AppDomain as I will never execute it.

Reason for this is I have a system with aplugin architecture. I'm building a UI for support staff where the can push a new plugin (assembly) onto the production system. As part of this, the UI should read the types from the assembly so that the support staff can enter into the database config items required for each type.

Hope this makes sense! Any help appreciated!

Thanks,

Graeme

"Just beacuse you're paranoid, don't mean they're not after you
 
i want to find out the information in a book, but don't want to pick it up or open it."

i guess it could be done, but it seems a lot of bother when there's such an easy way of doing it.


mr s. <;)

 

Unless I'm missing something - there is no easy way of doing it. The 'staging area' where the DLL is loaded into will not contain the dependiencies that the DLL needs. Also the DLL will then be moved to the production server - so I cannot load the assembly into the main AppDomain (won't load without dependencies and cannot lock the DLL file).

Am I missing something?

"Just beacuse you're paranoid, don't mean they're not after you
 
so you want to reflect the types in a dll which is passing by on its own on the way to somewhere else.

why don't you have the dependencies, again?

why is my spider sense tingling?


mr s. <;)

 
>why don't you have the dependencies, again?

The support user will use a Web UI to 'upload' the assembly (along with any newly added dependencies) provided by the developer.

The assembly will reference other assemblies (such as it's base type) which will not be found on the server the Web UI runs on.

After some config, the web ui will then push the new assemblies to the plugin folder on the production server. This folder will contain all dependencies the plugin needs.

I would like to allow the support user to be presented with a list of classes so they can add data to the database. (e.g. any instance of class 'Person' will require a setting called 'Name' it it's config file)

"Just beacuse you're paranoid, don't mean they're not after you
 
which will not be found on the server the Web UI runs on

why not?

support user to be presented with a list of classes

which they already have...





mr s. <;)

 
misterstick - any useful help on original problem would be greatly appreciated. I don't intend to go through the problem domain again justifying decisions.

"Just beacuse you're paranoid, don't mean they're not after you
 
MadJock - have you looked at the Plugin Pattern?

You should be creating an API for your plugins to work with. This means that you are expecting to find a pre-determined type inside each assembly you are trying to load - typically an interface.

If I'm trying to load tools into a toolbar, I create an iTools interface where the DLL MUST implement this interface. I can then go to the DLL and tell it to give me an iTools class.

You have to provide your plugins some form of data layer. You can't have a plugin sitting in a folder with absolutely no concept of data or else it will be useless.

Google "Plugin Pattern C#" and you will see what I mean.

 
i'm finding it difficult to engage with your question since it seems the problems you are having are to do with design choices you yourself have made.

if you make different choices your problem goes away.

mr s. <;)

 
JurkMonkey,

Thanks for suggestions. When the plugin is 'pushed' (i.e. moved) to the production environment, it will have all dependencies (including the assembly that holds the interfaces it implements).

In the staging location mentioned above, it will not be executed. For this reason I want to avoid having to copy all the dependencies to the staging location:

- It is unlikely during any framework releases that releasing the 'unused' dependencies to the staging area will be rememebered
- It just seems wrong to have a bunch of DLL's sitting around purely for the purpose of helping to reflect over a plugin

Scenario of what I'm trying to acheive:

Developer to support team: Can you release this assembly please? It has the following types in it. Any instance of 'TypeX' requires a setting called 'A' and any instance of 'TypeY' requires a settings called 'A', 'B' and 'C'

The support team will then use the support ui, a web page, (not the main application UI) to upload the new assembly. I would like the web page then to list go through the types in the assembly, prompting the support user to enter the required settings into the meta data.

Once this is complete, the support UI will copy the assembly to the production environment where it can be loaded an executed.

To start any instance of the plugin, the support user will use the support UI wizard which will prompt them for which plugin they wish to use and also to provide values for the required settings (as entered in the support UI at release stage).

Another pat of the reason for this design is that the actual applications running the plugins performs various external communications and hence, due to company policy, is running within a DMZ that we have limited access to.


"Just beacuse you're paranoid, don't mean they're not after you
 
you need the references to reflect.

since you're right not to put all the referenced dlls into the dmz, perhaps the support staff could work from a copy in an area that can have them in.

oh, and btw, if you work for a large enough company to have four such entirely separate functions, why are you posting questions here? does your boss know? ;)



mr s. <;)

 
OK - the solution (possibly not the most performant - but this is a UI for support staff!).

Code:
    public class AssemblyViewer : MarshalByRefObject
    {
        #region Constructor

        public AssemblyViewer()
        {
            _dumbAssemblies = new Dictionary<string, AssemblyBuilder>();
        }

        #endregion

        #region Methods

        public List<string> GetTypes(string asmFile)
        {
            Assembly asm = this.LoadAssemblyForViewFrom(asmFile);
            List<string> ret = new List<string>();
            // here go the types that could be loaded
            foreach (Type type in asm.GetTypes())
            {
                if (type != null)
                    ret.Add(type.FullName);
            }

            return ret;
        }

        #endregion

        #region Event handlers

        private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(args.Name), AssemblyBuilderAccess.Run);
            _dumbAssemblies.Add(args.Name, ab);

            return ab;
        }

        #endregion

        #region Supplementary

        private void GenerateDumbType(string asm, string typeName)
        {
            AssemblyBuilder ab;
            if (_dumbAssemblies.TryGetValue(asm, out ab))
            {
                ModuleBuilder module = ab.GetDynamicModule(asm);
                if (module == null)
                    module = ab.DefineDynamicModule(asm);
                TypeBuilder tb = module.DefineType(typeName, TypeAttributes.Public);
                tb.CreateType();
            }
        }

        private Assembly LoadAssemblyForViewFrom(string asmFile)
        {
            Assembly asm = Assembly.LoadFrom(asmFile);
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

            try
            {
                asm.GetTypes();
            }
            catch (ReflectionTypeLoadException e)
            {
                // here are the unresolved ones
                if (e.LoaderExceptions != null)
                {
                    foreach (TypeLoadException exc in e.LoaderExceptions)
                    {
                        string missedAsmName = (string)typeof(TypeLoadException).GetField("AssemblyName", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(exc);
                        GenerateDumbType(missedAsmName, exc.TypeName);
                    }
                }
            }
            finally
            {
                AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            }

            return asm;
        }

        #endregion

        #region Fields

        private Dictionary<string, AssemblyBuilder> _dumbAssemblies;

        #endregion
    }

Useage of this (from main application):
Code:
            string filename = @"c:\stagingDir\MyPlugin.dll";
            AppDomain app2 = AppDomain.CreateDomain("Resolver");

            AssemblyViewer ins = (AssemblyViewer)app2.CreateInstanceAndUnwrap("ReflectingNoDependencies", "ReflectingNoDependencies.AssemblyViewer");

            List<string> types = ins.GetTypes(filename);

            foreach (string s in types)
            {
                Console.WriteLine(s);
            }

            AppDomain.Unload(app2);

and there we have it.

"Just beacuse you're paranoid, don't mean they're not after you
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top