Enabling .NET 2.0 references in a class library of version 4.0 or higher during runtime.

Written by Steve Endow

If you’re unfamiliar with .NET mixed mode assemblies, you can safely disregard this post. However, if you do understand them and the challenges they present, read on.

This post serves as a personal reference for a solution I’ve used, saving me from searching through numerous past projects in the future.

My colleague, Andrew Dean from Envisage Software, and I have presented this solution during Dynamics GP .NET Development presentations at reIMAGINE and GPUG Summit. It has proven invaluable in our Dynamics GP development projects.

The primary reason for employing this solution with Dynamics GP is the frequent use of GPConnNet.dll, a DLL only compatible with .NET 2.0. Developing a new solution using .NET 4.5.1 will trigger the well-known mixed mode assembly error.

This error message indicates that the assembly targets .NET version ‘v2.0.50727’ and needs additional configuration to load in the 4.0 runtime.

Typically, this error is resolved by modifying the application configuration file (app.config or exe.config). While effective for EXEs, this solution fails when developing class library DLLs used by external applications beyond your control, such as Dynamics GP.

Reed Copsey Jr. provides an ingenious alternative in his blog post, outlining how to set the .NET legacy policy during runtime. This approach is a lifesaver for DLL libraries referencing resources across multiple .NET versions.

http://reedcopsey.com/2011/09/15/setting-uselegacyv2runtimeactivationpolicy-at-runtime/

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public static class RuntimePolicyHelper
{
    public static bool LegacyV2RuntimeEnabledSuccessfully { get; private set; }

    static RuntimePolicyHelper()
    {
        ICLRRuntimeInfo clrRuntimeInfo =
            (ICLRRuntimeInfo)RuntimeEnvironment.GetRuntimeInterfaceAsObject(
                Guid.Empty, 
                typeof(ICLRRuntimeInfo).GUID);
        try
        {
            clrRuntimeInfo.BindAsLegacyV2Runtime();
            LegacyV2RuntimeEnabledSuccessfully = true;
        }
        catch (COMException)
        {
            // This occurs with an HRESULT meaning 
            // "A different runtime was already bound to the legacy CLR version 2 activation policy."
            LegacyV2RuntimeEnabledSuccessfully = false;
        }
    }

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("BD39D1D2-BA2F-486A-89B0-B4B0CB466891")]
    private interface ICLRRuntimeInfo
    {
        void xGetVersionString();
        void xGetRuntimeDirectory();
        void xIsLoaded();
        void xIsLoadable();
        void xLoadErrorString();
        void xLoadLibrary();
        void xGetProcAddress();
        void xGetInterface();
        void xSetDefaultStartupFlags();
        void xGetDefaultStartupFlags();

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void BindAsLegacyV2Runtime();
    }
}

This approach empowers you to develop mixed-mode assembly class libraries effectively.

Steve Endow is a Microsoft MVP for Dynamics GP and a Dynamics GP Certified IT Professional based in Los Angeles. He owns Precipio Services, providing Dynamics GP integrations, customizations, and automation solutions.

Find him onGoogle+andTwitter

http://www.precipioservices.com

Licensed under CC BY-NC-SA 4.0