Use .NET assembly without locking dll file
Asked Answered
N

1

6

I have a windows service that executes once a day. It's only 10 minutes of action.

I build the service's files in the bin folder of the website, because the service uses the website dll's.

Unfortunately I noticed that when I installed the website module (dotnetnuke .zip module by website installer) I got an error that the file is locked by antoher process.

Disabling the service before each module is installed is very problematic so I want to make my service not lock the dll's which are used in it.

I read about the AppDomain and ShadowCopyFiles options, but I can NOT make them work for me.

This is an example of how I use ShadowCopyFiles:

class Program
{
    static string GenerateRandomName()
    {
        //maybe name must be unique?!
        var random = new Random();
        return "a" + random.Next().ToString() + "b" + random.Next();
    }

    static int RandomNumber()
    {
        var info = ConfigureAppDomainSettings();

        var domain = AppDomain.CreateDomain(GenerateRandomName(), null, info);
        var assembly = domain.Load("SharedLibrary");
        var shared = (SharedLibrary.IShared)assembly.CreateInstance("SharedLibrary.Shared");

        int retVal = shared.RandomNumber();

        AppDomain.Unload(domain);

        domain = null;
        assembly = null;
        shared = null;
        info = null;

        Console.WriteLine("before cleanning");
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        GC.WaitForFullGCComplete();
        GC.Collect();
        Console.WriteLine("after cleanning");

        return retVal;
    }

    static AppDomainSetup ConfigureAppDomainSettings()
    {
        AppDomainSetup domainSettings = AppDomain.CurrentDomain.SetupInformation;
        domainSettings.ShadowCopyFiles = "true";
        domainSettings.CachePath = @"C:\inetpub\wwwroot\eshop\DesktopModules\Rossnet_EShop\SharedAssemblyTest\PrivateCache";

        return domainSettings;
    }

    static void Main(string[] args)
    {
        Console.WriteLine(RandomNumber());

        Console.ReadKey();
    }
}

Code of example assembly:

public interface IShared
{
    int RandomNumber();
}

[Serializable]
public class Shared : IShared
{
    public int RandomNumber()
    {
        var random = new Random();
        return random.Next(20);
    }
}

A private cache is created and not locked and the original file is locked. <- right now this is absurd for me.

Nosey answered 21/7, 2014 at 20:6 Comment(2)
Your IShared interface gets loaded into both appdomains. Which puts a permanent lock on the DLL. Put the Shared class it in another one.Aposematic
I cast to dynamic type instead of interface previously and it didn't work, so it isn't the only problem with my code.Shrewish
H
9

If you have access to modify all code that uses the assemblies, simply loading them by the Assembly.Load overload that takes a byte[] should do the trick. You'll read the file yourself, and pass it to that method. I use this approach myself (for other reasons though), and it gives me the ability to update the files at any time.

A way of doing this easily (albeit a bit weird) is to rename your files (from .dll to something else, so they can't be found) and then subscribe to the AppDomain.AssemblyResolve event, which will be called when they're missing, at which point you can have your code that manually loads the assemblies.

Heymann answered 21/7, 2014 at 20:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.