跨应用程序域传递对象
我在跨应用程序域传递对象时遇到问题。在进一步调查过程中,我发现问题是由于 IronPython 对象未序列化造成的。此 IronPython 对象派生自 .NET 基类。 .NET 基类派生自 MarshalByRefObj。
让我解释一下我的环境。我的 C# 应用程序中嵌入了 IronPython。 IronPython 中的每个类都必须继承 .NET 基类(例如 ClassA)。 ClassA 派生自 MarshalByRefObj,因为我需要将此类的实例传递给另一个应用程序域。我创建一个新的应用程序域并将 ClassA 的实例传递给该应用程序域。通过 ClassA 的实例调用 python 类中的方法时,出现异常,提到“在程序集 'IronPython, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' 中键入 'IronPython.Runtime.Types.PythonType' 不是”标记为可序列化”
如何从 C# 序列化 python 对象,或者是否有其他方法来解决这种情况。
更新
更深入地了解问题。如果我实例化在默认应用程序域中访问 python 方法的类,然后将该实例传递给创建的应用程序域,则不会出现上述问题。另一方面,当我实例化类时,我在创建的应用程序域中访问 python 方法,然后访问 python 方法,然后抛出序列化异常。
我认为解决此问题的一种方法是修改 IronPython 源代码以序列化所需的类型。我还有其他方法可以解决这个问题吗?
这是重现我遇到的异常的示例代码
using System;
using Microsoft.Scripting;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
class Foo
{
public static void Main(string[] args)
{
AppDomain ad = AppDomain.CreateDomain("foo");
var engine = Python.CreateEngine(ad);
engine.Runtime.LoadAssembly(typeof(MbrBase).Assembly);
var code = engine.CreateScriptSourceFromString(@"
import MbrBase
class C(MbrBase):
pass
a = C()
", SourceCodeKind.Statements);
var scope = engine.CreateScope();
code.Execute(scope);
Console.WriteLine("Trying to do it... {0}",
AppDomain.CurrentDomain.Id);
MbrBase mbr = (MbrBase)scope.GetVariable("a");
string isSubClassCode = String.Format("issubclass({0},{1})", "C",
"MbrBase");
ScriptSource script =
engine.CreateScriptSourceFromString(isSubClassCode,
SourceCodeKind.Expression);
bool result = (bool)script.Execute(scope);
if (result == true)
{
ObjectOperations ops = engine.Operations;
object subClass = scope.GetVariable("C");
object instance = ops.Call(subClass);
mbr = instance as MbrBase;
}
mbr.DoItVirtually();
mbr.DoIt();
Console.ReadKey();
}
}
public class MbrBase : MarshalByRefObject
{
public virtual void DoItVirtually()
{
Console.WriteLine("Did it virtually {0}", AppDomain.CurrentDomain.Id);
}
public void DoIt()
{
Console.WriteLine("Did it {0}", AppDomain.CurrentDomain.Id);
}
}
I am having issues while passing objects across Appdomains.During further investigation I found that the issue is due to the IronPython object not been Serialized. This IronPython object is derived from a .NET base class. The .NET base class is derived from MarshalByRefObj.
Let me explain my environment. I have IronPython embedded in my C# application. It is imposed that every class in IronPython inherit the .NET base class say ClassA. ClassA is derived from MarshalByRefObj as I need to pass an instance of this class to another appdomain. I create a new appdomain and pass the instance of ClassA to this Appdomain. While calling a method in python class through the instance of ClassA I get an exception mentioning that "Type 'IronPython.Runtime.Types.PythonType' in Assembly 'IronPython, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable"
How can I serialize python objects from C# or is there any other way to tackle this situation.
Update
More insight into the problem. If I instantiate the class where I access python methods in the default appdomain and then pass the instance to the created appdomain then the above mentioned issue is not seen. On the other side when I Instantiate the class where I access the python method in the created appdomain and then access the python methods then the serialization exception is thrown.
One way I see to resolve this issue is that i modify the IronPython source code to serialize the types that are required. Is there any other way that i can do to get around this issue.
Here is a sample code to reproduce the exception I encountered
using System;
using Microsoft.Scripting;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
class Foo
{
public static void Main(string[] args)
{
AppDomain ad = AppDomain.CreateDomain("foo");
var engine = Python.CreateEngine(ad);
engine.Runtime.LoadAssembly(typeof(MbrBase).Assembly);
var code = engine.CreateScriptSourceFromString(@"
import MbrBase
class C(MbrBase):
pass
a = C()
", SourceCodeKind.Statements);
var scope = engine.CreateScope();
code.Execute(scope);
Console.WriteLine("Trying to do it... {0}",
AppDomain.CurrentDomain.Id);
MbrBase mbr = (MbrBase)scope.GetVariable("a");
string isSubClassCode = String.Format("issubclass({0},{1})", "C",
"MbrBase");
ScriptSource script =
engine.CreateScriptSourceFromString(isSubClassCode,
SourceCodeKind.Expression);
bool result = (bool)script.Execute(scope);
if (result == true)
{
ObjectOperations ops = engine.Operations;
object subClass = scope.GetVariable("C");
object instance = ops.Call(subClass);
mbr = instance as MbrBase;
}
mbr.DoItVirtually();
mbr.DoIt();
Console.ReadKey();
}
}
public class MbrBase : MarshalByRefObject
{
public virtual void DoItVirtually()
{
Console.WriteLine("Did it virtually {0}", AppDomain.CurrentDomain.Id);
}
public void DoIt()
{
Console.WriteLine("Did it {0}", AppDomain.CurrentDomain.Id);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这现在对我有用。
问题是我试图将对象从远程域返回到本地域。 ObjectOperations 有一组重载,它们采用 ObjectHandles 并具有一些其他方法,这些方法返回 ObjectHandles 以处理远程应用程序域中的对象。如果将上面的代码修改为下面的代码就可以了。
添加:使用
System.Runtime.Remoting我从 Iron Python 社区得到了解决方案。
This works for me now.
The problem was that I was trying to return the objects from the remote domain into the local domain. ObjectOperations has a set of overloads which take ObjectHandles and has some other methods which return ObjectHandles for working with objects in a remote app domain. If the above code is modified to the code below it works.
Add: using System.Runtime.Remoting
P.S. I got the solution from Iron Python community.