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:
(Historical Note: This is the approach that PowerShell now uses to make “Add-Type -AssemblyName System.Web” and friends safe to run.)
################################################################################
## 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.]