Tuesday, November 17, 2009

WCF Service in pure IronPython

I wrote about implementing WCF service in IronPython a couple of weeks ago. Meanwhile I pushed Shri a little bit with the clrtype.py and he has implemented ClrInterface metaclass there so we can create the whole WCF service in IronPython now.

The IronPython interface implementation is straightforward:

TestServiceInterface.py

import clr
import clrtype
clr.AddReference('System.ServiceModel')
from System.ServiceModel import (
        ServiceContractAttribute,
        OperationContractAttribute)
OperationContract = clrtype.attribute(
        OperationContractAttribute)

class ImyService(object):
    __metaclass__ = clrtype.ClrInterface
    _clrnamespace = "TestServiceInterface"
    _clrclassattribs = [ServiceContractAttribute]

    @OperationContract()
    @clrtype.accepts(int)
    @clrtype.returns(str)
    def GetData(self, value):
        raise RuntimeError("this should not get called")

Also switching from C# interface to IronPython interface is easy:

TestService.py

import clr
import clrtype
clr.AddReference('System.ServiceModel')
from TestServiceInterface import ImyService
from System import Console, Uri
from System.ServiceModel import (ServiceHost,
        BasicHttpBinding, ServiceBehaviorAttribute,
        InstanceContextMode)

class myService(ImyService):
    __metaclass__ = clrtype.ClrClass
    _clrnamespace = "myWcfService"
    _clrclassattribs = [ServiceBehaviorAttribute]

    def GetData(self, value):
        return "IronPython: You entered: %s" % value

sh = ServiceHost(myService, Uri(
        "http://localhost:9000/myWcfService"))
sh.AddServiceEndpoint(clr.GetClrType(ImyService),
        BasicHttpBinding(), "")
sh.Open()
Console.WriteLine("Press  to terminate\n")
Console.ReadLine()
sh.Close()

Notice that we call ServiceHost with myService which is the type and not the instance of our service. Because of this, the ServiceBehavior attribute does not need to have InstanceContextMode.Single parameter.

Finally, here is the test client:

TestClient.py

import clr
clr.AddReference('System.ServiceModel')
import System.ServiceModel
from TestServiceInterface import ImyService

mycf = System.ServiceModel.ChannelFactory[ImyService](
        System.ServiceModel.BasicHttpBinding(),
        System.ServiceModel.EndpointAddress(
            "http://localhost:9000/myWcfService"))
wcfcli = mycf.CreateChannel()
print "WCF service returned:\n%s" % wcfcli.GetData(11)

The disadvantage of having just a single service instance is gone, the harder configuration remains. One new disadvantage can be it is not possible (yet) to compile the interface and save it to disk nor use it from other .NET languages.

Edit 22. 11. 2009: See WCF Service in pure IronPython with config file

6 comments:

dwelden said...

Now if the interface could be implemented as decorator, the python code would be even closer to the C#.

Lukáš Čenovský said...

Yes, it would be nice to implement it as decorator. Unfortunately it is not possible because it has to use metaclasses - see DevHawk's blog:

I wish I could use Python’s class decorators for custom class attributes, but class decorators run after metaclasses so unfortunately that doesn’t work.

Naveen said...

is it then possible to implement the wcf service in ironpython and the client in csharp and vice versa ?

Lukáš Čenovský said...

It is possible.

The only thing which is not possible is to host IronPython WCF service in IIS.

Unknown said...

I know it's a while since you posted this tutorial, but I've encountered problems with metaclasses that I can't seem to get around it.

When i load the python-file (Note: Inside ACAD 2016), i get an Metaclass confict between ClrInterface and ClrClass. However, with your old example, with the interface written in C#, i don't encounter this problem.

Have you any advice for me?

Greetings from Switzerland

Lukáš Čenovský said...

I'm sorry but no idea - I would guess it is specific to ACAD 2016.