How do I easily load assemblies, when LoadWithPartialName has been deprecated?

There are some very useful parts of the .Net framework (ie: System.Web and System.Windows.Forms) that Monad doesn’t load into its AppDomain by default.  In order to use them, you first load them with one of the Load() methods from the System.Reflection.Assembly class.


At first, the easiest approach seems to be LoadWithPartialName.  You can simply request “System.Windows.Forms” and be done with it:


MSH:73 C:\temp > [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)


GAC    Version        Location
—    ——-        ——–
True   v2.0.50727     C:\WINNT\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e…


(you can cast the result to [void] if you don’t want your script to belch the loading information.)


However, the documentation shows this handy method as being deprecated.


This is because the API needs to make too many guesses about what you really want.  Most people don’t really want “Whatever version of System.Windows.Forms you can scrounge up from the GAC or current directory.”  Most people really want “Microsoft’s version of System.Windows.Forms, shipped with .Net 2.0″


This is especially true in the face of breaking changes that may or may not happen to the DLL you want to load.  For applications that need to be reliable, LoadWithPartialName will cause problems.  Suzanne Cook discusses its implications on her blog entry, “Avoid Partial Binds.”


For scripts that you don’t mind debugging by hand when things break, you can stick with LoadWithPartialName until it’s physically removed from the framework.  However, your best bet is to consciously make the decisions that the LoadWithPartialName method makes on your behalf with the following helper script:



################################################################################
## load-assembly.msh
##
## Loads a given assembly by a more friendly name, while still using the strong
## binding characteristics of Assembly.Load.
##
## Assembly.LoadWithPartialName has been deprecated, as it binds only by display
## name.  It’s a convenient shortcut, but opens your application and script, and
## environment  to all sorts of reliability issues, including:
##    backwards incompatibility, forwards incompatibility, breaking changes,
##    and subtle assembly dependency problems.
##
################################################################################
param([string] $assemblyName)

## Our assembly name shortcuts
$assemblyMappings = (
   (“forms”“System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″),
   (“web”“System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”)
)

## List the assembly shortcuts we support
if(-not $assemblyName)
{
   “Please specify an assembly name.  Supported assemblies are: “
   foreach($assembly in $assemblyMappings) { $assembly[0] }
   return
}

## Load the assembly they request
## This fails with an error message if this specific assembly version can’t
## be loaded.
foreach($assembly in $assemblyMappings)
{
    if($assemblyName -eq $assembly[0])
    {
        [void] [Reflection.Assembly]::Load($assembly[1])
    }
}



 

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

7 Responses to “How do I easily load assemblies, when LoadWithPartialName has been deprecated?”

  1. Richard Siddaway writes:

    This has been really useful. One question though – I can’t seem to get this method to work with System.DirectoryServices.ActiveDirectory which works OK with the loadwithpartialname method. I’d be grateful for any ideas

    Thanks

  2. Lee writes:

    Hi Richard;

    When you want to add a new type to your load-assembly script, this is how you get the full name:

    1) $loadedAssembly = [System.Reflection.Assembly]::LoadWithPartialName("your_assembly_here")
    2) $loadedAssembly.FullName

    That gives you the fully qualified name of the assembly, which you can add to your list.

  3. HC Eng writes:

    I have trouble loading System.Drawing. Any clues? Thanks.

    PS C:\> $aa=[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
    PS C:\> $aa.Fullname
    System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
    PS C:\> [void][Reflection.Assembly]::Load(("drawing", "System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"))
    Exception calling "Load" with "1" argument(s): "Could not load file or assembly ‘drawing System.Drawing, Version=2.0.0.
    0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ or one of its dependencies. The system cannot find the file specif
    ied."
    At line:1 char:34
    + [void][Reflection.Assembly]::Load( <<<< ("drawing", "System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken
    =b03f5f7f11d50a3a"))

  4. Lee writes:

    Hi HC;

    The Assembly.Load method accepts the full name of the assembly, so it looks like this:

    [Reflection.Assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

    The "drawing" shortcut I used in the script just lets you use a shortcut to load the assembly — but it actually uses the full name for the actual call.

  5. Harkamal writes:

    Good article, I have been a fan of PowerShell Cookbook.

    Ok, so once i have an assembly loaded into powershell, say System.Drawing — How can I see which methoda or properties it supports, …can we make use of Get-Member somehow ??

    Th

  6. Understanding .NET from the perspective of an IT Professional « Energized About Technology writes:

    […] about more of this, you should check into these excellent online posts from Richard Siddaway, Lee Holmes and  Doug Finke which I used as a reference to get […]

  7. Perry writes:

    Watch out — the script is broken — it uses curly non-ASCII double quotes which will not work, and must be fixed before the script can work.

Leave a Reply