从内存中将程序集加载到 Appdomain,createinstance 导致 'filenotfound' 异常
Loaded an assembly into Appdomain from memory, createinstance results in 'filenotfound' exception
对于某些上下文:我已经 运行 在第三方应用程序提供的 "plugin" 应用程序域中。这很重要,因为它限制了类加载时可以做的事情。更具体地说,此应用程序依赖于某些预定义的核心 dll 位于经典应用程序基本路径上,并从数据库动态加载其他所有内容。虽然我没有看到那个层,但它似乎没有使用文件系统(临时文件之类的东西)所以我假设它正在将所有非核心的 DLL 作为字节数组直接加载到内存中。
我有一个作为嵌入式引用加载的 DLL,它需要某个 app.config 和插件上下文中不可控制的 bin 目录,因此我打算使用 appdomain。插件中的 DLL 嵌入资源被读取为字节数组并注入到应用程序域中。
DLL 出现在创建的应用程序域的 AppDomain.GetAssemblies() 中,但是,当我尝试从该 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' 看来我无法 bootstrap我的自定义代码。
即使在我的 AppDomainSetup.AppDomainInitializer 中使用匿名委托函数,它显然也依赖于其他一些可用的 DLL。我只在我的委托中调用 GAC 对象,但它需要将执行程序集(设置应用程序域的程序集)加载到目标应用程序域中。为了传递一个匿名委托。为什么?
Could not load file or assembly 'ParentAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
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;
};
})
因此,我似乎无法让我的应用程序域在内存中查找其类型。这里有什么想法吗?
您使用的 CreateInstanceFromAndUnwrap
重载采用程序集文件而不是程序集名称。
尝试以 assembly name
作为参数的 CreateInstanceFromAndUnwrap
重载:
_proxy = (AdsRemote)_adsDomain.CreateInstanceFromAndUnwrap("ADSOCWrapper",
typeof(FeedDao).FullName);
对于某些上下文:我已经 运行 在第三方应用程序提供的 "plugin" 应用程序域中。这很重要,因为它限制了类加载时可以做的事情。更具体地说,此应用程序依赖于某些预定义的核心 dll 位于经典应用程序基本路径上,并从数据库动态加载其他所有内容。虽然我没有看到那个层,但它似乎没有使用文件系统(临时文件之类的东西)所以我假设它正在将所有非核心的 DLL 作为字节数组直接加载到内存中。
我有一个作为嵌入式引用加载的 DLL,它需要某个 app.config 和插件上下文中不可控制的 bin 目录,因此我打算使用 appdomain。插件中的 DLL 嵌入资源被读取为字节数组并注入到应用程序域中。
DLL 出现在创建的应用程序域的 AppDomain.GetAssemblies() 中,但是,当我尝试从该 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' 看来我无法 bootstrap我的自定义代码。
即使在我的 AppDomainSetup.AppDomainInitializer 中使用匿名委托函数,它显然也依赖于其他一些可用的 DLL。我只在我的委托中调用 GAC 对象,但它需要将执行程序集(设置应用程序域的程序集)加载到目标应用程序域中。为了传递一个匿名委托。为什么?
Could not load file or assembly 'ParentAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
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;
};
})
因此,我似乎无法让我的应用程序域在内存中查找其类型。这里有什么想法吗?
您使用的 CreateInstanceFromAndUnwrap
重载采用程序集文件而不是程序集名称。
尝试以 assembly name
作为参数的 CreateInstanceFromAndUnwrap
重载:
_proxy = (AdsRemote)_adsDomain.CreateInstanceFromAndUnwrap("ADSOCWrapper",
typeof(FeedDao).FullName);