RSS

Tag Archives: Reflection

InvalidCastException when using Assembly.LoadFile

Here is something that I have come across which puzzled me. If you are required to write an extensible application that uses plugins, and you have used dynamically loaded assemblies to accomplish that, then you might have encountered the following exception ([path] and [other path] are placeholders for actual file paths):

“[A]Plugin.MyPlugin cannot be cast to [B]Plugin.MyPlugin. Type A originates from ‘Plugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ in the context ‘LoadNeither’ at location ‘[path]Plugin.dll’. Type B originates from ‘Plugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ in the context ‘Default’ at location ‘[other path]Plugin.dll’.”

Setup
I’ll describe a sample scenario how this exception might occur. In this sample I’ll be using Xml Serialization for storing the plugin’s state, but the issue is not unique to Xml Serialization and you might encounter it regardless.

So, in this sample the plugin is an ordinary class, within a Class Library, that implements a regular .NET Interface (in a different Class Library). There is one executable that will use reflection to load the plugin and use it via the interface:

  1. IPlugin is the interface plugins are required to implement (Class Library project ‘PluginLib’).
  2. MyPlugin class is the inheriting plugin (Class Library project ‘Plugin’ referencing ‘PluginLib’).
  3. MainProg is the main extensible application (exe referencing PluginLib, which will dynamically load ‘MyPlugin’, residing in the ‘Plugin’ assembly).

PluginLib consists of a simple interface:

namespace PluginLib
{
    public interface IPlugin
    {
        void DoSomething();
    }
}

‘Plugin’ project is a very simply one (the ‘State’ property is not required for demonstrating this issue, and only serves as an excuse to use Xml Serialization in this sample):

namespace Plugin
{
    public class MyPlugin : PluginLib.IPlugin
    {
        public string State { get; set; }
        public void DoSomething()
        {
            // do something
        }
    }
}

MainProg dynamically loads the plugin for use (note that no try-catch clauses or any validations are shown here, but you would probably want to have those in “real world” code):

// [path] is a place holder for an absolute path located elsewhere
string pluginPath = @"[path]Plugin.dll";

// load the plugin from the specified path
Assembly assembly = Assembly.LoadFile(pluginPath);

// detect the first Type that implements IPlugin (you should test the result for 'null')
var type = assembly.GetTypes().FirstOrDefault(t => typeof(IPlugin).IsAssignableFrom(t));

// instantiate the plugin using the detected Type
IPlugin plugin = (IPlugin)Activator.CreateInstance(type);

// use the plugin
plugin.DoSomething();

So far so good. This works perfect. Now let’s assume that we would like to use Xml Serialization to maintain the plugin’s state. Although there are many ways to maintain a state, Xml Serialization is a very convenient method for doing so. I’ll revise the code a little:

// [path] is a place holder for an absolute path located elsewhere
string pluginPath = @"[path]Plugin.dll";
Assembly assembly = Assembly.LoadFile(pluginPath);

var type = assembly.GetTypes().FirstOrDefault(t => typeof(IPlugin).IsAssignableFrom(t));
IPlugin plugin = (IPlugin)Activator.CreateInstance(type);
plugin.DoSomething();

XmlSerializer serializer = new XmlSerializer(plugin.GetType());
using (MemoryStream ms = new MemoryStream())
{
    serializer.Serialize(ms, plugin);
}
  • Line 9: Notice that the XmlSerializer uses the actual Type of the created instance.
  • Line 12: This is where the exception will eventually occur.

For now, this will also work well. However, as I wanted to use the plugin “out of the box” without having the end-user to configure anything, I added a reference from MainProg directly to Plugin (“Add Reference…”). This way MyPlugin will be available at “design time” and will surely exist in the bin folder for deployment. This is when I got the exception on line 12.

Explanation
After googling for this exception and making several attempts to modify my code in order to try and get it to work, I came across this excellent post, which sums up the main differences between the different static Load methods that exist in the Assembly class. As the exception states, and as can be understood from the post, there are different contexts where assemblies are loaded to:

  • The ‘Load’ context is the Default context. ‘Design time’ referenced assemblies would load there (i.e. GAC assemblies or assemblies located in the private Bin folder etc.) In other words, where .NET assemblies are normally loaded by the process of probing. In her interview, Suzanne defines the Load method as the recommended good practice for loading assemblies.
  • The ‘LoadFrom’ context to my understanding is when you would like to have the assembly loader load an assembly which can’t be found by regular probing. Assemblies can be loaded to this context by explicitly calling Assembly.LoadFrom(). There are several advantages to this method, for example if there are other dependencies to be loaded referenced by this assembly.
  • The ‘Neither’ (or rather ‘LoadNeither’) context is used when Fusion in not involved (In her interview, Suzanne explains that Fusion is the part that is responsible for locating an assembly, for example in the private Bin folder, or GAC. So Fusion is not the Loader). Assemblies are loaded here when using Assembly.Load(byte[]), Reflection.Emit or Assembly.LoadFile(). To my understanding, this context is to be used when you would like save probing costs or have more control over the assemblies loaded. There are many articles and blogs that relate to Assembly.LoadFile() as a bad alternative, but I’m not sure that it is. As in other programming areas, I assume that this context addresses a need for particular projects. In the interview, Suzanne explains that there might be situations that you are required to recompile your assembly and reload it without using a different AppDomain, so that why the Neither context may come in handy.
  • There is another context not mentioned in that post (as it’s from 2003), and that’s the ReflectionOnly context. In this context you can load assemblies only to be examined using reflection, but you cannot run the code. For example, you may want to examine an assembly compiled for 64 bit on a 32 bit application, or check if an assembly is compatible with specific requirements prior to loading it into an executable context.

