跨应用程序域传递对象

发布于 2024-08-25 09:25:32 字数 2342 浏览 10 评论 0原文

我在跨应用程序域传递对象时遇到问题。在进一步调查过程中,我发现问题是由于 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

橘香 2024-09-01 09:25:32

这现在对我有用。

问题是我试图将对象从远程域返回到本地域。 ObjectOperations 有一组重载,它们采用 ObjectHandles 并具有一些其他方法,这些方法返回 ObjectHandles 以处理远程应用程序域中的对象。如果将上面的代码修改为下面的代码就可以了。

添加:使用

        var subClass = scope.GetVariableHandle("C"); // get back a handle
        var instance = ops.Invoke(subClass, new ObjectHandle[0]); // invoke the handle to create an instance

        mbr = instance.Unwrap() as MbrBase; // now we know we have an MBR and we can unwrap it to our local side

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

        var subClass = scope.GetVariableHandle("C"); // get back a handle
        var instance = ops.Invoke(subClass, new ObjectHandle[0]); // invoke the handle to create an instance

        mbr = instance.Unwrap() as MbrBase; // now we know we have an MBR and we can unwrap it to our local side

P.S. I got the solution from Iron Python community.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文