我正在尝试创建一个开源库,它会生成一个新的
AppDomain
并在其中运行PowerShell
脚本。我有一个静态方法,它采用 powershell 文件的名称和 AppDomain
的名称。从 C# 控制台应用程序调用时,该方法会成功执行,但不会 PowerShell
。
我知道 dll 正在第二个应用程序域中加载,因为 fusionlog 中的此条目。
类声明和构造函数如下所示。
public class AppDomainPoshRunner : MarshalByRefObject{
public AppDomainPoshRunner (){
Console.WriteLine("Made it here.");
}
}
无论我是从 C# 控制台应用程序还是从 PowerShell 应用程序运行 dll,当我调用 CreateInstanceFromAndUnwrap 时,构造函数中的消息都会输出。
当我在下面的静态方法中将
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
。
我做错了什么?
我遇到了同样的问题:我创建了具有仅执行权限(最小权限)的沙箱,以便在非常受限的环境中执行不受信任的代码。所有这些在 C# 应用程序中都工作得很好,但当起点是创建 .NET COM 对象的 vbs 脚本时则不起作用(相同的强制转换异常)。我认为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; }
}
}
这听起来很像加载上下文问题。类型标识不仅仅与物理程序集文件有关;它还与物理程序集文件有关。它还与它的加载方式和位置有关。这是 Suzanne Cook 的一篇旧博客文章,您可能需要阅读十五遍才能开始理解您的问题。
选择绑定上下文
https://learn.microsoft.com/en-us/archive/blogs/suzcook/choosing-a-binding-context
在你说“但它可以在控制台应用程序中工作”之前,请记住,当从 powershell 运行它时,在调用应用程序域的上下文、探测路径、身份等方面,你会遇到完全不同的情况。
祝你好运!