阴影复制,以便不锁定程序集

时间:2011-06-27 16:39:53

标签: c# .net clr

我已经创建了一个测试库

public class Test
{
    public int Add(int val1, int val2)
    {
        return val1 + val2;
    }
}

一个叫它的项目:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;

namespace Loader
{
    class Program
    {
        static void Main(string[] args)
        {
            String path = @"...Lib.dll"; // path to lib
            var name = Path.GetFileName(path);

            AppDomainSetup setup = new AppDomainSetup  
            {
                ApplicationBase = @"...", // directory where Lib.dll is 
                ShadowCopyFiles = "true",
                ShadowCopyDirectories = @"..."// directory where Lib.dll is 
            };  

            var appdomain = AppDomain.CreateDomain("Loader." + name, null, setup);
            Assembly ass = Assembly.LoadFile(path); // <--- I think here is the problem, here where assembly is locked
            Assembly assembly = appdomain.Load(ass.FullName);

            dynamic a = assembly.CreateInstance("Lib.Test");

            Console.WriteLine(a.Add(1, 5));
        }
    }
}

请帮忙找出我做错了什么?为什么我的装配被锁定了?

带有硬编码程序集名称的

编辑

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;

namespace Loader
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomainSetup ads = new AppDomainSetup();

            String fullPath = @"c:\users\myuser\documents\visual studio 2010\Projects\ShadowCopy\Loader\bin\Debug\Lib.dll";

            ads.ShadowCopyFiles = "true";
            ads.ApplicationName = "AppName";
            ads.ShadowCopyDirectories = Path.GetDirectoryName(fullPath);
            //ads.ApplicationBase = Path.GetDirectoryName(fullPath);
            //ads.PrivateBinPath = Path.GetDirectoryName(fullPath);
            ads.CachePath = @"c:\users\myuser\documents\visual studio 2010\Projects\ShadowCopy\Loader\bin\Debug\Cache\";

            AppDomain ad = AppDomain.CreateDomain("myName" + ads.ApplicationName, null, ads);

            ad.AssemblyResolve += new ResolveEventHandler( ad_AssemblyResolve );

            Console.WriteLine(ad.ShadowCopyFiles);
            Console.WriteLine(ad.SetupInformation.ShadowCopyDirectories);

            try
            {
                //Assembly assembly = ad.Load(AssemblyName.GetAssemblyName(fullPath));
                //dynamic obj = ad.CreateInstanceAndUnwrap(assembly.GetName().Name, "Lib.Test");

                dynamic obj = ad.CreateInstanceAndUnwrap("Lib", "Lib.Test");

                Console.WriteLine(obj.Add(1, 7));

                Console.ReadKey();

                Console.WriteLine(obj.Add(1, 90));
            }
            catch( Exception e)
            {
                Console.WriteLine( e.Message );
            }
        }

        static Assembly ad_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            return Assembly.LoadFile(@"c:\users\myuser\documents\visual studio 2010\Projects\ShadowCopy\Loader\bin\Debug\Lib.dll");
        }
    }
}

有趣的是,缓存的声明也被锁定了。

编辑2:

以下是阻止程序集的代码行

Console.WriteLine(obj.Add(1, 7));

因此,一旦访问了Lib.Test中的一个方法,就会阻塞它。

可以解决什么问题?

2 个答案:

答案 0 :(得分:1)

当您运行锁定文件的Assembly.LoadFile()时,您正在将程序集加载到主AppDomain中。如果要将其直接加载到AppDomain中,则需要直接使用AppDomain.Load(),允许AppDomain根据您指定的参数解析它。请注意,由于程序集未在主AppDomain中加载,因此Main方法无法访问该类型。您的Lib.Test需要派生自MarshalByRefObject,以便编组系统可以创建代理(当您将其分配给动态代理时,代理将进一步包装到动态代理中。)


编辑:

进一步想到,我怀疑这里的问题是,为了在动态代理上调用方法,它必须反映对象(它本身是你的其他AppDomain中实例的透明代理。)如果它最终会反映原始的类类型(而不是'隐藏'透明代理类型),这将导致它在本地AppDomain中加载程序集的副本(从而将其锁定。)这是使用时的一个原因AppDomain隔离,您通常将对象强制转换为在“主”应用程序和托管AppDomain都可以引用的单独程序集中定义的接口。他们将各自获得自己的接口程序集副本,但现在“实现”程序集已被隔离。

答案 1 :(得分:0)

您有两个选项,您需要在运行时查找程序集名称并对其进行硬编码,或者如果您不知道之前的运行时间,则需要编写第二个库,您知道{{ 1}}并在AppDomain中加载它。第二个库将是一个具有一个功能的类

FullName

这应该在没有锁定它的情况下将目标加载到新的AppDomain中,因为应该使用卷影副本打开它。

编辑:至于为什么你的方法不起作用,你在哪里加载锁定它once a assembly is loaded in to a AppDomain it can not be unloaded.