[IronPython] Remoting: Marshal object

Dino Viehland dinov at exchange.microsoft.com
Fri Jun 23 15:56:52 PDT 2006


Sorry for the delay, your repros are complex :). Additionally having not used Remoting thoroughly in about 4-5 years (and then only having a fairly brief but in-depth in certain areas exposure to it) this took me some time to work through.

Doing everything programmatically in C# this is where I ended up w/ a solution that appears to be what you want, but I'm not sure if this is the same as what you're doing.  I also changed the type of the event handler to be a simple EventHandler rather than your type.

I think I am doing something slightly different than you.  On the client side it sounds like you're marshalling what should be your WKO instead of marshalling the listener for the event.  You'll notice in my client I have an instance of foo that I Marshal to TalkIsGoodToo and then wire up to the remote event handler.  Maybe you actually just have two instances of CallbackSink on both the client & server doing something more peer-to-peer.

Server side:

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Serialization.Formatters;

class foo{
    public static void Main(string[]args){
        SoapServerFormatterSinkProvider provider = new SoapServerFormatterSinkProvider();
        provider.TypeFilterLevel = TypeFilterLevel.Full;
// Creating the IDictionary to set the port on the channel instance.
        IDictionary props = new Hashtable();
        props["port"] = 8086;

        ChannelServices.RegisterChannel(new HttpChannel(props, null, provider), false);
        WellKnownServiceTypeEntry wkoe = new WellKnownServiceTypeEntry(typeof(CallbackSink), "SayHello", WellKnownObjectMode.Singleton);
        RemotingConfiguration.RegisterWellKnownServiceType(wkoe);

        Console.WriteLine("server running");
        //CallbackSink cbs = (CallbackSink)System.Runtime.Remoting.RemotingServices.Marshal(typeof(CallbackSink), "SayHello");
        //cbs.Send("Server Hello");

        Console.ReadLine();
    }
}

Client side:

using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Services;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Serialization.Formatters;

class foo : MarshalByRefObject{

    public static void Main(string[]args){
        SoapServerFormatterSinkProvider provider = new SoapServerFormatterSinkProvider();
        provider.TypeFilterLevel = TypeFilterLevel.Full;
        IDictionary props = new Hashtable();
        props["port"] = 8087;

        ChannelServices.RegisterChannel(new HttpChannel(props, null, provider), false);

        Console.WriteLine("go");
        CallbackSink cbs = (CallbackSink)System.Activator.GetObject(typeof(CallbackSink), "http://localhost:8086/SayHello");

        foo f = new foo();
        System.Runtime.Remoting.RemotingServices.Marshal(f, "TalkIsGoodToo");
        cbs.OnHostToClient += f.MyEventHandler;
        cbs.Send("hello!");
    }

    public void MyEventHandler(object sender, EventArgs e){
        Console.WriteLine("MyEventHandler!");
    }
}


Then my Python script ends up looking like this:

import System
import clr
clr.AddReference('System.Runtime.Remoting')
clr.AddReference('System.Runtime.Serialization.Formatters.Soap')
from System.Runtime.Serialization.Formatters import TypeFilterLevel
provider = System.Runtime.Remoting.Channels.SoapServerFormatterSinkProvider()
provider.TypeFilterLevel = TypeFilterLevel.Full
props = System.Collections.Hashtable()
props["port"] = 8087

System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(System.Runtime.Remoting.Channels.Http.HttpChannel(props, None, provider), False)

clr.AddReferenceToFile('ro.dll')
import CallbackSink

cbs = System.Activator.GetObject(CallbackSink, "http://localhost:8086/SayHello")

class foo(System.MarshalByRefObject):
    def handler(self, sender, args): print 'called'

f = foo()

System.Runtime.Remoting.RemotingServices.Marshal(f, "TalkIsGoodToo")
cbs.OnHostToClient += f.handler

