[Mono-list] Assembly.LoadFrom() - Assembly.CreateInstance() - Activator.CreateInstanceFrom() ---> invalid cast

Jaroslaw Kowalski jaroslaw.kowalski@atm.com.pl
Tue, 27 Jan 2004 10:54:21 +0100


Hi Timothy,

I found the reason why this isn't working (and solution). This applies to MS
.NET and is related to assembly versioning but I thought it might be
interesting.

Sorry for quite a long post.

REPRODUCING THE PROBLEM:

1. I grabbed "ByteFX.Data" from "mcs" and created a VS.NET 2003 project, and
compiled it (obviously using .NET 1.1.4322).
2. Among other things "ildasm ByteFX.Data.dll" shows a reference to
System.Data that comes with .NET 1.1

.assembly extern System.Data
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         //
.z\V.4..
  .ver 1:0:5000:0
}

3. I created a test file: "test.cs"
---------------
using System;
using System.Reflection;
using System.Data;

public class Class1
{
    public static void Main()
    {
        Assembly DataProvider;
        DataProvider = Assembly.LoadFrom(@"bytefx\ByteFX.Data.dll");
        object dbConnection =
DataProvider.CreateInstance("ByteFX.Data.MySqlClient.MySqlConnection",false)
;
        Console.WriteLine(dbConnection.ToString());
        IDbConnection dbConn = (IDbConnection)dbConnection;
    }
}
---------------
4. I have both MS.NET 1.0 and 1.1 and csc.exe from 1.0.3705 happens to be in
my path. So when I compiled test.cs by:

csc test.cs

it referenced all libraries from .NET 1.0. "ildasm test.exe" shows:

.assembly extern System.Data
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         //
.z\V.4..
  .ver 1:0:3300:0
}

5. When I run test.exe I get invalid cast exception.

HERE'S WHY:

a) IDbConnection in test.cs acually means (using assembly-qualified type
names)
System.Data.IDbConnection, System.Data, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089, Custom=null
b) IDbConnection in "ByteFX.Data.dll" IDbConnection means:
System.Data.IDbConnection, System.Data, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089, Custom=null
c) Under .NET 1.0 the types aren't compatible and you have to provide
assembly redirection to get it working.
d) Under .NET 1.1 things have changed, and every time you ask for ANY type
from ANY assembly that shipped with MS.NET 1.1 (regardless of the version)
you always get the one that comes with .NET 1.1.

SOLUTION:

a) Recompile "test.cs" with csc.exe that comes with .NET 1.1. (In general -
use the same compiler for both library and an exe)
OR (when you want to run this on .NET 1.0)
b) Create a config file "test.exe.config"

<configuration>
   <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <dependentAssembly>
            <assemblyIdentity name="System.Data"
                              publicKeyToken="b77a5c561934e089"
                              culture="neutral" />
            <bindingRedirect oldVersion="1.0.5000.0"
                             newVersion="1.0.3300.0"/>
         </dependentAssembly>
      </assemblyBinding>
   </runtime>
</configuration>

that will redirect all request to System.Data to version that comes with
.NET 1.0

c) Note that when you compile test.cs for .NET 1.1 you don't need the config
file even if the ByteFX.Data was compiled against .NET 1.0 System.Data.dll
because of the auto-redirection feature from 1.1.

MY ADVICE:

Use Activator.CreateInstance() and pass it the full name of the type you
want to create. Something like:

Activator.CreateInstance(Type.GetType("ByteFX.Data.MySqlClient.MySqlConnecti
on, ByteFX.Data"))

This works like a charm provided that ByteFX.Data.dll is in your application
directory or in assembly probe path.

Jarek