Click here to Skip to main content
11,634,561 members (73,499 online)
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C# reflection
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
        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 11-Jun-12 18:19pm
Edited 12-Jun-12 1:48am
v2
Comments
SAKryukov at 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
SAKryukov at 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
goodpeapul at 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
JimJos at 12-Jun-12 9:53am
   
Are you putting your assembly names as fully qualified paths or just assembly name?
goodpeapul at 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?
JimJos at 12-Jun-12 10:17am
   
Before calling PrintAllPubliMembers could you verify you assembly is loaded into assembly variable?
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

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
  Permalink  
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

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.


 
// 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)
        {
 
        }
    }
}
 

// 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>
  Permalink  
v2

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

  Print Answers RSS
0 OriginalGriff 8,736
1 Sergey Alexandrovich Kryukov 8,359
2 Mika Wendelius 6,845
3 F-ES Sitecore 2,354
4 Suvendu Shekhar Giri 2,205


Advertise | Privacy | Mobile
Web03 | 2.8.150728.1 | Last Updated 12 Jun 2012
Copyright © CodeProject, 1999-2015
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100