C#无法将AssemblyResolve与CreateInstanceAndUnwrap结合使用 [英] c# Cant get AssemblyResolve working in combination with CreateInstanceAndUnwrap
问题描述
嗨
在过去的几天里,我一直在努力解决AsssemblyResolve的问题.
我要实现的是一种服务的设置,该服务可以从URL更新和缓存程序集,并且能够在不重新启动服务的情况下创建和卸载AppDomain.
但是我的问题要简单得多,并且我创建了一个最小化的样本来说明我的问题.
1:带有加载程序的控制台exe
Hi
I’ve been struggling for the past couple of days with at problem with AsssemblyResolve.
What I want to achieve is a setup for a service that can update and cache assemblies from a URL, and be able to Create and UnLoad an AppDomain without restarting the service.
But my problem is much simpler, and I have created a minimized sample, which illustrate my problem.
1: a console exe with a Loader
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
namespace TestAppDoms
{
public static class Loader
{
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += FindAssem;
Program.GO();
}
public static Assembly FindAssem(object sender, ResolveEventArgs args)
{
string shortName = new AssemblyName(args.Name).Name;
using (FileStream fs = File.OpenRead(Path.Combine(@"C:\TestAssem\", shortName + ".dll")))
{
byte[] assemBin = new byte[fs.Length];
fs.Read(assemBin, 0, Convert.ToInt32(fs.Length));
Assembly Assem = Assembly.Load(assemBin);
return Assem;
}
}
}
public class Program
{
public static void GO()
{
brokerCtrl brkCtrl = new brokerCtrl();
brkCtrl.Run();
Console.ReadLine();
}
}
}
2:一个dll(象征一个现成的程序集)
2: a dll (symbolizing the a cashed assembly)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
namespace TestAppDoms
{
public class brokerCtrl
{
public void Run()
{
Console.WriteLine("Hello From Ctrl.dll " + AppDomain.CurrentDomain.FriendlyName);
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
setup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
AppDomain brokerDom = AppDomain.CreateDomain("b2bBroker", AppDomain.CurrentDomain.Evidence, setup);
brokerDom.AssemblyResolve += new ResolveEventHandler(brokerDom_AssemblyResolve);
BrokerWrapper brokerProxy = (BrokerWrapper)brokerDom.CreateInstanceAndUnwrap(typeof(BrokerWrapper).Assembly.FullName, typeof(BrokerWrapper).FullName);
brokerProxy.StartBroker();
AppDomain.Unload(brokerDom);
brokerProxy = null;
}
public static Assembly brokerDom_AssemblyResolve(object sender, ResolveEventArgs args)
{
string shortName = new AssemblyName(args.Name).Name;
Console.WriteLine("Hello from brokerDom_AssemblyResolve");
using (FileStream fs = File.OpenRead(Path.Combine(@"C:\TestAssem\", shortName + ".dll")))
{
byte[] assemBin = new byte[fs.Length];
fs.Read(assemBin, 0, Convert.ToInt32(fs.Length));
Assembly Assem = Assembly.Load(assemBin);
return Assem;
}
}
}
public class BrokerWrapper : MarshalByRefObject
{
public override object InitializeLifetimeService()
{
return null;
}
public void StartBroker()
{
Console.WriteLine("Hello From " + AppDomain.CurrentDomain.FriendlyName);
}
}
}
当将TestAppDoms.exe和brokerCtrl.dll都放置在同一目录中(CLR可以在探测路径中找到dll时),所有内容都像一个超级按钮.
但是,当我将dll从exe移开(移至C:\ TestAssem \)时,brokerDom.AssemblyResolve + =新的ResolveEventHandler(brokerDom_AssemblyResolve)不会触发-符合预期.
显然我忽略了一些东西.
有人可以帮我解决我的问题吗?
最好,Robert
When both TestAppDoms.exe and brokerCtrl.dll are placed in the same directory (and the CLR can locate the dll in the probing path) everything works like a charm.
But when I move the dll away from the exe (to the C:\TestAssem\ ) The brokerDom.AssemblyResolve += new ResolveEventHandler(brokerDom_AssemblyResolve) never fires - as expected.
Obviously I overlook something.
Can anybody help me solve my problem?
Best, Robert
推荐答案
最后,我找到了一个解决方案. (通过在NutShell中阅读Albahari C#)
首先,我定义了两个应用程序域共享的小组装.
Finally I found a solution. (by reading Albahari C# in a NutShell)
First I defined a small assemby that both appdomains share.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
namespace TestAppDoms
{
public interface Ib2bBroker
{
void StartBroker();
}
public class b2bBrokerLink : MarshalByRefObject
{
public static Dictionary<string, Assembly> assemCache;
static Dictionary<string, byte[]> assemBinCache;
public b2bBrokerLink()
{
assemCache = new Dictionary<string, Assembly>();
}
public override object InitializeLifetimeService()
{
return null;
}
public void InitAssemCache(Dictionary<string, byte[]> _assemBins)
{
assemBinCache = _assemBins;
Console.WriteLine("Assems loaded");
}
public static Assembly brokerDom_AssemblyResolve(object sender, ResolveEventArgs args)
{
string shortName = new AssemblyName(args.Name).Name;
Console.WriteLine("Hello from brokerDom_AssemblyResolve");
if (assemCache.ContainsKey(shortName))
return assemCache[shortName];
if (assemBinCache.ContainsKey(shortName))
{
Assembly assem = Assembly.Load(assemBinCache[shortName]);
assemCache.Add(shortName,assem);
return assem;
}
return null;
}
}
}
接下来修改如下的BrokerCtrl.Run()
Next modified BrokerCtrl.Run() as follows
Console.WriteLine("Hello From New Ctrl.dll " + AppDomain.CurrentDomain.FriendlyName);
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
setup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
AppDomain brokerDom = AppDomain.CreateDomain("b2bBroker", AppDomain.CurrentDomain.Evidence, setup);
brokerDom.AssemblyResolve += new ResolveEventHandler(b2bBrokerLink.brokerDom_AssemblyResolve);
b2bBrokerLink assemResolver = (b2bBrokerLink)brokerDom.CreateInstanceFromAndUnwrap(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "b2bBrokerLink.dll"), "TestAppDoms.b2bBrokerLink");
Dictionary<string,> assemBinCache = new Dictionary<string,>();
using (FileStream fs = File.OpenRead(Path.Combine(@"C:\TestAssem\", "b2bBroker" + ".dll")))
{
byte[] assemBin = new byte[fs.Length];
fs.Read(assemBin, 0, Convert.ToInt32(fs.Length));
assemBinCache.Add("b2bBroker", assemBin);
}
assemResolver.InitAssemCache(assemBinCache);
Ib2bBroker broker = (Ib2bBroker)brokerDom.CreateInstanceAndUnwrap("b2bBroker", "TestAppDoms.b2bBroker");
broker.StartBroker();
AppDomain.Unload(brokerDom);
assemResolver = null;
启动b2bBrokerLink会创建新的b2bBroker AppDomain,并允许主AppDomain下载最新的程序集版本(作为原始二进制文件),并将assemCache(Direcrory< string,byte []>)推送到b2bBroker AppDomain中.
接下来,使用接口Ib2bBroker启动代理,brokerDom_AssemblyResolve现在将能够将(最新的)程序集加载到新的AppDomain中.
这可能对其他人有用-也许有人有更好的解决方案.
Initiating b2bBrokerLink creates the new b2bBroker AppDomain and allows the main AppDomain download the most recent assembly-versions (as raw binary) and push assemCache (Direcrory<string,byte[]>) into the b2bBroker AppDomain.
Next start the a broker using the inteface Ib2bBroker and the brokerDom_AssemblyResolve will now be able to load the (most recent) assemblies into the new AppDomain.
It might be usefull for someone else - and maybe someone has a better solution.
这篇关于C#无法将AssemblyResolve与CreateInstanceAndUnwrap结合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!