从PowerShell调用时无法在dll中强制转换透明代理,但在C#控制台应用程序中成功

从PowerShell调用时无法在dll中强制转换透明代理,但在C#控制台应用程序中成功,c#,powershell,appdomain,marshalbyrefobject,C#,Powershell,Appdomain,Marshalbyrefobject,我正在尝试创建一个新的AppDomain,并在其中运行PowerShell脚本。我有一个静态方法,它采用powershell文件名和AppDomain的名称。当从C#控制台应用程序调用该方法时,该方法会成功执行,但不会PowerShell 我知道dll正在第二个应用程序域中加载,因为 类声明和构造函数如下所示 public class AppDomainPoshRunner : MarshalByRefObject{ public AppDomainPoshRunner (){

我正在尝试创建一个新的
AppDomain
,并在其中运行
PowerShell
脚本。我有一个静态方法,它采用powershell文件名和
AppDomain
的名称。当从C#控制台应用程序调用该方法时,该方法会成功执行,但不会
PowerShell

我知道dll正在第二个应用程序域中加载,因为

类声明和构造函数如下所示

public class AppDomainPoshRunner : MarshalByRefObject{

    public AppDomainPoshRunner (){
        Console.WriteLine("Made it here.");
    }
}
无论是从C#控制台应用程序还是从PowerShell应用程序运行dll,当我调用时,构造函数中的消息都会得到输出

当我在下面的静态方法中将
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中运行时,我得到一个
invalidcastexception
,消息是无法将透明代理强制转换为类型
JustAProgrammer.ADPR.AppDomainPoshRunner


我做错了什么?

听起来很像是加载上下文问题。类型标识不仅仅是物理程序集文件;它还涉及如何以及在何处加载。这里有一篇苏珊娜·库克(Suzanne Cook)的旧博文,你可能要读十五遍,直到你开始理解你的问题

选择绑定上下文

在您说“但它在控制台应用程序中工作”之前,请记住,当从powershell运行它时,您在调用appdomain的上下文、探测路径、身份等方面遇到了完全不同的麻烦


祝你好运

我也遇到了同样的问题:我创建的沙盒具有仅执行权限(最小权限),可以在非常受限的环境中执行不受信任的代码。所有这些都在C#应用程序中工作得很好,但当起点是vbs脚本创建.NET COM对象时,这些都不起作用(相同的强制转换例外)。我认为PowerShell也使用COM。我找到了使用AppDomain.DoCallBack的解决方法,它避免了从AppDomain获取代理。这是代码。 如果你找到更好的选择,请张贴。在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; }
        }
    }

runner
的类型需要继承自
AppDomainPoshRunner
。因此,您的意思是,当您从C#console应用程序调用
RunScriptInAppDomain()
时,它运行正常,但当您从PowerShell调用它时,它会抛出该异常?@Scott,
runner
的类型是
AppDomainPoshRunner
@svick正如scott所说,runner的类型是AppDomainPoshRunner。@scott,正确,RunScriptInAppDomain()在C#console应用程序中可以正常工作,但在powershell应用程序中不能。两者的源代码都在github中。谢谢你的文章。即使它不能直接解决这个问题,但如果你在AppDomains上乱搞,它肯定是有用的。加入GAC是一个快速修复方法,因为GAC的程序集总是在加载上下文中结束。打开远程实例后,AppDomainPoshRunner将加载到调用appdomain的上下文中,该上下文与被调用方中的上下文不同。这给了他们不同的身份。如果您不想将整个实现放在GAC中,我会在共享程序集中创建一个IScriptRunner接口,而将该接口放在GAC中。将具体impl保留在本地非gac的程序集中,但它也需要强名称,否则将无法加载gac的共享程序集。