and depending on how I tweak things, I finally get an exception of one sort on the final line.  For starters I got that ModuleScope was not serializable.  I changed it to derive from MarshalByRefObject (not sure that's right, just wanted to see about getting past this) and I was able to get a little bit further, but this is where it starts to get difficult to make any forward progress.

For starters cbs, being a remote MarshalByRefObject, has all the same problems w/ remote MarshalByRefObject's that you ran into previously.  I was able to get closer to wiring up the event handler by doing:

CallbackSink.OnHostToClient.__get__(cbs, CallbackSink).__iadd__(f.handler)

But then we seem to hit a brick wall where we fail to serialize something else, and it's not very clear what it is...

So, the question then becomes, how do you actually do this w/ IronPython?  I think what you'll need to do is setup a helper class that can do the event handling for you.  Link that against IronPython.dll and call through Ops to invoke your object, I came up with:

using System;
using IronPython.Runtime.Operations;

public class Helper : MarshalByRefObject {
    private object o;
    public Helper(object o){
        this.o = o;

    }

    public void Register(CallbackSink cbs){
    cbs.OnHostToClient += this.OnCalled;
    }

    public virtual void OnCalled(object sender, EventArgs e){
        Console.WriteLine("Helper.OnCalled");
        Ops.Call(o);
    }
}

(note the registration does need to occur via C#).

Finally I use that from Python like:

import System
import clr
clr.AddReference('System.Runtime.Remoting')
clr.AddReferenceToFile('helper.dll')
#clr.AddReference('System.Runtime.Serialization.Formatters.')
from System.Runtime.Serialization.Formatters import TypeFilterLevel
provider = System.Runtime.Remoting.Channels.BinaryServerFormatterSinkProvider()
provider.TypeFilterLevel = TypeFilterLevel.Full
props = System.Collections.Hashtable()
props["port"] = 8087

System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(System.Runtime.Remoting.Channels.Tcp.TcpChannel(props, None, provider), False)

clr.AddReferenceToFile('ro.dll')
import CallbackSink

cbs = System.Activator.GetObject(CallbackSink, "Tcp://localhost:8086/SayHello")

def myCallback():
        print 'called'

import Helper
f = Helper(myCallback)
System.Runtime.Remoting.RemotingServices.Marshal(f, "TalkIsGoodToo")
f.Register(cbs)

CallbackSink.Send(cbs, 'hello')


All in all I'd say that IronPython is capable w/ some effort of consuming remoting objects, but that we're not capable of producing remotable objects (which is what you're effectively trying to do here).  So as you get into the more production side of things you'll need some C# code to stitch things together.  Hopefully we can do a better job here in the future (although it's not entirely clear how) but unfortunately we probably won't make any significant changes to this for v1.0.



-----Original Message-----
From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] On Behalf Of Ralph Soons
Sent: Wednesday, June 21, 2006 12:49 AM
To: users at lists.ironpython.com
Subject: Re: [IronPython] Remoting: Marshal object

In c# I have 3 assembly's. There's a server exe and a client exe and a library in which the remoting objects are implemented, which are included in both the client and the server. The CallbackSink class is situated in the library which has the namespace RemotingServerClient.
I use server activated Singleton mode configuration.

I would like to register on the OnHostToClient event at server side so any object registering for this event receives a notification when a client calls. My problem was that the object I registered my event to and the object which was called by the client weren't the same. So my registered event handlers weren't called. That's why I had to use the marshal function.
Using the c# server and client this works.

After this I replaced the c# server by a python server. I used the same configuration. Created an event handler function. Created the CallbackSink object (got an instance) and registered the event handler to it. Now I marshal the callbacksink object to make sure during a call from the client the same object is used.

When I call my server in python from the c# client, the message is received in the Send function of the CallbackSink and if write the received message to the console I see the message appearing in the python console. However the CallbackSink object is newly created and isn't the object I marshalled in the python server.

So it looks like the Marshal call doesn't work. I don't see any exception.
Only thing I see is that the objects are different.


>From: Dino Viehland <dinov at exchange.microsoft.com>
>Reply-To: Discussion of IronPython <users at lists.ironpython.com>
>To: Discussion of IronPython <users at lists.ironpython.com>
>Subject: Re: [IronPython] Remoting: Marshal object
>Date: Tue, 20 Jun 2006 09:05:07 -0700
>
>I'm a little lost on this one - what is RemotingServerClient here?  Is
>it a type, an assembly, a namespace?
>
>Also, do you get an exception, or does it just do nothing?
>
>-----Original Message-----
>From: users-bounces at lists.ironpython.com
>[mailto:users-bounces at lists.ironpython.com] On Behalf Of Ralph Soons
>Sent: Tuesday, June 20, 2006 8:04 AM
>To: users at lists.ironpython.com
>Subject: [IronPython] Remoting: Marshal object
>
>I have a remoting problem again. I want to create an object at server
>side, as singleton so when a call is done at client side, ill get the
>already existing object. I tried it first with a c# server and client.
>
>Can anyone tell me why the marshal function doesn't work, objects on
>server and client side are still different (same code works in c#
>application so configuration is correct):
>
>Client side (Python):
>t = RemotingServerClient.CallbackSink.Instance
>System.Runtime.Remoting.RemotingServices.Marshal(t, 'TalkIsGoodToo')
>
>Server side (c#):
>CallbackSink.Instance.Send("Message");
>
>Remotable object (c#):
>public class CallbackSink : MarshalByRefObject
>     {
>         private static CallbackSink m_Instance = null;
>         public event delCommsInfo OnHostToClient;
>
>         public static CallbackSink Instance
>         {
>             get
>             {
>                 if (null == m_Instance)
>                 {
>                     m_Instance = new CallbackSink();
>                 }
>                 return m_Instance;
>             }
>         }
>
>         private CallbackSink()
>         { }
>
>         public void Send(string message)
>         {
>             OnHostToClient(info);
>         }
>     }
>
>Thanks for your help.
>Best regards,
>Ralph Soons
>
>_________________________________________________________________
>Talk with your online friends with MSN Messenger
>http://www.join.msn.com/messenger/overview
>
>_______________________________________________
>users mailing list
>users at lists.ironpython.com
>http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>_______________________________________________
>users mailing list
>users at lists.ironpython.com
>http://lists.ironpython.com/listinfo.cgi/users-ironpython.com

_________________________________________________________________
Talk with your online friends with MSN Messenger http://www.join.msn.com/messenger/overview

_______________________________________________
users mailing list
users at lists.ironpython.com
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com


More information about the users mailing list