Mono WCF Advent Day 5: expose and consume WSDLs

| 8 Comments | No TrackBacks

WCF services can be exposed as a set of WSDL documents, and WCF client classes can be automatically generated by consuming such WSDLs. Today's topic is our WSDL support. It is not really perfect, but supporting code is there.

ServiceDescription

When you create a ServiceHost with your service implementation class, WCF creates an object of "ServiceDescription" that describes the service details, such as set of endpoints, debugging support and service throttling. It is exposed as Description property of the ServiceHost instance.

As I explained Day 2 a bit, a service class may implement more than one service contract interfaces. Each service contract in the service is bound to a service endpoint URI (EndpointAddress) and a Binding. This set of A(ddress), B(inding) and C(ontract) are represented as a ServiceEndpoint class. To reflect these, a ServiceDescription has an Endpoints property which is a collection of ServiceEndpoints.

WSDL output and ServiceMetadataBehavior

To explain how to do it, I have to explain "service behaviors". A service behavior, which is represented as IServiceBehavior interface, is to add additional facilities or give behavioral changes to the service. ServiceDescription has a set of IServiceBehavior implementations as Behaviors property.

WSDL output support is represented as one of such an implementation of IServiceBehavior, namely ServiceMetadataBehavior. For example, to enable WSDL output, modify service.cs of Day 2 as:

-    var host = new ServiceHost (typeof (HelloService));
+    var host = new ServiceHost (typeof (HelloService));
+    var meta = new ServiceMetadataBehavior () {
+      HttpGetEnabled = true,
+      HttpGetUrl = new Uri ("wsdl", UriKind.Relative) };
+    host.Description.Behaviors.Add (meta);

Run service.exe, and then visit http://localhost:8080/wsdl in your browser. It will show you the corresponding WSDL.

svcutil.exe and clients

On the client side, it is non-coding land. In the example in Day 2, we wrote "HelloClient" class by our own. However, by consuming the service's WSDL, we actually don't have to write that class. Instead, we can use "svcutil" tool. It is based on the same tool in Windows SDK (SvcUtil.exe).

To use it, start service.exe first and then run:

$ svcutil http://localhost:8080/wsdl

So far it does not exactly behave like svcutil.exe in .NET, but gives resulting C# code as "output.cs".

Then, edit client.cs of Day 2 as:

- [ServiceContract]
- public interface IHelloService
- {
-   [OperationContract]
-   string Greet (string name);
- }

-    var client = new HelloClient (binding, address);
+    var client = new HelloServiceClient (binding, address);

Then compile two sources into an exe:

$ gmcs client.cs output.cs

The resulting client.exe should work as the earlier client.exe used to do.

As of the end of year 2009, svcutil and WSDL support is in somewhat early stage, namely:

  • It does not give default constructor that should give the expected binding and the endpoint address. You'll have to explicitly supply them so far.
  • There is no configuration output.
  • I am aware of some bogus behaviors of HTTP(s) GET URI patterns.

Asynchronous service contracts

Our svcutil can also generate service contracts in "asynchronous" pattern. Use -async command line option, and you'll get an interface like:

$ svcutil http://localhost:8080/wsdl -async
[ServiceContract]
public interface IHelloService
{
    [OperationContract (AsyncPattern = true)]
    IAsyncResult BeginGreet (string name,
                 AsyncCallback callback,
                 object state);
    string EndGreet (IAsyncResult result);
}

