Click here to Skip to main content
15,889,992 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hi,

I am writing a custom application to fetch all the public members of a class using reflection.

Whenever I call the GetTypes() method on the assembly, I get the following exception.

Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.


The inner exception has the following details


{"Could not load file or assembly 'ObjectModel, Version=1.4.0.18193, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.":"ObjectModel, Version=1.4.0.18193, Culture=neutral, PublicKeyToken=null"}

ObjectModel assembly is a custom assembly found in the same directory as that of the assembly currently loaded.

I have the following code
C#
private void ProcessAssemblies(IList<string> assemblyNames)
{
    string assemblyName = string.Empty;
    for (int i = 0; i < assemblyNames.Count; i++)
    {
        assemblyName = assemblyNames[i];
        if (File.Exists(assemblyNames[i]))
        {
            Assembly assembly = Assembly.LoadFile(assemblyName);

            PrintAllPublicMembers(assembly);
        }
    }
}

private void PrintAllPublicMembers(Assembly assembly)
{
    foreach (Type type in assembly.GetTypes())
    {
        if (PropertiesCheckBox.Checked)
        {
            IList<PropertyInfo> properties = type.GetProperties(bindingAttributes);
            PrintAllProperties(properties);
        }
        if (MethodsCheckBox.Checked)
        {
            IList<MethodInfo> methods = type.GetMethods(bindingAttributes);
            PrintAllMethods(methods);
        }
    }
}

// The bindingAttributes currently takes the following values
BindingFlags bindingAttributes = BindingFlags.Public | BindingFlags.Instance;




Am I taking the wrong approach in finding the public members of a class? Or am I missing anything?
Posted
Updated 12-Jun-12 1:48am
v2
Comments
Sergey Alexandrovich Kryukov 12-Jun-12 1:05am    
Just a note: you are not trying to print all public members: you are trying to get only the properties and methods. There are also nested types, fields, events, constructors...

What is the value of "bindingAttributes"? By the way, if you simple omit this parameter, it means all public members of this kind (all public properties, all public methods, etc.)

--SA
Sergey Alexandrovich Kryukov 12-Jun-12 1:11am    
How did you obtain the list of assemblies? Is any of the assemblies in GAC? does the assembly executing this code reference all of the assemblies in question or not? I also have some doubt that this exception is thrown by GetTypes. In some (rare) situations the debugger can show wrong like. To make is clean, output Exception.StackTrace (this is just a string) and show it (use "Improve question").
--SA
vinayvraman 12-Jun-12 7:51am    
Hi SA,

The user selects the assemblies for which he needs to see the public members of the class. The original idea of the app was to fetch all the public members of the class. Since it wasn't working for Properties and methods, I have excluded the rest of them from the sample source code I have uploaded here.

Some of the referenced assemblies are not in GAC and it is for these assemblies I am getting the above mentioned exception. And the exception seems to be valid for me. The assembly load function is not able to load the assemblies from its start up path. But if I put my application in the path where the assemblies exist, then it is able to load all the referenced assemblies.

Best Regards
Vinay
Jim Jos 12-Jun-12 9:53am    
Are you putting your assembly names as fully qualified paths or just assembly name?
vinayvraman 12-Jun-12 10:11am    
Lets consider I am trying to load assembly 'A.dll' which in turn refers an assembly 'B.dll'.
A.dll and B.dll are in the same directory.

The dlls are provided by the user (i.e. he/she selects the assembly) for which class member information is required.

The above code gets fully qualified path for A.dll and hence File.Exists() method succeeds. But when the PrintAllPublicMembers method is called, and assembly.GetTypes() method is executed, I get an exception.

Am I missing anything here?

If you lookup up the referenced assemblies from the assembly using GetReferencedAssemblies() you'll get a list of all the assemblies that (might) be needed to retrieve full type info.
You can then use this information to have the user browse to were ever that assembly is and load that as well, and then you'll need to repeat that recursively as assemblies can reference more assemblies.

Hope this helps,
Fredrik
 
Share this answer
 
