问题描述
我需要读取在同一进程中但在不同 appDomain 中运行的应用程序 (Core.exe) 的标准输出.在处理流程时重定向输出非常容易,但 appDomains 概念对我来说是新的.
I need to read standart output from application (Core.exe) that runs in the same process but in different appDomain. It's quite easy to redirect output when one deals with process but the appDomains concept is new to me.
所以.. 我在孤立的 appDomain 中启动应用程序
So.. I start application in isolataed appDomain like that
new HostedApp("core", "Core.exe").Run();
class HostedApp
{
internal string DomainName;
internal string AssemblyName;
internal AppDomain Ad;
internal Thread AppThrd;
public HostedApp(string a_domain, string a_assemblyName)
{
DomainName = a_domain;
AssemblyName = a_assemblyName;
Ad = AppDomain.CreateDomain(a_domain);
}
public void Run()
{
AppThrd = new Thread(RunApp);
AppThrd.Start();
}
private void RunApp()
{
try
{
Ad.ExecuteAssembly(AssemblyName);
}
catch(Exception _ex)
{
MessageBox.Show("Unhandled exception\n" + _ex);
}
}
}
我已经尝试将 Console.Out 重定向到当前进程,假设如果应用程序共享相同的进程,则会有单个标准输出.
I've tride to redirect Console.Out of the current process assuming that if the apps share the same process there will be single standart output.
但它只显示默认的 appDomain 标准输出.
But it only shows the default appDomain standart output.
所以,总而言之,我需要访问另一个 appDomain 应用程序标准输出.或者有没有办法从核心"appDomain 调用位于默认 appDomain 中的方法?
So, to sum it up I need to gain access to another appDomain application standart output. Or may be there is a way to call a method located in default appDomain from "core" appDomain?
推荐答案
也许这可以帮到你.我使用这些类能够监听远程 AppDomains Trace.(Write/WriteLine) 调用.
Maybe this can help you.I use these classes to be able to listen to remote AppDomains Trace.(Write/WriteLine) calls.
第一个类是允许我将 TraceListen Write/WriteLine 方法重定向到自定义委托的类.
The first class is a class that allows me to redirect the TraceListen Write/WriteLine methods to a custom delegate.
public delegate void TraceWriterHandler(string message);
internal class SynchronizedTraceListener : TraceListener
{
private TraceWriterHandler messageHandler;
public SynchronizedTraceListener(TraceWriterHandler writeHandler)
{
messageHandler = writeHandler;
}
public override void Write(string message)
{
messageHandler(message);
}
public override void WriteLine(string message)
{
messageHandler(message + System.Environment.NewLine);
}
}
然后是我的远程 AppDomain 跟踪侦听器类的核心.这是棘手的部分.我会尽量不搞乱解释.这对我来说很棘手,但在这里.
Then the core of my remote AppDomain trace listener class.This is the tricky part. I'll try not to mess the explanation. This is tricky for me to, but here it goes.
- (本地)CrossDomainTracer 对象在远 AppDomain 上创建(远)CrossDomainTracer 对象.
- (本地)CrossDomainTracer 对象调用(远)CrossDomainTracer 对象 .StartListening 并将其自身发送(本地)作为参考.
- (远)CrossDomainTracer 对象开始侦听(远)他的域中的任何 Trace.Write/WriteLine 调用.
- 当进行(远)Trace.Write/WriteLine 调用时,它会从(本地)远程 AppDomain 调用 .RemoteWrite 方法.
- (本地).RemoteWrite 调用它自己的 AppDomain 范围 Trace.Write,以便(本地)侦听器可以正确显示消息.
注意事项:
- AssemblyResolve 可确保在尝试引用包含此代码的程序集时出错.
- 此代码必须存在于两个进程中并共享相同的命名空间.我在库中使用它并将程序集引用添加到两个应用程序中.
- 还要注意 Serializable 属性和 MarshalByRefObject 继承.这是框架在 AppDomains 之间正确编组对象所必需的.
[Serializable]
public sealed class CrossDomainTracer : MarshalByRefObject
{
private CrossDomainTracer remoteTracer;
private SynchronizedTraceListener remoteListener;
public CrossDomainTracer()
{
}
public CrossDomainTracer(AppDomain farDomain)
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
this.remoteTracer = farDomain.CreateInstanceFrom(Assembly.GetExecutingAssembly().Location, typeof(CrossDomainTracer).FullName).Unwrap() as CrossDomainTracer;
AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
if (remoteTracer != null)
{
remoteTracer.StartListening(this);
}
}
public void StartListening(CrossDomainTracer farTracer)
{
this.remoteTracer = farTracer;
this.remoteListener = new SynchronizedTraceListener(new TraceWriterHandler(Write));
Trace.Listeners.Add(this.remoteListener);
}
public void Write(string message)
{
this.remoteTracer.RemoteWrite("AppDomain(" + AppDomain.CurrentDomain.Id.ToString() +") " + message);
}
public void RemoteWrite(string message)
{
Trace.Write(message);
}
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
try
{
Assembly assembly = System.Reflection.Assembly.Load(args.Name);
if (assembly != null)
{
return assembly;
}
}
catch { }
// Try to load by assembly fullname (path to file)
string[] Parts = args.Name.Split(',');
string File = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + Parts[0].Trim() + ".dll";
return System.Reflection.Assembly.LoadFrom(File);
}
}
最后,您可以将所有这些巧妙地打包到一个静态类中.
Finnaly you can neatly pack all this in a static class.
public static class CrossDomainTrace
{
public static void StartListening(AppDomain remoteDomain)
{
new CrossDomainTracer(remoteDomain);
}
}
通过在将注册远 Trace 按摩的应用中执行此操作.
By doing this in the app that will be registering the far Trace massages.
CrossDomainTrace.StartListening(theFarAppDomain);
剩下的唯一一件事就是将一个 TraceListner 添加到这一侧的 Trace.Listeners 集合中,以便对消息执行您想要的任何操作.
The only thing left is to add a TraceListner to the Trace.Listeners collection on this side to do what ever you want with the messages.
希望有帮助.
这篇关于跨应用域访问 Console.Out的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!