Now the exception is a lot clearer. By using Assembly.LoadFile(), the assembly plugin was loaded into the ‘LoadNeither’ context, whereas the Xml Serializer attempts to use a MyPlugin class already loaded into the Default Load context. Although these are the same classes as far as I’m concerned, they differ in the contexts used and therefore are considered as different classes by .NET.

Solution
So, a decision is to be taken here:

  • Either remove the “direct reference” to the plugin and always load it dynamically using LoadFile (or better, use LoadFrom). Only a single MyPlugin will exist in the different contexts and therefore the exception will be prevented. Or,
  • Figure out how to load the assembly into the Load context (or rather, use the already existing “design time” Plugin assembly in the private Bin folder even if differs from the file path specified by LoadFile).

I wanted the second option because as far as my app, it was OK to assume that no two plugins of the same name would co-exist, and if the dll was to be loaded dynamically (just like the plugin that it is), it will be OK to prefer the dll within the private Bin folder. So, I just needed to figure out how to load my plugin using the Load context, because Assembly.Load() does not have an overload for loading from a file path.

Luckily, reading the comments in above post provided a solution. Turns out that you can use the static AssemblyName.GetAssemblyName(string assemblyFile) to retrieve a valid AssemblyName object for assemblyFile. Once you have an AssemblyName, you can pass it as an argument to Assembly.Load(…). If an assembly by that AssemblyName is already loaded, that assembly would be used; or, if an assembly that corresponds to the AssemblyName is found within the probing paths, it will be favored and loaded. Only if an assembly that corresponds to that AssemblyName was not found, then the assembly you specified in the file path will be loaded. Suzanne commented that this might be a little costly in probing performance, but the behavior is exactly what I wanted it to be, and I wasn’t bothered by a possible performance issue in my particular case as my app doesn’t load assemblies all day long.

So, the modified code is as follows:

// [path] is a place holder for an absolute path located elsewhere
string pluginPath = @"[path]Plugin.dll";
AssemblyName name = AssemblyName.GetAssemblyName(pluginPath);
Assembly assembly = Assembly.Load(name);

var type = assembly.GetTypes().FirstOrDefault(t => typeof(IPlugin).IsAssignableFrom(t));
IPlugin plugin = (IPlugin)Activator.CreateInstance(type);

XmlSerializer serializer = new XmlSerializer(plugin.GetType());

using (MemoryStream ms = new MemoryStream())
{
    serializer.Serialize(ms, plugin);
}

The problem is solved, although one must take into account that this solution means that the specified plugin in the file path might not be the one actually used at run-time. If you have to ensure that the specified plugin is indeed the one used, you’ll have to use one of the other Load contexts and handle the possibility of receiving the exception which started it all.

Other references
Here are some interesting references that I came across when reading about this (no particular order):

Summary
When using reflection for dynamically loading your assemblies, there are different methods of doing so. As a rule of thumb, you should always try to load your assemblies to the default Load context. Next alternative is the LoadFrom context, and LoadFile is your last alternative and should be used only for particular cases when the other two might not be adequate.

If you are going to use the method described in this post (i.e. loading using AssemblyName in order to ensure loading into the Load default context), you should remember that plugins might have identical names to assemblies found in the probing path or simply other assemblies that are already loaded. If your application is one that requires extensive plugin usage, you should probably develop some method of checking whether those dynamically loaded plugins have matching AssemblyNames, and possibly consider notifying users that there is a problem. Otherwise you might run into unexpected behavior. Same goes for development and debugging: you may think that you have loaded an assembly by specifying a valid path name, but end-up using an assembly from a different path (or from the GAC), with a different behavior and classes.

Advertisements
 
2 Comments

Posted by on 11/11/2012 in Software Development

 

Tags: , , ,

How to write a code based ValidationExpression using ExpressionBuilder

Here’s a pain: write an¬†ASP.NET ExpressionBuilder. Here’s another: use a ValidationExpression for a RegularExpressionValidator which isn’t hard-coded, Resource based or App Settings based, but code based. This post will cover both pains, but will open a “world of options” for using custom ASP.NET Expressions.

ASP.NET Expressions

To those unfamiliar with ASP.NET Expressions, here’s a brief: you can set property values in a declarative way using Expressions. For example:

<asp:Label runat="server" Text="<%$Resources: Description %>"/>

Assuming that you have a corresponding resource file, the user will see the value set there for the item that has the Description key. I won’t get into this in this post, but I’m a big fan of using Resources in ASP.NET, so Expressions are something I use often.

ASP.NET comes with 3 out-of-the-box Expression “types”: Resources, Connection Strings and App Settings.

