Вопрос по appdomain, c# – Кросс-приложениеДоменный доступ к Console.Out

2

Мне нужно прочитать стандартный вывод из приложения (Core.exe), который выполняется в том же процессе, но в другом домене приложения. Это довольно легко перенаправить вывод, когда кто-то имеет дело с процессом, но концепция appDomains для меня нова.

Итак .. я запускаю приложение в изолированном домене приложения, вот так

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 текущего процесса, предполагая, что если приложения совместно используют один и тот же процесс, будет один стандартный вывод.

Но он показывает только стандартный вывод appDomain по умолчанию.

Итак, чтобы подвести итог, мне нужно получить доступ к другому стандартному выводу приложения appDomain. Или, может быть, есть способ вызвать метод, расположенный в стандартном appDomain из «основного» appDomain?

Ваш Ответ

1   ответ
6

это может помочь вам. Я использую эти классы, чтобы иметь возможность прослушивать удаленные вызовы AppDomains Trace. (Write / WriteLine).

Первый класс - это класс, который позволяет мне перенаправлять методы TraceListen Write / WriteLine пользовательскому делегату.



    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. Это сложная часть. Я постараюсь не связываться с объяснением. Это сложно для меня, но здесь это идет.

(Локальный) объект CrossDomainTracer создает (удаленный) объект CrossDomainTracer в удаленном домене приложений.(Локальный) объект CrossDomainTracer вызывает (дальний) объект CrossDomainTracer .StartListening и отправляет (локально) его сам в качестве ссылки.(Дальний) объект CrossDomainTracer начинает прослушивать любые вызовы Trace.Write / WriteLine в (дальнем) его домене.Когда выполняется (дальний) вызов Trace.Write / WriteLine, он вызывает метод .RemoteWrite из (локального) удаленного AppDomain.(Локальный) .RemoteWrite выполняет вызов своей собственной области AppDomain Trace.Write, чтобы (локальный) прослушиватель мог правильно отобразить сообщение.

Примечания:

AssemblyResolve обеспечивает ошибки при попытке ссылки на сборку, которая содержит этот код.Этот код должен существовать в обоих процессах и совместно использовать одно и то же пространство имен. Я использую его в библиотеке и добавляю ссылку на сборку в оба приложения.Также обратите внимание на атрибут Serializable и наследование MarshalByRefObject. Это требуется платформой для правильного распределения объектов между доменами приложений.



    [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(',');
            s,tring File = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + Parts[0].Trim() + ".dll";

            return System.Reflection.Assembly.LoadFrom(File);
        }
    }

В конце концов вы можете аккуратно упаковать все это в статический класс.



    public static class CrossDomainTrace
    {
        public static void StartListening(AppDomain remoteDomain)
        {
            new CrossDomainTracer(remoteDomain);
        }
    }

Делая это в приложении, которое будет регистрировать массажи Trace.



    CrossDomainTrace.StartListening(theFarAppDomain);

Осталось только добавить TraceListner в коллекцию Trace.Listeners на этой стороне, чтобы делать с сообщениями все, что вы захотите.

Надеюсь, это поможет.

Это помогло. Спасибо. Я закончил тем, что отправил ссылку на TextWriter из стандартного appDomain в удаленный и использовал WriteLine в нем в методе RemoteWrite wazelin

Похожие вопросы