Thank you all for the help.

I found the solution for the problem I was facing. Here is the complete code for what I was trying to achieve.

The AppDomain to which the assembly is loaded tries to resolve the assembly references for the referenced assemblies automatically. If the referenced assemblies are in the same directory as that of application or if it is in GAC then assembly resolution succeeds. In case it is unable to resolve then "AssemblyResolve" event is fired. By subscribing to this event we can attempt resolving the references.


C#
// Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;

namespace AssemblyInformation
{
    public partial class Form1 : Form
    {
        BindingFlags bindingAttributes = BindingFlags.Public | BindingFlags.Instance;
        BackgroundWorker workerThread;
        StringBuilder stringBuilder = new StringBuilder();

        public Form1()
        {
            InitializeComponent();

            workerThread = new BackgroundWorker();
            workerThread.DoWork += new DoWorkEventHandler(workerThread_DoWork);
            workerThread.ProgressChanged += new ProgressChangedEventHandler(workerThread_ProgressChanged);
            workerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerThread_RunWorkerCompleted);
            workerThread.WorkerSupportsCancellation = true;
        }

        void workerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ResultsTextBox.Text = stringBuilder.ToString();
        }

        void workerThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {

        }

        void workerThread_DoWork(object sender, DoWorkEventArgs e)
        {
            IList<string> fileNames = e.Argument as IList<string>;
            ProcessAssemblies(fileNames);
        }

        private void WordWrapCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            ResultsTextBox.WordWrap = WordWrapCheckBox.Checked;
            WordWrapCheckBox.Font = new Font(WordWrapCheckBox.Font, WordWrapCheckBox.Checked ? FontStyle.Bold : FontStyle.Regular);
        }

        private void AttributesCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox attributeCheckBox = sender as CheckBox;
            if (attributeCheckBox != null)
            {
                attributeCheckBox.Font = new Font(attributeCheckBox.Font, attributeCheckBox.Checked ? FontStyle.Bold : FontStyle.Regular);
            }
        }

        private void BrowseButton_Click(object sender, EventArgs e)
        {
            if (AssemblyOpenFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                ResultsTextBox.Clear();
                SelectedAssemblyTextBox.Text = AssemblyOpenFileDialog.SafeFileNames.GetCommaSeperatedValue();

                workerThread.RunWorkerAsync(AssemblyOpenFileDialog.FileNames);
            }
        }

        private void ProcessAssemblies(IList<string> assemblyNames)
        {
            try
            {
                string assemblyName = string.Empty;
                this.BeginInvoke((Action)(() => this.Cursor = Cursors.WaitCursor));

                AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(appDomain_AssemblyResolve);
                for (int i = 0; i < assemblyNames.Count; i++)
                {
                    assemblyName = assemblyNames[i];
                    if (File.Exists(assemblyNames[i]))
                    {
                        string path = Path.GetDirectoryName(assemblyName);
                        Directory.SetCurrentDirectory(path);

                        stringBuilder.Append(assemblyName + Environment.NewLine);
                        stringBuilder.Append("---------------------------------" + Environment.NewLine);

                        //Assembly assembly = appDomain.Load(assemblyName);
                        Assembly assembly = Assembly.LoadFile(assemblyName);
                        AppDomain.CurrentDomain.Load(assembly.GetName());
                        IList<assemblyname> referencedAssemblyNames = assembly.GetReferencedAssemblies();

                        foreach (AssemblyName assemblyNameRef in referencedAssemblyNames)
                        {
                            try
                            {
                                AppDomain.CurrentDomain.Load(assemblyNameRef);
                            }
                            catch (FileNotFoundException)
                            {
                                string referencedAssemblyPath = path + "\\" + assemblyNameRef.Name + ".dll";
                                AppDomain.CurrentDomain.Load(referencedAssemblyPath);
                            }
                        }
                        PrintAllPublicMembers(assembly);
                    }
                }
            }
            finally
            {
                this.BeginInvoke((Action)(() => this.Cursor = Cursors.Default));
            }
        }

        Assembly appDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            string path = Path.GetDirectoryName(AssemblyOpenFileDialog.FileName) + "\\" + args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll";

            //Retrieve the list of referenced assemblies in an array of AssemblyName.
            Assembly MyAssembly = null;

            //Load the assembly from the specified path. 					
            if (File.Exists(path))
                MyAssembly = Assembly.LoadFrom(path);
            else
            {
                this.Invoke((Action)(() =>
                {
                    OpenFileDialog resolveAssemblyFileDialog = new OpenFileDialog();
                    resolveAssemblyFileDialog.FileName = args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll";
                    resolveAssemblyFileDialog.Filter = resolveAssemblyFileDialog.FileName + "|" + resolveAssemblyFileDialog.FileName;
                    resolveAssemblyFileDialog.Multiselect = false;
                    if (resolveAssemblyFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        MyAssembly = Assembly.LoadFrom(resolveAssemblyFileDialog.FileName);
                    }
                    else
                    {
                        DialogResult appClosureConfirmationDialogResult = MessageBox.Show("Unable to proceed without resolving reference to the '" + args.Name + "' assembly. Do you want to try again?", "Assembly Information", MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button2);
                        if (appClosureConfirmationDialogResult == System.Windows.Forms.DialogResult.Yes)
                        {
                            if (resolveAssemblyFileDialog.ShowDialog(this) == System.Windows.Forms.DialogResult.OK)
                            {
                                MyAssembly = Assembly.LoadFrom(resolveAssemblyFileDialog.FileName);
                            }
                            else
                            {
                                Application.Exit();
                            }
                        }
                        else
                            Application.Exit();
                    }
                }));
            }
            //Return the loaded assembly.
            return MyAssembly;
        }

        private void PrintAllPublicMembers(Assembly assembly)
        {
            foreach (Type type in assembly.GetTypes())
            {
                stringBuilder.Append("Class/Interface: " + type.Name + Environment.NewLine);
                stringBuilder.Append("\tProperties: " + Environment.NewLine);
                if (PropertiesCheckBox.Checked)
                {
                    IList<propertyinfo> properties = type.GetProperties(bindingAttributes);
                    PrintAllProperties(properties);
                }
                stringBuilder.Append("\tMethods: " + Environment.NewLine);
                if (MethodsCheckBox.Checked)
                {
                    IList<methodinfo> methods = type.GetMethods(bindingAttributes);
                    PrintAllMethods(methods);
                }
            }
        }

        private void PrintAllMethods(IList<methodinfo> methods)
        {
            foreach (var method in methods)
            {
                stringBuilder.Append("\t\t" + method.Name + Environment.NewLine);
            }
        }

        private void PrintAllProperties(IList<propertyinfo> properties)
        {
            foreach (PropertyInfo property in properties)
            {
                IList<object> customAttributes = property.GetCustomAttributes(false);
                foreach (var item in customAttributes)
                {

                }
                stringBuilder.Append("\t\t" + property.Name + Environment.NewLine);
            }
        }

        private void TypeAttributesCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox attributeCheckBox = sender as CheckBox;
            if (attributeCheckBox != null)
            {
                attributeCheckBox.Font = new Font(attributeCheckBox.Font, attributeCheckBox.Checked ? FontStyle.Bold : FontStyle.Regular);
            }
        }

        private void FindButton_Click(object sender, EventArgs e)
        {

        }
    }
}


C#
// ExtentionMethods.cs

    internal static class ExtensionMethods
    {
        public static string GetCommaSeperatedValue(this IList<string> stringArray)
        {
            string output = string.Empty;

            if (stringArray.Count == 0)
                return output;
            else if (stringArray.Count == 1)
                return (output = stringArray[0]);
            else
            {
                for (int i = 0; i < stringArray.Count; i++)
                {
                    output += "\"" + stringArray[i] + "\"";
                    if (i < (stringArray.Count - 1))
                    {
                        output += " ";
                    }
                }

                return output;
            }
        }
    }
</string>
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900