The RegularExpressionValidator Situation (Pain number 2):

I assume that most of us who develop using WebForms and ASP.NET Validators have used the RegularExpressionValidator at some point. Using the ValidationExpression property, we can easily set a Regular Expression to validate our users input for stuff like emails, phone numbers, zip codes etc. Very comfortable:

However, a ValidationExpression has to be either hard coded, or retrieved using an Expression. This means that if you need to use the same regular expression in different locations, you’ll either have to copy-paste it, or use an Expression based solution. Hard-coding and copy-pasting a ValidationExpression could prove to be a bad practice, especially for generic validations such as emails and the like, because you may want to change the tested expression, and in such a case you’ll have to find all those locations you now have to replace. Using Expressions is a better solution because by placing a regular expression in a Resource file or App Settings, you can at least avoid copy-pasting it and you have single location where changes can be made. However, both of these Expression-based solutions are somewhat an ugly workaround, because you’d usually want your regular expression in a Shared/Common dll, so other components may use it, and not only your ASP.NET validators. While AppSettings can still be used across your different assemblies, Resources cannot (well, you can use Reflection but that’s another story). Finally, your expression may reside in a Property and contain logic, so now you have to have a code based solution. For example, let’s assume that you need a regular expression validation which is culture oriented – you probably have to use thread culture code to accomplish that. Unfortunately, you cannot use server side script tags to fetch a static, const or property. For some reason I’m not familiar with, MS has not provided what should have been one of the most basic features in ASP.NET, and that is to use the <%= %> from within declarative syntax:

The above code compiles and runs, but literally renders the server tags themselves instead of resolving them. You can use <%= %> in your JavaScript code, or even inside a regular html block, but you can’t use it in declarative properties! This is beyond me, although I guess that there’s a good explanation to this.

Anyhow, if you do want to use a regular expression placed in a const, static field or a static property as written in the following code, you are now stuck, or you are forced to code-behind this in your page and give up the declarative ValidationExpression.

StaticExpression (Pain number 1):

I decided to overcome this situation using a custom Expression. I have written just a small number of expressions all these years, and each time I found myself wasting precious time on remembering how to do this, googling for sample code etc. There are several good resources on the web for writing custom Expressions. Here’s one and another from MS. To summarize this, I’ll just say that basically there are 4 steps to writing your own a custom expression:

  1. Write a custom Expression class by inheriting from ExpressionBuilder (e.g. StaticExpression class that will accomplish retrieving static, const or Property values).
  2. This class should have a static method which actually performs what you want to do and return the desired string.
  3. This class should also implement the abstract GetCodeExpression( ) method, which simply uses CodeDom objects to call the method you created in step 2. (Note, that you may choose to implement the code directly from this method and skip the static method in step 2, as shown in MS’ sample).
  4. Add the custom Expression to the web.config, so that ASP.NET will now how to resolve the declarative Expressions in your pages.

Here is the StaticExpression class, which supports returning a string from a const or static field/property using simple Reflection (explanation below). I placed this class in the App_Code:

  • Lines 9-18 is the CodeDom method which returns the custom method which actually does all the work (lines 20-71).
  • Lines 26-35 parse and determine whether the expression contains not only the class and field/property, but also an assembly name where to retrieve it from. Note, that you can alternatively change the code so that if no assembly is specified, some default assembly is used (in such a case you’ll have to insert a line of code adjacent to line 34, which states: assemblyName=”<your default assembly name>”.
  • Lines 29-30 assumes that the expression specifies an assembly, and that the assembly is specified prior to the const/property. This resembles working with Global Resources, but this doesn’t have to be the case. You may choose to specify the assembly after the const/property name, resembling how Reflection’s Type.GetType work (line 47 shows this).
  • Lines 38-47 resolves the type of the class to be used. The expression, without the assembly, is parsed so that we’ll have the class (including namespace if specified) separated from the field/property name.
  • Line 50 retrieves the actual class type.
  • Lines 54-58 attempt to detect if the name relates to a static field or const, and retrieve it’s value (the null in Line 57 implies a static field or a const).
  • Lines 59-64 relate to properties (the first null in Line 63 implies a static property and the second null means that there are no arguments to this property).
  • Lines 67-68 will throw an exception if the text could not be retrieved.

The declarative code in your Page:

  1. The Label’s Text demonstrates how to retrieve MyConst const from a Consts class residing in the App_Code (no assembly specified).
  2. The RegularExpressionValidator’s ValidationExpression demonstrates how to retrieve a static Property value from a class residing in a different assembly.

And the web.config, which states that when a “Static” keyword is used for an Expression, resolve it using the StaticExpression class:

Final notes

You may also choose to inherit ResourceExpressionBuilder instead of the abstract ExpressionBuilder. This could be handy if you need a custom Expression that will fallback to resolving a Resource Expression. For example, if your page is running in two different custom modes, X and Y, you could change the resource key stated in the declarative property and only then proceed to retrieving the resource, by calling the base class methods. Your code will require changes, but it’s certainly achievable.

 
Leave a comment

Posted by on 11/11/2011 in Software Development

 

Tags: , , , ,