Binary Deserialization issue from COM Addins, Custom Tools, Plugins and Other

31 Jan

Binary Deserialization issue from COM Addins, Custom Tools, Plugins and Other

OK, I struggled with the title a bit. But this is an issue that I have come across numerous times and every time I encounter it I forget how I got around it the previous time. I usually find information on how to fix the problem relatively easily (because of my experience in searching for this problem probably), but I thought that if I blog it that maybe I will remember it for next time (And I know there will be a next time).

If you are building plug-ins or COM Add-ins like a Office or Visual Studio Add-in or maybe a Visual Studio Custom tool or IIS sync you have to remember that the directory of the process that is executing will be the base directory of the AppDomain that you are going to be running in (It is actually pretty logical why it works this way, but that doesn’t mean you are not going to have trouble with it). This causes many problems, but the one that I keep encountering is when I try and serialize and deserialize objects. An easy way to recreate the problem is as follows:

  1. Create a new Visual Studio Project, go to Other Project Types and click on Extensibility. Then Select ‘Shared Add-in’ and create the project.
  2. Follow the Wizard and select your language of choice click Next, select only Word from the next list (its all we need for now) and click Next.
  3. Supply a name and description, click Next. Then check the ‘I would like my Add-in to load when the host application loads’ option, and click Next and then Finish.
  4. This will create a project with a Connect class (Connect.cs).
  5. Open up Connect.cs and in the Class create the following static initializer (or just copy paste the code below into your class):

internal class SerializationTest
private string name = “test1”;
public string Name{get { return name; }set { name = value; }}

static Connect()
System.IO.MemoryStream memStream = new System.IO.MemoryStream();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binForm = new

binForm.Serialize(memStream, new SerializationTest());
memStream.Flush();memStream.Position = 0;

SerializationTest test = (SerializationTest)binForm.Deserialize(memStream);
catch (Exception error)

Now you’ve created your project you will need to build and install it. Visual studio usually creates a setup with an Add-in project so just right click on the setup project and click build, then after it’s built you can right click on the setup project again and click Install. Just follow the steps as per normal.

Now to actually see the error you will need to debug since most Office Addins will fail silently and this case is no different. So put your breakpoint in the catch or earlier if you’d like and then setup your project for debugging (remember to make sure that you are building in debug mode). To debug the project:

  1. Right click on the Add-in project (mine I left as MyAddin1). And select Properties. Select the Debug tab (or list-item in 2003).
  2. Then in the Start Action group (topmost group), make sure the ‘Start external program’ option is selected.
  3. Click on the browse button (…) and browse to the location of your Word application file (winword.exe). It is usually in [primary drive]:\Program Files\Microsoft Office\Office12\WINWORD.EXE, or Office11 or Office10, oh or Program Files (x86) if you have a 64bit Windows installed, and then click OK.
  4. Close the Properties tab window.

After you have the breakpoints set, your debugging setup and your project installed, press ‘F5’. If your breakpoint is not fired then check the following:

  • Make sure all instances of Word are closed first before you press F5.
  • Open up your processes and check if WinWord.exe is not still running.
  • If you are using Word as your email editor in Outlook, make sure outlook is closed.
  • Uninstall the project (right click on the setup project and then uninstall), rebuild and reinstall.

The exception you’ll see in the catch block is: Unable to find assembly ‘MyAddin1, Version=1.0.2655.25428, Culture=neutral, PublicKeyToken=null’. Or something like that depending on what you named the project. And if you open AppDomain.Current.BaseDirectory in your QuickWatch or Watch window you’ll notice that it points to your word application folder.

The Solutions

OK, this error is pretty global and occurs (like mentioned above) in many plug-in/add-in or COM type architectures. There are a few solutions and I will run through them all quickly:

  1. Create a new AppDomain and set the base directory. Then load your Assembly into it and only serialize/deserialize from there. Personally I think this is a sloppy way of getting around this particular problem and you will have a lot of problems in you’re assembly architecture if you try and implement this solution, so I’m not going any further on this one.
  2. Stong-Name your assembly (if it’s not already) and add it to the Global Assembly Cache. This is a much better solution, and also easy, but in this case we do not want to fill the GAC with COM registered Add-in assemblies. There are also many other reasons why you would not want to add the assembly into the GAC.
  3. Implement AppDomain.CurrentDomain.AssemblyResolve event. This event passes the ResolveEventArgs which contain the name of the assembly to resolve and then returns a System.Reflection.Assembly . In the context of the scenario above it is a good (relatively clean) solution to our problem. But remember that every time any assembly needs to be loaded/resolved, your event will be called. To solve the above problem we would do the following:

    Change the static method to do the following instead:

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    SerializationTest test = SerializationTest)binForm.Deserialize(memStream);
    catch (Exception error) {
    AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);

    Obviously keep the top part of the method intact, and then add the event implementation to your Connect class:
    static System.Reflection.Assembly CurrentDomain_AssemblyResolve( object sender, ResolveEventArgs args)
    string partialName = “MyAddin1”;
    if (args.Name.IndexOf(partialName) != -1)
    return System.Reflection.Assembly.GetExecutingAssembly();
    return null;

    Just change the partialName variable with your assembly name. You could also use System.Reflection.Assembly.Load(asmName); to specify the full path of the assembly but then you will need to store the deployment path somewhere (and if you want to specify the path in the Config file you will have to use the application’s .config file which in this case is winword.exe.config in the office directory). There are also other ways to get already loaded assemblies, but you’ll see how to implement them in the next solution.

  4. Create a System.Runtime.Serialization.SerializationBinder implementation by inheriting from SerializationBinder and overriding the BindToType method. Then also go through the current loaded assemblies in the current AppDomain and return the correct one:

public class Binder : SerializationBinder
public override Type BindToType( string assemblyName, string typeName)
Type type = null;
string shortName = assemblyName.Split(‘,’)[0];
Assembly[] lasms = AppDomain.CurrentDomain.GetAssemblies();

foreach(Assembly lasm in lasms)
if(shortName == lasm.FullName.Split(‘,’)[0]) {
type = ayAssembly.GetType(typeName);
return tyType;

To use this Binder, insert the following line after you have created a new BinarryFormatter, like so:

System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binForm = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

binForm.Binder = new Binder();

If you are still attaching to the AssemblyResolve event, you can remove the two lines where you attach and detach to the event and you could also remove or comment the static event implementation method.

This solution (solution 4) is in my opinion the neatest and best way to get around the problem since you only do the work (resolving the Assembly/ies) when it is required in the Deserialization process.

K, that’s that.

Enjoy, Go Crazy.


Posted by on January 31, 2008 in Dotnet/C#


2 responses to “Binary Deserialization issue from COM Addins, Custom Tools, Plugins and Other

  1. Ofir

    October 6, 2013 at 10:43 pm

    Dude you are a life saver, I’ve google’d so much and I couldn’t find such a decent solution.
    I followed Method #3: AppDomain.CurrentDomain.AssemblyResolve

    In my case I’m developing this VS package, and when attempting to de-serialize the objects it yells it can’t find the dll, although it is listed in:

    So my suspicion is that Visual Studio initializes the assemblies list prior to the package load, and therefore cannot find it.

    What do you think could be the cause of the problem?
    (the serialize and de-serialize occur from the same assembly)

    Thanks a lot!


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: