Невозможно привести прозрачный прокси в dll при вызове из PowerShell, но успешно в консольном приложении C # - PullRequest
3 голосов
/ 24 сентября 2011

Я пытаюсь создать библиотеку с открытым исходным кодом , которая порождает новый AppDomain и запускает в ней скрипт PowerShell. У меня есть статический метод, который принимает имя файла powershell и имя AppDomain. Метод успешно выполняется при вызове из консольного приложения C #, но не PowerShell.

Я знаю, что dll загружается во второй домен приложения из-за этой записи в fusionlog .

Объявление класса и конструктор выглядят следующим образом.

public class AppDomainPoshRunner : MarshalByRefObject{

    public AppDomainPoshRunner (){
        Console.WriteLine("Made it here.");
    }
}

Это сообщение в конструкторе выводится, когда я вызываю CreateInstanceFromAndUnwrap независимо от того, запускаю ли я dll из консольного приложения C # или из приложения PowerShell.

Ошибка возникает, когда я приведу значение, возвращаемое CreateInstanceFromAndUnwrap к AppDomainPoshRunner в статическом методе ниже.

    public static string[] RunScriptInAppDomain(string fileName, string appDomainName = "Unamed")
    {
        var assembly = Assembly.GetExecutingAssembly();

        var setupInfo = new AppDomainSetup
                            {
                                ApplicationName = appDomainName,
                                // TODO: Perhaps we should setup an even handler to reload the AppDomain similar to ASP.NET in IIS.
                                ShadowCopyFiles = "true"
                            };
        var appDomain = AppDomain.CreateDomain(string.Format("AppDomainPoshRunner-{0}", appDomainName), null, setupInfo);
        try {
            var runner = appDomain.CreateInstanceFromAndUnwrap(assembly.Location, typeof(AppDomainPoshRunner).FullName);
            if (RemotingServices.IsTransparentProxy(runner))
                Console.WriteLine("The unwrapped object is a proxy.");
            else
                Console.WriteLine("The unwrapped object is not a proxy!");  
            Console.WriteLine("The unwrapped project is a {0}", runner.GetType().FullName);
            /* This is where the error happens */
            return ((AppDomainPoshRunner)runner).RunScript(fileName);
        }
        finally
        {
            AppDomain.Unload(appDomain);
        }
    }

При запуске этого в PowerShell я получаю InvalidCastExcception с сообщением Невозможно привести прозрачный прокси к типу JustAProgrammer.ADPR.AppDomainPoshRunner.

Что я делаю не так?

Ответы [ 2 ]

2 голосов
/ 07 декабря 2012

У меня была та же проблема: я создал изолированную программную среду с разрешениями «Выполнять только» (минимум), чтобы выполнять ненадежный код в очень ограниченной среде.Все отлично работало в приложении C #, но не работало (то же исключение приведения), когда отправной точкой был vbs-скрипт, создающий .NET COM-объект.Я думаю, что PowerShell также использует COM.Я нашел обходной путь, используя AppDomain.DoCallBack, который позволяет избежать получения прокси из домена приложения.Это код.Если вы найдете лучший вариант, пожалуйста, напишите.Регистрация в GAC не является хорошим решением для меня ...

    class Test
    {
        /*
         create appdomain as usually
        */

        public static object Execute(AppDomain appDomain, Type type, string method, params object[] parameters)
        {
            var call = new CallObject(type, method, parameters);
            appDomain.DoCallBack(call.Execute);
            return call.GetResult();
        }
    }
    [Serializable]
    public class CallObject
    {
        internal CallObject(Type type, string method, object[] parameters)
        {
            this.type = type;
            this.method = method;
            this.parameters = parameters;
        }

        [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
        public void Execute()
        {
            object instance = Activator.CreateInstance(this.type);
            MethodInfo target = this.type.GetMethod(this.method);
            this.result.Data = target.Invoke(instance, this.parameters);
        }

        internal object GetResult()
        {
            return result.Data;
        }

        private readonly string method;
        private readonly object[] parameters;
        private readonly Type type;
        private readonly CallResult result = new CallResult();

        private class CallResult : MarshalByRefObject
        {
            internal object Data { get; set; }
        }
    }
0 голосов
/ 25 сентября 2011

Это очень похоже на проблему с контекстом загрузки. Идентификация типа - это не только файл физической сборки; это также о том, как и где это было загружено. Вот старая запись в блоге от Сюзанны Кук, которую вам, вероятно, придется читать пятнадцать раз, пока вы не начнете понимать свою проблему.

Выбор связующего контекста

http://blogs.msdn.com/b/suzcook/archive/2003/05/29/57143.aspx

Прежде чем сказать "но это работает в консольном приложении", запомните, что при запуске его из powershell у вас есть совершенно иная ловушка с точки зрения контекста вызывающего домена приложения, путей поиска, идентификации и т. Д.

Удачи!

...