我在两个.NET应用程序域之间传递一些数据时遇到了一些麻烦,我希望有人可以帮助我.
基本上我所拥有的是一个主应用程序(Main),它将程序集A和B加载到它的主域中,然后当我运行一个插件时(C)Main在B上调用一个创建域方法,它创建一个新域并加载C和一个实例将B放入其中,以便C只能访问B而不能访问其他人.
B包含一个指向Main的IDispatch的指针,但只有它在用C加载到新域后才会得到它.我要做的是从B的新域实例发送指针的副本,并将其发送到仍在默认域中运行的A.
只是为了记录我控制A,B和C但不控制主要
对不起,如果这有点难以理解,我尽力解释.
码:
在一个:
public class Tunnel : MarshalByRefObject
{
public void SetPointer(int dispID)
{
IntPtr pointer = new IntPtr(dispID);
}
}
Run Code Online (Sandbox Code Playgroud)
在B:
//Call by Main after loading plug in but after A.dll is loaded.
public void CreateDomain()
{
AppDomain maindomain= AppDomain.CurrentDomain;
tunnel = (Tunnel)maindomain.CreateInstanceAndUnwrap(typeof(Tunnel).FullName,
typeof(Tunnel).FullName); …Run Code Online (Sandbox Code Playgroud) 是否可以从程序集中读取GUID,而无需在当前App域中实际加载它.
通常,Assembly.Load将DLL加载到app域中.我只想读取价值.
GUID的描述是
'The following GUID is for the ID of the typelib
' if this project is exposed to COM
<Assembly: Guid("DEDDE61CD-928E-4ACD-8C25-3B8577284819")>
Run Code Online (Sandbox Code Playgroud)
在主要的事情是我不想要锁定的文件,以便有没有错误"另一个进程正在访问该文件"的错误.
我试图找到一种在运行时编译程序集并加载它们的方法.基本意图是将它们存储在不在光盘上的数据库中.所以我写了一些代码,但看到了一个有趣的情况.这是我的代码:
//SumLib
namespace SumLib
{
public class SumClass
{
public static int Sum(int a, int b)
{
return a + b;
}
}
}
// Console app
class Program
{
public static void AssemblyLoadEvent(object sender, AssemblyLoadEventArgs args)
{
object[] tt = { 3, 6 };
Type typ = args.LoadedAssembly.GetType("SumLib.SumClass");
MethodInfo minfo = typ.GetMethod("Sum");
int x = (int)minfo.Invoke(null, tt);
Console.WriteLine(x);
}
static void Main(string[] args)
{
AppDomain apd = AppDomain.CreateDomain("newdomain", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation);
apd.AssemblyLoad += new AssemblyLoadEventHandler(AssemblyLoadEvent);
FileStream fs = new FileStream("Sumlib.dll", …Run Code Online (Sandbox Code Playgroud) 我想以一种孤立的方式运行来自不同.dll的多个服务.基本上,所有服务都是从中派生出来的RoleEntryPoint,我希望将每个服务分开加载AppDomain并在不同的线程中运行它.
到目前为止,我可以找到服务并获取其类型:
String pathToDll = @"C:\....\bin\Debug\ChildWorkerRole.dll";
Assembly assembly = Assembly.LoadFrom(pathToDll);
Type serviceType = assembly.GetTypes().SingleOrDefault(t => t.BaseType == typeof(RoleEntryPoint));
Run Code Online (Sandbox Code Playgroud)
而在目前还运行AppDomain和Thread:
RoleEntryPoint myRole2 = (RoleEntryPoint)Activator.CreateInstance(serviceType);
if (myRole2.OnStart())
myRole2.Run();
Run Code Online (Sandbox Code Playgroud)
但是当我尝试在不同的AppDomain中单独运行它时,我得到一个例外:
AppDomain domain = AppDomain.CreateDomain("MyNewDomain");
RoleEntryPoint myRole = (RoleEntryPoint)domain.CreateInstanceFromAndUnwrap(pathToDll, serviceType.FullName);
if (myRole.OnStart())
myRole.Run();
Run Code Online (Sandbox Code Playgroud)
这个例外:
System.Runtime.Serialization.SerializationException was unhandled
Message=Type 'ChildWorkerRole.WorkerRole' in assembly 'ChildWorkerRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
Source=mscorlib
StackTrace:
at System.AppDomain.CreateInstanceFromAndUnwrap(String assemblyName, String typeName)
.......
Run Code Online (Sandbox Code Playgroud)
有趣的是,ChildWorkerRole它实际上标有SerializableAttribute...但可能是因为RoleEntryPoint不是,它无法完成.
任何想法或解决方法? …
我需要在c#(伪)中做这样的事情:
static var ns = new Non_Serializable_Nor_Marshal()
var app = new AppDomain();
app.execute(foo)
void foo()
{
var host = AppDomain.Current.Parent; //e.g. the original one
host.execute(bar)
}
void bar()
{
ns.Something();
}
Run Code Online (Sandbox Code Playgroud)
我在一个应用程序域中有一个非序列化或编组对象.我想创建第二个域并执行foo().从第二个域内我想在原始域上执行bar().
如何将原始域名传递给孩子?
假设我有.Net应用程序App.exe,它创建三个域:DomainA,DomainB和DomainC.
我们可以说CLR会为App.exe进程分配一些物理内存,然后这个内存在我们的三个域之间分成一定比例吗?
或者对于每个新域,独立于App.exe和其他域分配的内存给出一个新的独立内存部分?
简单来说:我可以将逻辑内存分配想象为带有歌曲的(顺序)磁带(其中歌曲是AppDomans),或者作为一种FAT32,其中文件随机定位,我们只知道它们在磁盘上的位置?
不知何故,我假设传递给另一个 AppDomain 的委托会变成一个代理,就好像它是从MarshalByRefObject. 不幸的是,他们似乎没有。
假设在我的代码中我有一个MyClass这样的类:
[Serializable]
public sealed class MyClass
{
public Func<Input, Output> SomeDelegate;
}
[Serializable]
public sealed class Input { ... }
[Serializable]
public sealed class Output { ... }
Run Code Online (Sandbox Code Playgroud)
现在我需要将 的实例传递MyClass给另一个 AppDomain。
问题是存储在的委托SomeDelegate可能包含对几乎任何方法的引用,包括潜在的类型实例上的方法,它既不是[Serializable]也不是派生自MarshalByRefObject.
对于这个问题的缘故,让我们假设我不能改变的创建委托的代码,我也可以做MyClass一个MarshalByRefObject。然而,它是[Serializable]。
(请注意,如果MyClass包含派生自 类型的字段MarshalByRefObject,则存储在该字段中的对象将变成代理,而类的其余部分将被序列化。)
有什么我可以做的事情可以让我将类作为序列化传递,但是委托变成了代理,就像它是一个MarshalByRefObject? (最好在 AppDomain 的设置中这样我就不需要更改MyClass,但也欢迎涉及更改类的建议,只要我不需要更改创建委托的代码。)
我正在实现支持插件的应用程序。当前,当我尝试加载由主机应用程序和插件使用的通用程序集时,会出现问题 :主机应用程序应使用该程序集的一个版本,而插件使用另一版本。这由应用程序升级过程决定-插件可以与主机应用程序分开进行更新。
每个程序集都经过签名,因此我使用强名称来加载程序集。
我创建了一个演示该问题的测试应用程序。插件程序集位于主机应用程序的子文件夹“ Plugin”中。Plugin文件夹包含插件实现DLL,插件声明接口DLL和CommonLib DLL。主机应用程序还使用插件声明DLL和CommonLib DLL(位于文件夹树中的上一级)。
这是插件加载的源代码:
static void Main(string[] args)
{
Console.WriteLine("Host says: {0}", GreetingManager.SayHello("Sasha"));
Console.WriteLine("Host says: {0}", GreetingManager.SayGoodBye("Sasha"));
var pluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugin");
var pluginFile = Directory.GetFiles(pluginDir).First(f => f.EndsWith("Plugin.dll"));
Assembly asmr = Assembly.ReflectionOnlyLoadFrom(pluginFile);
AppDomain pluginDomain = AppDomain.CreateDomain("Plugin", null, pluginDir, "", false);
pluginDomain.Load(asmr.FullName);
Assembly asm = pluginDomain.GetAssemblies().First(a => a.GetName().Name == "Plugin");
Type p = asm.GetTypes().First(t => t.GetInterfaces().Contains(typeof(IPlugin)));
var pluginInstance = (IPlugin)pluginDomain.CreateInstanceAndUnwrap(asm.FullName, p.FullName);
Console.WriteLine("Plugin says: {0}", pluginInstance.TransformString("Sasha"));
}
Run Code Online (Sandbox Code Playgroud)
它引发异常:
Unhandled Exception: System.IO.FileLoadException: Could not load file …Run Code Online (Sandbox Code Playgroud) 在下面的示例应用程序中,我创建了一个新的AppDomain,我执行它并启用了卷影复制.从新的AppDomain我然后尝试删除(替换)原来的主exe.但是我收到"访问被拒绝错误".有趣的是,在启动程序后,从Windows资源管理器中可以重命名主exe(但不能删除它).
阴影复制可以用于运行时覆盖主exe吗?
static void Main(string[] args)
{
// enable comments if you wanna try to overwrite the original exe (with a
// copy of itself made in the default AppDomain) instead of deleting it
if (AppDomain.CurrentDomain.IsDefaultAppDomain())
{
Console.WriteLine("I'm the default domain");
System.Reflection.Assembly currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
string startupPath = currentAssembly.Location;
//if (!File.Exists(startupPath + ".copy"))
// File.Copy(startupPath, startupPath + ".copy");
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationName = Path.GetFileName(startupPath);
setup.ShadowCopyFiles = "true";
AppDomain domain = AppDomain.CreateDomain(setup.ApplicationName, AppDomain.CurrentDomain.Evidence, setup);
domain.SetData("APPPATH", …Run Code Online (Sandbox Code Playgroud) 从记忆中,微软拿走AppDomain了,这个机制已经被关闭了。
现在突然发现AppDomain又回来了:
程序集 System.Runtime.Extensions,版本=4.2.1.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a\dotnet\packs\Microsoft.NETCore.App.Ref\3.0.0\ref\netcoreapp3.0\System.Runtime.Extensions.dll
该程序集包含 AppDomain 类。
这是我的问题:为什么?