Today in svn trunk I added support for another async alternative: event-based async operation pattern, which is at first introduced for Silverlight and then incorporated to .NET too. The corresponding option is "-targetClientVersion:Version35" or "-tcv:Version35" (aligned to .NET's svcutil.exe). Use it along with "-async" option. This asynchronous pattern is implemented in the (auto-generated) client class and is used like:

$ svcutil http://localhost:8080/wsdl -async -tcv:Version35
public class Test
{
  public static void Main (string [] args)
  {
    string name = args.Length > 0 ? args [0] : "anonymous joe";
    var binding = new BasicHttpBinding ();
    var address = new EndpointAddress ("http://localhost:8080/");
    var client = new HelloServiceClient (binding, address);
    client.GreetCompleted += delegate (object o, GreetCompletedEventArgs e) {
      Console.WriteLine (e.Result);
    };
    client.GreetAsync (name);
    Console.WriteLine ("Type [CR] to quit");
    Console.ReadLine ();
  }
}

Again, note that the latter pattern is available only in trunk so far.

Client proxies for Moonlight and MonoTouch

WSDL support is mostly about full .NET compatibility and not for Moonlight or MonoTouch. You cannot do any of above for those limited environment.

In Silverlight, client proxies are generated by "slsvcutil.exe", which is svcutil.exe for Silverlight.

However, creating client proxies using svcutil is partly possible and especially recommended for MonoTouch. Unlike slsvcutil.exe, we have some extra command line options on svcutil.exe itself:

  • -moonlight option gives you client proxies that uses Silverlight-only Channel implementation i.e. ClientBase<T>.ChannelBase<T&gt . It is used to provide async operation support as well as eliminating need for dynamic code generation.
  • -monotouch option is almost the same as -moonlight (it is especially important for MonoTouch to eliminate dynamic code generation), but still gives you synchronous call proxy methodstoday it became unavailable. It may be temporarily, or might be permanently. It is due to some limitation in our svcutil. I'll sort out at some stage.

Note that Silverlight usually uses the event-based asynchronous pattern explained above, and it is (I repeat again) available only in svn trunk.

We don't have corresponding feature in MonoDevelop yet ("Add Service Reference" in Visual Studio), but it will be done at some stage. So far, live with svcutil.exe or manually write proxies.

No TrackBacks

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

8 Comments

I personally believe that good WCF support is one of the most important factors of mono success/fail story. Great job so far - Thank you !

Thanks - we'll continue our WCF effort (this time ;-)

Hi,
I want to ask you, where can I find svcutil.exe with event-based async operation pattern. (param -tcv). Thank you very much.

It is (of course) in svcutil.exe.
If you're asking about source code location, then:
http://anonsvn.mono-project.com/viewvc/trunk/mcs/tools/svcutil/CommandLineOptions.cs (search for "tcv")

Hi,

I am very new in iPhone development. We have our wcf service developed in .net platform.

I try to use very simple wcf service in MonoDevelop 2.8.2.

Couple of question please..

1. I try to run svcutil.exe from window machine and it's generate .cs file and i added in my mono project in mac system. when it's try to open service it's give me error
"monotouch does not support dynamic proxy code generation" so find your blog here and it's say we need to use -monotouch after svcutil, but i try svcutil -monotouch in windows machine but it doesn't like it.

Can you please let me know how can i generate .cs file which i can use in mono project.

Pleae reply asap, i already spend lot's time on it.

Thanks lot.

Similar topic was up on the mailing list. http://lists.ximian.com/pipermail/monotouch/2011-November/006861.html

.NET's svcutil generates WCF proxy for full .NET, which is not what MonoTouch, Mono for Android or Silverlight/Moonlight accepts. Use our svcutil -monotouch or at least "slsvcutil" in Silverlight SDK instead.

HTH.

I tried to modify the Day 2 example to expose the WSDL. But when I visit http://localhost:8080/wsdl I get this:

a:DestinationUnreachable


The request message has the target 'http://localhost:8080/wsdl' with action '' which is not reachable in this service contract

How to resolve this? Is there more to add/change than just what is described above?

I tried to modify the Day 2 example to expose the WSDL. But when I visit http://localhost:8080/wsdl I get this:

a:DestinationUnreachable


The request message has the target 'http://localhost:8080/wsdl' with action '' which is not reachable in this service contract

How to resolve this? Is there more to add/change than just what is described above?

Leave a comment