对于某些情况:我已经在"插件中运行" appdomain由第三方应用程序提供。这很重要,因为它限制了在类加载时可以做的事情。更具体地说,该应用程序依赖于某些预定义的核心dll在经典应用程序基本路径上,并从数据库动态加载其他所有内容。虽然我没有查看该层,但它似乎没有使用文件系统(tempfile类的东西)所以我假设它将所有非核心的DLL直接加载到内存中作为字节数组。
我有一个DLL作为嵌入式引用加载,需要在插件上下文中无法控制的某个app.config和bin目录,因此我打算使用appdomain。插件中的DLL嵌入式资源被读取为字节数组并注入到appdomain中。
DLL在AppDomain.GetAssemblies()中显示为创建的appdomain,但是,当我尝试从该DLL创建实例时,它会抱怨" FileNotFound"。我已经检查过FullNames是否匹配等。这引发了第一个也是最简单的问题:为什么要查找已经加载的DLL?它似乎是故意跳过所有加载字节数组的程序集,以便查找类型。我已经尝试禁用基本路径探测,只是将错误从FileNotFound更改为更通用的引用未找到错误。下面是试图使用内存注入DLL并失败的代码。
public AdsAdapter(Context context)
{
try
{
var adsPath = session.GetSystemSetting("SpecialConfig");
var adsBin = Path.Combine(session.GetSystemSetting("SpecialBin"), @"special\path");
AppDomainSetup appSetup = new AppDomainSetup()
{
ApplicationName = "ExtendsProxyOC",
ApplicationBase = adsBin,
PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory,
ConfigurationFile = System.IO.Path.Combine(adsPath,"cs_client_app.config")
};
_adsDomain = AppDomain.CreateDomain("adsDomain"+Guid.NewGuid(),
null,appSetup);
// add inmemory DLL
var dll = Assembly.GetAssembly(typeof(AdsAdapter))
.GetManifestResourceStream(resourcespath + "ADSOCWrapper.dll");
var dlldbg = Assembly.GetAssembly(typeof(AdsAdapter))
.GetManifestResourceStream(resourcespath + "ADSOCWrapper.pdb");
Assembly asmWrapper = _adsDomain.Load(StreamToBytes(dll), StreamToBytes(dlldbg));
// Load a file which IS in the bin directory filesystem
_adsDomain.Load("ads_core");
// the DLL IS in memory at this point and this proves it. Type definitions are there, looks fine.
Assembly[] assm = _adsDomain.GetAssemblies();
// error occurs here "FileNotFound" in the app base for the .DLL file. Why is it trying to load from disk when it is already loaded?
_proxy = (AdsRemote)_adsDomain.CreateInstanceFromAndUnwrap("ADSOCWrapper",
typeof(AdsRemote).FullName,
true, //case search
System.Reflection.BindingFlags.CreateInstance, //bindingattr
null, //Binder
new object[]{}, //args
null, //culture
null);//activationattr
}
catch (Exception e)
{
throw e;
}
}
static byte[] StreamToBytes(Stream input)
{
var capacity = input.CanSeek ? (int)input.Length : 0;
using (var output = new MemoryStream(capacity))
{
int readLength;
var buffer = new byte[4096];
do
{
readLength = input.Read(buffer, 0, buffer.Length);
output.Write(buffer, 0, readLength);
}
while (readLength != 0);
return output.ToArray();
}
}
}
我的下一步是尝试重写程序集解析过程,我认为这可能是答案,但由于我没有文件系统dll' anchor'好像我无法引导我的自定义代码。
即使在我的AppDomainSetup.AppDomainInitializer中使用匿名委托函数,它显然依赖于其他一些可用的DLL。我只在我的委托中调用GAC对象,但它要求父执行程序集(设置appdomain的程序集)被加载到目标appdomain中。为了传递匿名代表。为什么呢?
无法加载文件或程序集' ParentAssembly,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'或其中一个依赖项。系统找不到指定的文件。
AppDomainInitializer = new AppDomainInitializer(delegate(string[] target)
{
AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args)
{
if (args.Name.Contains("ADSOCWrapper"))
{
return Array.Find(AppDomain.CurrentDomain.GetAssemblies(),
x => x.FullName.Contains("ADSOCWrapper"));
}
return null;
};
})
因此,我似乎无法让我的appdomain在内存中查找其类型。这里有什么想法吗?
答案 0 :(得分:1)
您使用CreateInstanceFromAndUnwrap
的重载需要汇编文件而不是汇编名称。
尝试以assembly name
作为参数的 _proxy = (AdsRemote)_adsDomain.CreateInstanceFromAndUnwrap("ADSOCWrapper",
typeof(FeedDao).FullName);
重载:
// Both cause the warning
ptr[i] += (unsigned char) 32;
ptr[i] = tolower(ptr[i]);