Click here to Skip to main content
13,801,385 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

22.8K views
19 bookmarked
Posted 2 Nov 2014
Licenced CPOL

Loading Assembly to Leave Assembly File Unlocked

, 2 Nov 2014
Rate this:
Please Sign up or sign in to vote.
How to load assembly into memory in .NET application to have assembly file unlocked

Problem

If you need to manipulate .NET assembly files (rename, move, etc.) and at the same time load assembly in memory, you may be unpleasantly surprised by the fact that assembly file becomes locked by your application.

Using:

Assembly.LoadFrom(assemblyPath);

or:

Assembly.ReflectionOnlyLoadFrom(assemblyPath);

causes the assembly file to be locked.

I faced this problem creating an Assembly Strong Name Sign Tool when I needed to read assembly information and then rename assembly file.

Thanks to the CodeProject community feedback to this tip, I have found the 3 following solutions.

Solutions

  1. Using Assembly.Load(Byte[]) method
    (Proposed by SpArtA)
    Assembly.Load(File.ReadAllBytes(assemblyPath));

    In this way, assembly is loaded from new byte array in memory and no actual file lock is made.

    Pros: The simplest solution, requires a single line of code.
    Cons: The assembly location is unknown. You can't use Assembly.Codebase and Assembly.Location

  2. Loading assembly in a separate AppDomain
    (Also described in Sacha Barber's Blog in 2009)

    The only way to unload an assembly from an application domain is by unloading the Application Domain
    Application Domain is a unit of isolation in .NET that is like a subprocess in the process of application.

    The solution is to create a temporary AppDomain, read assembly data in it and then unload the temporary domain from memory.

    First, we need to create a class that holds assembly information.
    Class must be marked as [Serializable] since it travels between domain boundaries.

    [Serializable]
    public class AssemblyInfo
    {
        public string Name { get; set; }
        public string Version { get; set; }
        public string RuntimeVersion { get; set; }
        public string Platform { get; set; }
    
        public AssemblyInfo()
        {
        }
    
        public AssemblyInfo(AssemblyName assemblyName)
        {
            Name = assemblyName.Name;
            Version = assemblyName.Version.ToString();
            RuntimeVersion = "";
            Platform = assemblyName.ProcessorArchitecture.ToString();
        }
    
        public AssemblyInfo(Assembly assembly)
            : this(assembly.GetName())
        {
            RuntimeVersion = assembly.ImageRuntimeVersion;
        }
    }

    Then, we need to create a proxy class that will do stuff in another domain and return data to the current domain.
    It must inherit from MarshalByRefObject.
    Only classes inherited from MarshalByRefObject can be accessed between different application domain boundaries.

    public class AssemblyLoader : MarshalByRefObject
    {
        public AssemblyInfo LoadAssemlyInfo(string assemblyPath)
        {
            Assembly assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
            return new AssemblyInfo(assembly);
        }
    }

    Then, you create a temporary app domain, load the assembly in it and unload the domain:

    public static AssemblyInfo GetAssemblyInfo(string assemblyPath, bool lite = false)
    {
        AssemblyInfo assemblyInfo = null;
    
        // create a temporary app domain
        AppDomain tempDomain = AppDomain.CreateDomain("TempDomain");
    
        // create proxy instance in temporary domain
        var asmLoader = (AssemblyLoader)tempDomain.CreateInstanceAndUnwrap(
            typeof(AssemblyLoader).Assembly.FullName, typeof(AssemblyLoader).FullName);
    
        // load assembly in other domain
        assemblyInfo = asmLoader.LoadAssemlyInfo(assemblyPath);
    
        // unload temporary domain and free assembly resources
        AppDomain.Unload(tempDomain);
    
        return assemblyInfo;
    }

    Pros: You have access to full assembly info including Assembly.Codebase and Assembly.Location
    Cons: Method requires much more code including 3 separate classes.

  3. Configuring Current AppDomain to enable Shadow Copying Assemblies
    var setup = AppDomain.CurrentDomain.SetupInformation;
    setup.ApplicationBase = _basePath;
    setup.ShadowCopyFiles = "true";
    var domain = AppDomain.CreateDomain("MyDomainName" + Guid.NewGuid(), null, setup);

    (Proposed by SpArtA)

    This seems a "natural" way provided by .NET.
    As said in MSDN article:

    This setting causes all assemblies in the application path to be copied to a download cache before they are loaded.
    The copy is locked, but the original assembly file is unlocked and can be updated.
    The Common Language Runtime automatically deletes the files when they are no longer needed.

    Optionally set a custom location for shadow copied files by using the CachePath property and the ApplicationName property.

    The base path for the location is formed by concatenating the ApplicationName property to the CachePath property as a subdirectory. Assemblies are shadow copied to subdirectories of this path, not to the base path itself.

    Pros: Requires much less code than method 2 but a bit more than method 1
    Cons: You need to consider Startup Performance issues mentioned in MSDN article

Hope this tip will help you in your projects.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Nikita Mazhara
Software Developer Quipu GmbH
Ukraine Ukraine
My primary job is in development and maintainance of CutomWare.NET Core Banking application which was designed for use in ProCredit Holding.

This is a large, flexible and constantly improving system which includes a huge set of modules for Front and Back-end, payment systems, loans, deposits and whatever other the Bank may need.

Application is contributed with development of several Quipu GmbH regional offices in Kiev, Moscow, Skopje, Frankfurt, San Salvador, Bogota and Accra.

You may also be interested in...

Comments and Discussions

 
Generalmy time-saver Pin
Southmountain16-Apr-16 13:24
memberSouthmountain16-Apr-16 13:24 
AnswerGood work Pin
Sean Feldman3-Nov-14 4:17
memberSean Feldman3-Nov-14 4:17 
GeneralRe: Good work Pin
Sacha Barber3-Nov-14 12:15
mvpSacha Barber3-Nov-14 12:15 
Questiontakes me back to 2009 Pin
Sacha Barber2-Nov-14 6:40
mvpSacha Barber2-Nov-14 6:40 
AnswerRe: takes me back to 2009 Pin
Nikita Mazhara2-Nov-14 9:38
memberNikita Mazhara2-Nov-14 9:38 
GeneralRe: takes me back to 2009 Pin
Sacha Barber3-Nov-14 12:13
mvpSacha Barber3-Nov-14 12:13 
GeneralRe: takes me back to 2009 Pin
Nikita Mazhara4-Nov-14 1:22
memberNikita Mazhara4-Nov-14 1:22 
GeneralRe: takes me back to 2009 Pin
Sacha Barber4-Nov-14 3:45
mvpSacha Barber4-Nov-14 3:45 
QuestionEasy way ? Pin
SpArtA2-Nov-14 3:51
memberSpArtA2-Nov-14 3:51 
AnswerRe: Easy way ? Pin
Sacha Barber2-Nov-14 6:38
mvpSacha Barber2-Nov-14 6:38 
GeneralRe: Easy way ? Pin
Nikita Mazhara2-Nov-14 9:40
memberNikita Mazhara2-Nov-14 9:40 
AnswerRe: Easy way ? Pin
Nikita Mazhara2-Nov-14 9:43
memberNikita Mazhara2-Nov-14 9:43 
GeneralRe: Easy way ? Pin
SpArtA2-Nov-14 11:39
memberSpArtA2-Nov-14 11:39 
GeneralRe: Easy way ? Pin
Nikita Mazhara3-Nov-14 11:33
memberNikita Mazhara3-Nov-14 11:33 
GeneralRe: Easy way ? Pin
SpArtA3-Nov-14 23:02
memberSpArtA3-Nov-14 23:02 
GeneralRe: Easy way ? Pin
SpArtA2-Nov-14 11:46
memberSpArtA2-Nov-14 11:46 
GeneralRe: Easy way ? Pin
Nikita Mazhara3-Nov-14 11:35
memberNikita Mazhara3-Nov-14 11:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web06 | 2.8.181215.1 | Last Updated 2 Nov 2014
Article Copyright 2014 by Nikita Mazhara
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid