Mono WCF Advent Day 8: MonoTouch

| 8 Comments | 1 TrackBack

WCF is also available in iPhone land. MonoTouch had started based on "2.1" profile of Mono, which is for Moonlight, and then extended its coverage to some .NET API such as System.Web.Services and ADO.NET. Since WCF is part of Moonlight, it was also possible to get included in MonoTouch.

Example

Here I'm sort of expecting you knowing basic how-to in MonoTouch land. I'm explaining the procedure below as what I did with MonoTouch on Snow Leopard and iPhone SDK 3.1:

  • Edit MainWindow.xib to add a button. -- Create "MonoTouch application project", say, monotouchwcf -- Double click MainWindow.xib to open Interface Builder. -- Select "Window" and add Round Rect Button and Label (drag them onto the Window for each). -- Select the button and give the button title like "Tap me". -- Go to library window, select "Classes" tab and select "AppDelegate" which is likely at the top of the list. Add "button" and "label" outlets. -- Go to IB's main window and select AppDelegate there, and connect its "button" outlet to the actual Round Rect Button on Window. Do the same for "label" output and the actual Label on the Window. Save the XIB and it's done in IB.
  • Create and add client proxy code -- Run service like we did for Moonlight. -- run svcutil to create client proxy like we did for moonlight. -- Add "output.cs" from svcutil result to the project.
  • Add service invocation via the client proxy in the application -- Add reference to System.ServiceModel.dll in the project. -- Add "using System.ServiceModel" at the top of the source. -- In Main.cs, add code lines below in FinishedLaunching() method, like below.
  • Run the app and touch the button.
        public override bool FinishedLaunching (UIApplication app, NSDictionary options)
        {
            // If you have defined a view, add it here:
            // window.AddSubview (navigationController.View);

            window.MakeKeyAndVisible ();

            this.button.TouchDown += delegate {
                var binding = new BasicHttpBinding ();
                var address = new EndpointAddress ("http://192.168.1.3:8080/test.svc");
                var client = new HelloServiceClient (binding, address);
                client.GreetCompleted += delegate(object sender, GreetCompletedEventArgs e) {
                    this.InvokeOnMainThread (delegate {
                        this.label.Text = e.Result;
                    });
                };
                this.label.Text = "sending request...";
                client.GreetAsync ("monotouch");
            };
            return true;
        }

Note that:

  • Do not use "localhost" as the remote endpoint address. It is not the iPhone itself but the development machine that runs corresponding WCF service. Use IP directly instead, for example.
  • Use InvokeOnMainThread() to update the application UI.

sshot-mt-wcf.png

Some notes on WCF in MonoTouch

The usage in MonoTouch almost the same as Moonlight does, while there is no "async-only" limitation in the runtime. You can use sync operation calls. Though I used event-based async model in the example above. (The future versions of svcutil might stop supporting sync calls due to moonlight proxy generator limitation. But sync client should work at runtime level anyways.)

On the other hand, there is a big limitation in MonoTouch in general - you cannot dynamically generate runnable code. And since WCF often involves dynamic code generation, you have to be caucious to not do it. For example, you have to override ClientBase<T>.CreateChannel() by using ClientBase<T>.ChannelBase<T> . If you don't do that, the default Channel property is generated by ChannelFactory<T>.CreateChannel() method, which dynamically creates an implementation of the contract interface using System.Reflection.Emit API.


1 TrackBack

TrackBack URL: http://veritas-vos-liberabit.com/monogatari/mt-tb.cgi/91

Thank you for submitting this entry - Trackback from MonoTouch.Info Read More

8 Comments

Great article, very timely for what I am trying to do.

However, I am running up against the limitation where MonoTouch cannot generate dynamic code. I've tried to follow your advice of overriding ClientBase.CreateChannel, but the compiler keeps complaining that ClientBase.ChannelBase is not accessible (it is private).

protected override IDiagnostics CreateChannel()
{
return new ClientBase.ChannelBase(this);
}

I seem to be missing a piece of the puzzle here. Is there another way that I should be getting a reference to a ClientBase.ChannelBase besides just trying to create one?

Oh, probably you didn't pass -monotouch argument to svcutil. My bad, I should have mentioned it in the post. Anyways, try this: svcutil -monotouch http://target/url/to/wsdl

Not sure if this is being monitored, but I am facing the same issue... it seems like the mono svcutil does not support the -monotouch parameter anymore. Any other way to fix it? Thanks

-monotouch options is available only in post-2.6.x mono (i.e. git head or daily builds).

Hi!

Does BasicHttpBinding in MonoTouch takes care of Http Cookies automatically like Silverlight does?

If not, how can I access the Http Cookies from a WCF response?

I'm generating the ServiceClient classes with Silverlight's scvutil in Windows.

Thank you.

Well, yes, HttpTransportBindingElement (part of BasicHttpBinding) in MonoTouch (as well as Moonlight) should get and set IHttpCookieContainer to the WebRequest. Note that depending on the WebRequest, cookie container may not be implemented (as far as I can see, it is not implemented in System.Net.dll's WebRequest).

Note that the cookie container is available only in silverlight/moonlight or monotouch (not in full WCF).

I'm using mono 2.6.7, the -monotouch option is available for me. What does it do exactly? Cheers.

-monotouch is to generate both sync and async methods in the resulting proxy. (without argument it defaults to sync, -moonlight only supports async.)

Leave a comment