我的程序包含隐藏在一个可执行文件中的所有DLL。我正在为这个程序开发插件支持。
exe中的所有DLL都作为嵌入式资源存储。以下代码用于访问这些嵌入资源:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
var resourceName = Assembly.GetExecutingAssembly()
.GetManifestResourceNames()
.FirstOrDefault(x => x.EndsWith(new AssemblyName(args.Name).Name + ".dll"));
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
if (stream == null)
return null;
var assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
插件在单独的域中加载,以便卸载它们:
public static T CreateInstanceInNewAppDomain<T>(bool shadowCopy = true)
{
var cdSetupInf = AppDomain.CurrentDomain.SetupInformation;
var separateDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString(), null,
new AppDomainSetup()
{
LoaderOptimization = LoaderOptimization.MultiDomain,
ApplicationBase = cdSetupInf.ApplicationBase,
PrivateBinPath = cdSetupInf.PrivateBinPath,
ShadowCopyFiles = shadowCopy ? "true" : "false"
});
var type = typeof(T);
return (T)separateDomain.CreateInstanceFromAndUnwrap(type.Assembly.Location, type.FullName);
}
以前代码中最重要的部分是在单独的域上为创建对象调用“ CreateInstanceFromAndUnwrap ”。如果包含DLL的类型将在HDD上,则这部分代码将很好地工作。由于它是从嵌入式资源加载的,因此assemblyFile参数(表示为type.Assembly.Location)为空。因此,我无法创建我用于访问插件功能的IPluginAccessor实例。有没有什么方法可以在不需要指定assemblyName的情况下在单独的域中创建类型实例?如果有像 AppDomain.CreateInstanceFromAndUnwrap(Type type)这样的东西会很棒。如果我看起来很好,只有 Activator.CreateInstance(类型类型),但这适用于当前域而不是我指定的域。
非常感谢
答案 0 :(得分:0)
我认为您可以使用将在新AppDomain中执行的Callback。
定义辅助类:
class AnotherAppDomainPluginBuilder<T> : MarshalByRefObject
where T : new()
{
T Result { get; set; }
public void Create()
{
LoadRelevantDlls();
this.Result = new T();
}
void LoadRelevantDlls()
{
// load whatever DLLs in whatever way you would like to
}
}
然后代替:
return (T)separateDomain.CreateInstanceFromAndUnwrap(type.Assembly.Location, type.FullName);
写:
AnotherAppDomainPluginBuilder<T> builder =
(T)separateDomain.CreateInstanceFromAndUnwrap(
Assembly.CurrentAssembly,
typeof(AnotherAppDomainPluginBuilder<T> ));
separateDomain.DoCallback(builder.Create);
return builder.Result;