DEVPATH

Recently I have heard a great deal of confusion around DEVPATH. This blog tries to clarify a few things about DEVPATH.

 

  1. What is DEVPATH?
    DEVPATH is documented in MSDN (How to: Locate Assemblies by Using DEVPATH).

    In a nutshell, DEVPATH is a mechanism to enable debugging of private copies of shared assemblies without affecting running system during development time.

    To enable DEVPATH, add the following XML snippet to machine.config.

    <configuration>
    <runtime>
    <developmentMode developerInstallation="true"/>
    </runtime>
    </configuration>

    When DEVPATH is enabled, at runtime, fusion checks if environment variable DEVPATH exists. If it exists, fusion will probe the assembly in the path specified in environment variable DEVPATH before fusion probes GAC and AppBase.

    The path specified in DEVPATH can be anywhere in the system. Fusion does not enforce it to be under AppBase.

    When an assembly is found in DEVPATH, fusion still does Ref-Def matching check, but skips version check. In other words, fusion will compare name, culture, publicKeyToken and processorArchitecture, but will not compare version.

  2. Is DEVPATH supported?

    Yes. DEVPATH is supported by .Net framework v1.0, v1.1 and v2.0 in all the Operating systems. And it is likely to be supported in the foreseeable future.

    However, DEVPATH is only supported in development. It is not supported, and strongly discouraged in production, as it basically violates all the probing rules.

  3. When should I use DEVPATH?

    DEVPATH is typically used to override shared assemblies installed to GAC, without impacting the system.

    For example, a .Net framework developer on Windows Vista (where .Net framework 2.0 is built-in to the OS) does not want to overwrite the System.dll in GAC with his/her private copy of System.dll, as it may unstablize the operating system. He/She can use DEVPATH, and let his/her tests run against his/her private copy of System.dll.

  4. What is affected by DEVPATH?

    Fusion redirects both Assembly.Load() and Assembly.LoadFrom() to DEVPATH. Assembly.LoadFile/Assembly.Load(byte[]) are not redirected, as they don’t use fusion.

    When Assembly.LoadFrom() is redirected, fusion throws away the path, and only uses the file name to search in DEVPATH.

  5. What has changed between .Net framework v1.0/v1.1/v2.0 regarding DEVPATH?

    .Net framework v1.0 and v1.1 have identical implementation.

    However, there are significant changes between v1.1 and v2.0. Specifically.

    1. Multiple paths works in v1.1, but not in v2.0

      In v1.1, you can set environment variable DEVPATH to multiple paths separated by ‘;’. Fusion will search the assembly in every path specified in DEVPATH.

      This no longer works in v2.0 RTM. This is a regression, and we may fix in a future service pack for v2.0.
       

    2. Fusion redirects partial name assembly loading in v1.1, but no longer does so in v2.0.

      This change is to make the scenario close to production behavior, as fusion does not probe GAC for partial name assembly loading.

      If you are blocked by this change, you can work around the problem by using qualfyAssembly, as documented in MSDN.

      https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/gngrfQualifyAssemblyElement.asp

    3. Probing behavior changes significantly within DEVPATH.

      In v1.1, fusion simply appends the assembly simple name, plus “.dll” extension to the DEVPATH, and looks for the existence of that file. For example, if DEVPATH is set to “c:\debug”, for Assembly.Load(“Foo, version=1.0.0.0, culture=en-us, publicKeyToken=0123456789abcdef”), fusion will check if “c:\debug\foo.dll” exists or not. If it exists, fusion will return it.

      In v2.0, the DEVPATH is treated as another AppBase. Fusion uses the normal probing rule to probe within DEVPATH. In our example above, fusion will probe the following files in the specified order:

      c:\debug\foo.dll
      c:\debug\foo\foo.dll
      c:\debug\en-us\foo.dll
      c:\debug\en-us\foo\foo.dll
      c:\debug\foo.exe
      c:\debug\foo\foo.exe
      c:\debug\en-us\foo.exe
      c:\debug\en-us\foo\foo.exe

      The primary motivation for the change is for localization --- Apparently the v1.1 behavior won’t be able to support more than one resource assemblies.