December 2009 Archives

Mono WCF Advent Day 13: WCF 4.0 Routing

| 1 Comment | No TrackBacks

While we don't have some significant parts of WCF 3.0 stack such as working message security, we have some new stuff, like WebHttpBinding I explained on Day 9. It also applies to WCF 4.0. We have new routing stack.

WCF router support is only in SVN trunk, in System.ServiceModel.Routing assembly, mostly in System.ServiceModel.Routing namespace. Note that .NET 4.0 is still in beta, so things may change as .NET 4 development goes on.

Router usage

Message router is to dispatch messages that it received from clients, to certain servers. A WCF router is a WCF service for router client users, while the router works as a WCF client for routed services (which may not be WCF).

Routing design is almost simple: a WCF router service has a table of a message filter that is used to test if a message matches it or not, and a set of endpoints to dispatch messages it received. The table is represented as MessageFilterTable<MessageFilter,IEnumerable<ServiceEndpoint>>.

(Usually just one service endpoint is enough; simplex or duplex channels may dispatch messages to more than one service endpoints.)

Message router often has to rebuild the input message, like, adjusting message versions and To message header.

I haven't prepared an entire routing example (I tested it with MS sample in 4.0), but router usage would look like:

var host = new ServiceHost (typeof (RoutingService));
host.AddServiceEndpoint (
  typeof (IRequestReplyRouter),
  new BasicHttpBinding (),
  new Uri ("http://localhost:8081/router"));
var config = new RoutingConfiguration ();
var clientEndpoint = new ServiceEndpoint (
  ContractDescription.GetContract (typeof (IRequestReplyRouter)),
  new BasicHttpBinding (),
  new EndpointAddress ("http://localhost:8080/service"));
var list = new List<ServiceEndpoint> ();
list.Add (clientEndpoint);
config.FilterTable.Add (new MatchAllMessageFilter (), list);
host.Description.Behaviors.Add (new RoutingBehavior (config));

Internals

There is not many things to explain for WCF routing, so I'd explain its internals instead so that some people might want to write similar code for several purposes.

To host a routing service, RoutingService is used. It has four interfaces for several channel interface types;

  • IRequestReplyRouter for typical request-reply channels
  • ISimplexDatagramRouter for input/output channels
  • ISimplexSessionRouter for input/output sessions channels
  • IDuplexSessionRouter for duplex session channels

To add routing with a specific table, you'll first have to create the table. It is represented as FilterTable property in RoutingConfiguration class. Once you have created a configured RoutingConfiguration instance, then use RoutingBehavior object, which is of IServiceBehavior interface (a behavioral extension to ServiceDescription, see Day 5 for quick introduction to "service behaviors") and takes RoutingConfiguration as its constructor argument.

Once you have set routing configuration in above manner, then what to do next is to call AddServiceEndpoint() with (1) an interface type I listed above, (2) a binding for the router "(as a) service", and (3) an endpoint address for the router "(as a) service". (1) must be determined as to comply with the routed servers' requirements, and (2) and (3) represent the endpoint information for routers' client (and of course, a client must comply with (1) to properly communicate with the router).

Those four routing interfaces I listed above, all have Message as its one input argument (and output for IRequestReplyChannel). Since the contracts are very generic, a routing service can handle any communication between the client and the routed server (i.e. since they just take Message, it involves no typed serialization regardless of the contract of the routed service).

When a RoutingBehavior is called its ApplyDispatchBehavior() with a ServiceHostBase argument, it adds RoutingExtension to the service host. Then (1) it updates its service "instance context provider" (IInstanceContextProvider) that instantiates a RoutingService (which has no public constructor) and sets the routing configuration to it, and (2) creates a set of clients for the dispatched services internally.

There is another "endpoint behavior" SoapProcessingBehavior. It takes part in the router-to-service communication and adjusts messages (as I explained above e.g. updating message versions). You don't have to deal with it.

It is in very early stage and in fact I only tried request-reply style router.

Bonus

Our Routing stack should work on .NET 3.5 too. Try "make" under mcs/class/System.ServiceModel.Routing - it will build mcs/class/lib/net20/System.ServiceModel.Routing.dll i.e. for 2.0 profile. There is nothing new I depended for its underlying layer.

Mono WCF Advent Day 12: NetPeerTcpBinding

| 1 Comment | No TrackBacks

With related to NetTcpBinding, I have also implemented NetPeerTcpBinding, which is based on peer-to-peer communication.

NetPeerTcpBinding involves a lot of complicated things, so I'm not likely to explain a lot.

Peer to peer channel overview

NetPeerTcpBinding itself is a binding for duplex messaging with binary message encoders (like NetTcpBinding) and its own transport, namely PeerTransportBindingElement. It also involves a "peer resolver" which is used to manage peer node statuses.

PeerTransportBindingElement is a transport binding element like HttpTransportBindingElement or TcpTransportBindingElement. While HTTP endpoint is a typical http URI (locally it is most likely only about the port), and TCP endpoint is about an IP endpoint (I forgot to mention yesterday, but its URI is like "net.tcp://localhost:808"), peer transport endpoint is about a "mesh" name which is handled by a "peer resolver". Its URI looks like "net.p2p://mymesh/" . Messages are transmitted to all the "peer nodes" in the specified peer "mesh".

(If you read PeerTransportBindingElement API, you'd notice that it takes an IP endpoint for listening peer connections. But it is not the endpoint - peer transport indirectly uses it, unlike an IP endpoint for TCP endpoint.)

Actually, a peer resolver, which is represented as PeerResolverBindingElement, is more inportant to know the actual peer transport destination. On .NET there are (nominally) two ways to "resolve" peer nodes to transmit messages: (1) PNRP, represented as PnrpPeerResolverBindingElement is Windows peer node resolution protocol, and (2) custom resolver, represented as PeerCustomResolverBindingElement, is resolver-instance-by-user peer resolver with IPeerResolverContract and CustomPeerResolverService API.

With PNRP you don't have to specify anything to resolve peers. It is however not available in Mono (PNRP is Windows specific and I haven't spent any time to implement it). With custom resolver, you have to (only) specify a service endpoint (Binding and EndpointAddress) to IPeerResolverContract service, which is typically CustomPeerResolverService.

Having your host is simple. Just create a ServiceHost with CustomPeerResolverService and add a service endpoint for IPeerResolverContract.

Usage example

(NOTE: As it depends on NetTcpBinding and it has some blocking issues right now, this binding does not likely work fine either.)

I haven't written any cool net-peer application beyond simple tests. Instead, I used chat application which used to be the top Google results for "WCF application". The server isn't really a peer channel server but rather a custom peer resolver, but the clients show basic use of net-peer communication.

The example code makes use of PeerNode and its interface IOnlineStatus.

Implementation internals

The public peer resolver API does not tell much, but its internals are complicated. It has to provide several operations such as, register node to the target mesh (Register), resolve nodes in the target mesh (Resolve), updates node availability statuses (Refresh) and unregister the node from the mesh (Unregister).

Microsoft has a dedicated Windows protocol documentation. The expected peer resolver mechanism is documented as [MC-PRCR] and [MC-PRCH].

In .NET, CustomPeerResolverService internally uses PNRP to implement IPeerResolverContract, So, while "nominally" custom peer resolver is one of the two peer resolver kinds, there is actually only PNRP on .NET.

In Mono, I created BasicHttpBinding-based ad-hoc peer resolver service that is launched within a mono process that uses custom resolvers (the internal "LocalPeerResolverService" class in System.ServiceModel.dll implements the service). It checks port 8931 availability, and if it is already used then it premises as if it were occupied by another custom resolver of our implementation. This behavior may change in future versions.

For paranoiac

It is a trivia I found during NetPeerTcpBinding hacking. You cannot expose WSDL for IPeerResolverContract using ServiceMetadataBehavior (see Day 5) because of duplicate global element for 'http://schemas.microsoft.com/net/2006/05/peer:Update' . 99.999% of WCF users wouldn't have to do it though (say, you don't have to implement CustomPeerResolverService).

The reason for this is complicated: it is because RegisterResponseInfo and UpdateInfo have conflicting return element name "Update" (in the same XML namespace) due to its MessageBodyMemberAttribute. That's my guess though - as IPeerResolverContract methods use message contracts for its argument and return value types. But as the contract there wouldn't be other possibilities so it should be almost precise.

The above story is almost nothing for you. But this kind of faulty contract design could happen by chance and it cannot be checked very obviously. The only way I can suggest to try to avoid such problem is to check WSDL generation frequently (like, every time you change the message contract).

Mono WCF Advent Day 11: NetTcpBinding

| 6 Comments | No TrackBacks

Until today I have explain only two Bindings (or three): BasicHttpBinding and WebHttpBinding (and CustomBinding if it counts). But as I implied earlier, we have more. Today I'd explain TCP transport and NetTcpBinding and couple of new things.

In short, NetTcpBinding is WCF-only, non-interoperable binding based on binary messages and TCP transport.

Binary XML serialization

"Binary XML" is not really XML. It is fake, a buzzword. It actually means, a binary representation based on XML Infoset (or something, depending on what it would describe). In WCF land, binary XML usually means an XML binary format used by XML reader and writer from XmlDictionaryReader.CreateBinaryReader() and XmlDictionaryWriter.CreateBinaryWriter().

While we have corresponding implementation since 2005, its data format has been recently published as [MC-NBFX] as part of Microsoft's Windows Protocol documentation.

In WCF, there is BinaryMessageEncodingBindingElement that uses this binary XML representation to serialize and deserialize messages. You can explicitly use it as message encoder part of your binding (using CustomBinding) as I did on Day 3. NetTcpBinding uses this one without customization.

Request/Response vs. Duplex

Message transport protocol also involves its own binary representation, but I have to explain "channel types" in prior. Until today I haven't explain about channel types, in other words types of IChannel interface variety - as BasicHttpBinding and WebHttpBinding are both for request-reply style communication. WCF is not only about it - it actually supports:

  • request-reply messaging: represented as IRequestChannel and IReplyChannel. A client sends a request to a server, then the server receives it and sends reply back to the client, and the client receives it.
  • simplex messaging: represented as IOutputChannel and IInputChannel. A client sends a message to a server, then the server receives it. No further communication is performed.
  • duplex messaging: represented as IDuplexChannel. Either of the communication sides may perform simplex messaging.

They may also involve sessions and in such case they become IFooSessionChannel (e.g. IRequestSessionChannel). To know which kind of messaging is supported by the Binding you are using, you can use CanBuildChannelFactory<TChannel>() method for clients or CanBuildChannelListener<TChannel>() method for servers.

It may look strange, but duplex messaging could be still used to support service method that has both invocation parameters (request) and return value (reply).

TCP binary data exchange

Back to NetTcpBinding, it supports two kinds of above, under different configuration; NetTcpBinding has TransferMode property and it indicates the communication channel style. If the property value is TransferMode.Streamed, then it creates request-reply type channel. If it is TransferMode.Buffered, then it results in duplex channel. While duplex channel could be used for RPC-style service calls, the underlying communication protocol becomes different. So you have to adjust the transfer mode between client and server.

The communication protocol is also documented, as [MC-NMF] and some related docs in Windows Protocol documentation.

NetTcpBinding example

Here is an example pair of NetTcpBinding client and server, using buffered == duplex communication mode.

[NOTE] It turned out that I brought some regressions which broke some binary message communication. It has been a while since I have implemented a couple of months ago. I've been fixing some bugs these days.

// client
using System;
using System.Xml;
using System.ServiceModel;
using System.ServiceModel.Channels;

public class Test
{
  public static void Main ()
  {
    var binding = new NetTcpBinding ();
    binding.Security.Mode = SecurityMode.None;
    var endpoint = new EndpointAddress ("net.tcp://localhost:8080/");
    var proxy = new ChannelFactory<IFoo> (binding, endpoint).CreateChannel ();
    Console.WriteLine (proxy.Echo ("TEST FOR ECHO"));
    Console.WriteLine (proxy.Add (1000, 2000));
  }
}

[ServiceContract]
public interface IFoo
{
  [OperationContract]
  string Echo (string msg);

  [OperationContract]
  uint Add (uint v1, uint v2);
}
// service.cs
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

public class Tset
{
  public static void Main ()
  {
    ServiceHost host = new ServiceHost (typeof (Foo));
    NetTcpBinding binding = new NetTcpBinding ();
    binding.Security.Mode = SecurityMode.None;
    var uri = new Uri ("net.tcp://localhost:8080");
    host.AddServiceEndpoint ("IFoo", binding, uri);
    host.Open ();
    Console.WriteLine ("Hit [CR] key to close ...");
    Console.ReadLine ();
    host.Close ();
  }
}

[ServiceContract]
public interface IFoo
{
  [OperationContract]
  string Echo (string msg);

  [OperationContract]
  uint Add (uint v1, uint v2);
}

class Foo : IFoo
{
  public string Echo (string msg)
  {
    return msg;
  }

  public uint Add (uint v1, uint v2)
  {
    return v1 + v2;
  }
}

Limitation

.NET NetTcpBinding is actually capable of handling some complicated things such as message security, but we don't provide message security support yet. If you have NetTcpBinding configured to use message security, NetTcpBinding.Security.Mode has to be set as None.

Mono WCF Advent Day 10: ASP.NET AJAX Integration

| 3 Comments | No TrackBacks

Well, yes, it continues a bit more...

Yesterday I explained WebHttpBinding which is dedicated to REST world. It is however just one aspect of the new REST support in .NET 3.5. Here is another one - you can invoke remote WCF services from ASP.NET AJAX.

Javascript proxy generator

What's done here is, basically the same as what ASP.NET AJAX do for System.Web.Services asmx support. In asmx integration land, there is Javascript proxy generator that accesses to the remote service and returns server responses back to Javascript land. The Javascript proxy source is retrieved at http://your.host.name/service.svc/js or http://your.host.name/service.svc/jsdebug (with debugging info).

The implementation is in ProxyGenerator class in ASP.NET AJAX assembly (System.Web.Ext.dll). By using ProxyGenerator.GetClientProxyScript() method, you can see how the raw Javascript proxy code is generated from your service contract, without actually deploying your service at your host.

It matches the Javascript code that you can see at somewhere like: http://your.host.name/service.svc/jsdebug

WebScriptEnablingBehavior

The next question is, how to provide such Javascript proxy at ./js or ./jsdebug for each service (endpoint). When there are two or more services, there will be two or more js proxies (foo.svc/js and bar.svc/js).

To resolve this, there is "WebScriptServiceHostFactory" which adds support for those js proxies for each service endpoint. It internally uses WebScripeEnablingBehavior which is derived from WebHttpBehavior. When WebScriptEnablingBehavior is attached to a service endpoint, it adds a special request "dispatcher" (precisely, EndpointDispatcher) to the host to handle requests to ./js or ./jsdebug as to return js proxy string.

I don't explain the mechanism a lot here, but in case you are curious, ChannelDispatcher, EndpointDispatcher and DispatchRuntime have a lot of customizible things at service host.

(In my previous post, I didn't explain much about WebHttpBehavior, an implementation of IEndpointBehavior. It actually plays the primary role on the REST binding support such as, setting "message formatter" to serialize request parameters using JSON serializer, to bind to and generate parameters from "URI template", etc. etc.)

Anyways, now we have a dedicated endpoint for Javascript for each service endpoint from the service instance. The service instance should be adjusted to use WebHttpBinding which is configured to use JSON as its message format so that the service can communicate with the JS proxy running in users' browser.

ASP.NET hosting

The entire service host setup above is valid to standalone ServiceHost too. But it does not make sense to do so - the primary purpose of those js proxies is reference from ASP.NET AJAX web pages. Hence there is almost no use for standalone hosting.

I don't write a lot to explain how to use <asp:ServiceReference > and proxies in your ASP.NET AJAX web page (Javascript) here - our bug #525575 shows simple usage.

Xmas!

| No Comments | No TrackBacks

It's 5am here so I don't think I can give long explanation on my hack so I'll do it in later days, but here is one of my hobby hack of this year: visual MIDI player based on Moonlight desktop.

mldsp-gtk-2009xmas.png

Sources and brief introduction are on github.

Merry Christmas!

Mono WCF Advent Day 9: RESTful WebHttpBinding

| 6 Comments | No TrackBacks

REST support has been introduced in .NET 3.5. It includes JSON support for message serialization, and support for RSS and Atom for consuming web feeds (as serialization contract). It is implemented as WebHttpBinding in System.ServiceModel.Web.dll.

Unlike some of the topics I wrote earlier, our REST support compatibility for .NET 3.5 is almost feature complete (yes I prefer RESTians than SOAPy people).

URI Templates

REST services have "resources" identified by URLs, like: http://localhost/ShoppingService/Products/by-name/RupertsDanceLesson_DVD

While HTTP transport stack is reusable, the existing BasicHttpBinding does not fill such needs - the destination of its request is identified by SOAP request header or HTTP request content body. A dedicated message encoder is required.

The alternative mechanism used for processing such requests in WebHttpBinding is "UriTemplate" which is a syntax based on URI but includes expressions like '{x}'. For example: "/ShoppingService/Products/by-name/{name}"

When a client is to send a request with certain set of parameters, the client first determines the request URI by filling dynamic parts of the URI template. Then the client sends the request to the service. When the service received a request, it tries to determine which operation in the service should handle it, and extract parameter values from the actual request URI. There won't be files at the corresponding destination URI. It's all virtual.

JSON reader, writer, serializer

Requests in WebHttpBinding are created as an URI. Responses in REST services are often returned as JSON. With WebHttpBinding, you can read and write JSON in certain structure - since WCF Messages are serialized as "XML", which strictly means, XmlDictionaryReader/Writer, the JSON input and output are also represented as the XML reader and writer. I don't explain the details, but you can start reading from JsonReaderWriterFactory.

There also is another specialized type for JSON serialization i.e. DataContractJsonSerializer. It reads and writes JSON instead of XML.

JSON serializer could be also used for serializing complex request parameters.

Of course, WebHttpBinding does not always use JSON. Rather, it uses POX (plain old xml) by default.

RSS and Atom serialization

Another typical practice in REST world is use of syndication feeds such as RSS and Atom. WCF 3.5 added support for serialization of those feeds. In System.ServiceModel.Syndication namespace there is a couple of types for data contract serialization of feeds and feed items.

Operations using WebGet and WebInvoke

With WebHttpBinding the existing OperationContractAttribute is not sufficient to provide how to host services. A URI template must be associated to each operation. WebGetAttribute or WebInvokeAttribute are used onto an operation method to bind URI template. Though, you don't have to explicitly design the service URI; it will be automatically inferred like: http://...[baseuri]/[operation]?argFoo={argFoo}&argBar={argBar}...

Adding [WebGet] or [WebInvoke] does not automatically work for WCF engine to assure that it is RESTful service. You also have to use either a dedicated channel factory or a service host, or WebHttpBehavior, a custom IEndpointBehavior. While WebHttpBehavior plays the primary role for everything I explained above and more, former approach would be easier.

Now we are ready to write sample code and run.

// client
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Web;

[ServiceContract]
public interface IMyService
{
  [OperationContract]
  [WebGet (RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json)]
  string Greet (string input);
}

public class Test
{
  public static void Main (string [] args)
  {
    string name = args.Length > 0 ? args [0] : "anonymous joe";
    string url = "http://localhost:8080";
    WebHttpBinding b = new WebHttpBinding ();
    var f = new WebChannelFactory (b, new Uri (url));
    IMyService s = f.CreateChannel ();
    Console.WriteLine (s.Greet (name));
  }
}

// service
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;

[ServiceContract]
public interface IMyService
{
  [OperationContract]
  [WebGet (RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json)]
  string Greet (string input);
}

public class MyService : IMyService
{
  public string Greet (string input)
  {
    return "hola, " + input;
  }
}

public class Test
{
  public static void Main ()
  {
    string url = "http://localhost:8080/";
    WebHttpBinding b = new WebHttpBinding ();
    var host = new WebServiceHost (typeof (MyService), new Uri (url));
    host.AddServiceEndpoint (typeof (IMyService), b, "");
    host.Open ();
    Console.WriteLine ("--- type [CR] to quit ---");
    Console.ReadLine ();
    host.Close ();
  }
}

In the example above, I used WebChannelFactory<T> instead of client class which is derived from ClientBase<T>, but as long as you use a gives instance of IMyService from it, its role is almost the same as ClientBase.

Limitations

Sadly WebHttpBinding is not available in Moonlight (nor Silverlight). It is not because the REST style does not fit Silverlight or RIA land in general, but because Silverlight API lacks behavioral extensibility API. I see there is no reason to not add things like IEndpointBehavior, but that's what Microsoft API does.

While WebHttpBinding is more WWW-friendly, it is not always possible to handle RESTful services. To handle JSON objects, it automatically adds type IDs during serialization and expects the IDs on deserialization.

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.


Mono WCF Advent Day 7: Moonlight

| 1 Comment | No TrackBacks

Our WCF is ready in Moonlight 2.0. It provides Silverlight 2.0 compatibility, and filling 3.0 support should be almost easy (we need to implement things like CookieContainer support etc.). Actually our WCF stack has been improved a lot by the moonlight effort (the team gave several bug reports).

I haven't explained how to prepare Moonlight environment. Theis a wiki page for instructions I linked above (I assume it will be frequently updated, so I'm not going to give the anchor to the build instruction section now).

Also, when creating moonlight apps, make sure you have 'moonlight-web-devel' package (in case it is available in your distro) or some sort of equivalents (e.g. "MoonSDK") installed and set up.

Some notes

  • WCF in .NET and WCF in Moonlight are significantly different. We have almost feature complete WCF in Moonlight, while we lack a lot of features in .NET WCF. In WCF only BasicHttpBinding is supported in System.ServiceModel.dll (as Silverlight does).
  • As I mentioned on Day 5, Moonlight is the land of "async everywhere". So there isn't sync service calls. Operation methods are called with BeginFoo() and EndFoo() instead of Foo(). If you use them, EndFoo() is expected to be called inside AsyncCallback of the BeginFoo() argument. FooAsync() pattern is easier.
  • Silverlight applications may contain Microsoft's SDK assemblies. They are not what we implemented. For example, System.Xml.Linq.dll, System.Json.dll and System.ServiceModel.PollingDuplex.dll are SDK assemblies. I have never tried the last assembly, so it may or may not work.
  • Silverlight client can access the services only when it is from allowed domain by the website. "clientaccesspolicy.xml" and "crossdomain.xml" play the key role on the permission (I don't explain their details here, MSDN would give you hints).

Example

Now, let's build a simple app and see it's working. (NOTE: Here I use the latest version of svcutil which includes support for event-based async call I explained on Day 5.)

While it is possible to create a Moonlight application from console using "smcs" and "mxap" tools, I take the easiest way to create Moonlight project.

  • Start MonoDevelop (2.2 would be the best; earlier versions that support Moonlight project is fine).
  • Create a "Moonlight Application project", say, moonlight1. There are App.xaml, App.xaml.cs (folded), Page.xaml and Page.xaml.cs (folded) as the sources.
  • Just build and run to make sure it works (a web page with moonlight xap, printing "Hello Moon").
  • Prepare a WCF service which is hosted under xsp2 as explained on Day 6. It is important to host a service on ASP.NET since you have to provide access to "clientaccesspolicy.xml" (explained above). You cannot do it with a standalone ServiceHost at least in simple manner.
  • Create "clientaccesspolicy.xml" file on the hosted root directory. Moonlight WCF client will try to httpget the file. An example file content is pasted below, which states that it accepts SOAP requests from anywhere.
  • Create a client proxy explained on Day 5, by running: svcutil -moonlight http://localhost:8080/test.svc/wsdl
  • Open Page.xaml.cs on MonoDevelop, and add the code below for service invocation. The example means that the result from the SOAP response will be shown as a Javascript alert message when the application is loaded.
  • Run the Moonlight application project (F5 or F8). Moonlight addin will open your browser and show the test page.
<!-- clientaccesspolicy.xml -->
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-methods="*" http-request-headers="*">
        <domain uri="*">
        </domain>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true">
        </resource>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>
// Page.xaml.cs
this.Loaded += delegate {
  var binding = new BasicHttpBinding ();
  var address = new EndpointAddress ("http://localhost:8080/test.svc");
  var client = new HelloServiceClient (binding, address);
  client.GreetCompleted += delegate (object o, GreetCompletedEventArgs e) {
    System.Windows.Browser.HtmlPage.Window.Dispatcher.BeginInvoke (delegate {
        System.Windows.Browser.HtmlPage.Window.Alert (e.Result);
        tb.Text = e.Result;
    });
  };
  client.GreetAsync ("moonlight");
};

moonlight2-wcf-md.png

Mono WCF Advent Day 6: ASP.NET hosting

| 16 Comments | No TrackBacks

Mono WCF services can be hosted through ASP.NET. Actually, lots of WCF consumers in .NET would be aware only of this path, like, you may be only aware of .svc files and not ServiceHost class.

Service configuration through .config files

Until today I haven't explain any of .config file support while lots of WCF introductions do. I personally don't like WCF config support which rather brought confusion (and I was right; WCF 4.0 came with some simplification in this area), but if we want to use ASP.NET, we sort of need to use it.

We partially support service and client configuration by config files. A WCF configuration would look like this:

<configuration>
  <system.serviceModel>
    <services>
      <service name="HelloService" behaviorConfiguration="b">
        <endpoint binding="basicHttpBinding" contract="IHelloService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="b">
          <serviceMetadata httpGetEnabled="true" httpGetUrl="wsdl" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

By having this as "service.exe.config", you can omit these lines:

-    host.AddServiceEndpoint (
-      typeof (IHelloService), binding, address);

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

Note that configuration support is valid only on the full .NET profile. In Moonlight and MonoTouch there is an alternative (and much simpler) way to give configuration ("ServiceReferences.ClientConfig" file). I don't explain it here - try googling ServiceReferences.ClientConfig.

.svc http handler

.svc files in ASP.NET are processed by an IHttpHandler(Factory) to generate a service hosting class that internally starts ServiceHost and serves HTTP requests as a HTTP transport implementation. We do the same.

Now, it's time for instructions. First, create one-liner "test.svc" file as:

<%@ServiceHost Service="HelloService, service" %>

Then comment out the entire "Test" class from service.cs.

+ /*
  public class Test
(...)
  }
+ */

Create "bin" directory, and compile the service class into a library this time:

$ mkdir bin

$ gmcs -t:library -out:bin/service.dll service.cs -pkg:wcf

To run the service in ASP.NET, you need a configuration (now that you don't have configured service host in Test class). To do it, use web.config. Copy the example config above:

$ cp service.exe.config web.config

Then run:

$ xsp2

Now your service is hosted at http://localhost:8080/test.svc (note that the URL now ends with "test.svc"). Go to http://localhost:8080/test.svc/wsdl , there should be the WSDL we exposed at Day 5.

Limitations

ASP.NET integration is under some tricky situation to fit with existing HttpListener-based channel implementation, and actually have some safety nets that blocks concurrent calls. It would work, but is not likely to scale so far.

Though, as a HTTP server, xsp outperforms HttpListener a lot, so it may work nicer in the future (unless you hit WCF-specific bugs). The simpler (especially for debugging) is those without xsp. I have to admit that ASP.NET integration is somewhat buggy so far.

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.

Mono WCF Advent Day 4: Message and data contract

| 1 Comment | No TrackBacks

Until today I have carefully avoided any use of complex data transfer than mere string. Our WCF stack is however ready to use complex data than just a string.

Data contract serialization

Messaging system is tied to message serialization system. WCF has "data contract" as its own data serialization framework. Objects that are attributed as [DataContractAttribute] are serialized in its own manner i.e. only fields and properties attributed as [DataMemberAttribute] are written to the serialization output.

A simple usage example:

[DataContract]
public class UserInfo
{
  [DataMember]
  public string UserName { get; set; }
  [DataMember] // whoa, are you planning to send it via SOAP?
  public string Password { get; set; }

  public string Annotation { get; set; }
}
In the example ablve, only UserName and Password will be serialized. Data contract is actually sort of fake, you can serialize and deserialize non-datacontract objects. For example,
  • - Some types are serialized as "primitive". For example, XmlQualifiedName, Guid, UniqueId, DateTimeOffset, TimeSpan ...
  • - [Serializable] objects are serialized only by its fields. You can use System.Net.IPAddress. (It is actually used in peer-to-peer connection internals.) [UPDATE] this is not working in moonlight 2.0. It needs some backporting.[/UPDATE]
  • - By default, public fields and properties are serialized, unless it is marked as [IgnoreDataMember]. It should cover large amount of the classes in .NET land.
We support DataContractSerializer, while we don't support "NetDataContractSerializer" which is an alternative serializer in .NET WCF to support complete(?) CLR object serialization (yet). There is actually another data contract serializer. I'll revisit it in later days.

Serialization output is written to XmlDictionaryWriter, which is a derived implementation of XmlWriter, and deserialization input is read from XmlDictionaryReader, which is based on XmlReader. While they are "XML" reader and writer, anything that is based on XmlReader and XmlWriter should work. I will introduce JSON reader and writer in later days.

Message

In WCF, messages in the client-server system is represented as System.ServiceModel.Channels.Message class. A Message is originally mapped to the notion of a SOAP Envelope. A Message contains a set of Headers, Body (again, SOAP Header and SOAP Body), and message Properties (it is not transmitted). In an operation contract, Message can be used as its input and output, like:

[ServiceContract]
public interface IRequestAnything
{
    [OperationContract]
    Message Request (Message input);
}

In this contract you can send and receive any kind of Messages. If your input and/or output do not fit any of the supported serialization strategy and you are willing to handle them by yourself, it is useful.

A Message can be created by a lot of CreateMessage() method overloads. For example, CreateMessage(messageVersion, soapAction, bodyXmlReader) is useful to create a message from server replies, and CreateMessage(MessageVersion, soapAction, bodyObject) is useful to create a message from a serializable object (for both cases you wouldn't have to do it usually though). WCF internally uses those methods to create and read messages.

A Message also has a set of "properties". They do not show up in outputs, but may control the message transfer, or serialization. For example, you can use HttpRequestMessageProperty object which controls HTTP transport, for example by adding your own HTTP request header items.

Message contract

The last one I explain here is sorta confusing; you can sort of control the actual creation of messages by using "message contract", represented as [MessageContract] attribute. It is placed on sort of a data class where instances of it are to be serialized and deserialized.

Under message contract, members of the class with [MessageHeader] attribute are processed as message Headers, and members with [MessageBody] become the Body of the message. They can be any type and serialized using data contract serializer explained above. So, its' sort of confusing, but the usage is rather about message serialization, not arbitrary object serialization.

Missing stuff

In mono 2.6, I haven't finished (actually even haven't started) working on message fault contract support (such as FaultContractInfos). Things like MessageFault should work, but any further complicated contract stuff is left untouched yet.

Mono WCF Advent Day 3: Binding basics

| 1 Comment | No TrackBacks

Before starting today's post, let me clarify some strangeness for a couple of posts from now on. I originally wanted to write about Moonlight and MonoTouch support as Day 3, but turned out the order of the topics was sort of wrong and I needed to introduce some more, before talking about them. Hence, there will be some mention on Moonlight and MonoTouch support before introducing them, but please be patient to wait for them.

so-called ABC of WCF

In many introductions to WCF, there is "ABC" of WCF: address, binding and contract. While in my opinion ABC is not really important...

  • [A]ddress for most of WCF consumers is just an URI.
  • I gave a very short introduction to [C]ontract at Day 1, and I won't have to explain about it until I introduce our NetTcpBinding support.
  • ... so, today I'll mostly explain [B]indings.

Binding is a customized set of BindingElements, which in turn is to represent communication capabilities for each. Primary ones are:

  • MessageEncodingBindingElement, to represent a message encoder capabilities, which is used to serialize and deserialize service calls to and from Stream.
  • TransportBindingElement, to provide channels to transmit messages.
  • SecurityBindingElement, to provide security capabilities.

There is a lot more binding elements (the examples above are actually all abstract) that for each represent several capabilities. I don't explain a lot.

Another important concept for client and service interoperability is "message version" a.k.a MessageVersion. MessageVersion is used to adjust which SOAP version and WS-Addressing version are used. While it indicates a WS-Addressing version, it is not part of EndpointAddress, and is rather tied to Binding.

BasicHttpBinding

BasicHttpBinding is one of the supported binding in Mono 2.6, and the only supported binding in Moonlight and MonoTouch (except for CustomBinding which is explained later). It consists of two binding elements:

  • TextMessageEncodingBindingElement: supports XML message encoding.
  • HttpTransportBindingElement: supports message transport via HTTP.

BasicHttpBinding by default uses MessageVersion.Soap11 (which is, SOAP 1.1 with no WS-Addressing).

CustomBinding

Most of WCF consumers would use HTTP transport, which is HttpTransportBindingElement (or HttpsTransportBindingElement). There is also TcpTransportBindingElement, which is used in NetTcpBinding and other couple of bindings. In BasicHttpBinding, text XML message encoding is used, which is provided by TextMessageEncodingBindingElement, but there is also BinaryMessageEncodingBindingElement, which is to use "binary" message format.

I'll explain about them in the other day, but what I would note here is that you can mix a couple of binding elements by using CustomBinding. For example, it is possible to use binary message encoding over HTTP transport. Try it by modifying the Day 1 example by changing

    var binding = new BasicHttpBinding ();

to

    var binding = new CustomBinding (
      new BinaryMessageEncodingBindingElement (),
      new HttpTransportBindingElement ());

(Note: I noticed such mixed usage did not work in Mono due to some regressions, and fixed it in trunk. So it won't work under current 2.6 release.)

More to come later

We have a few more bindings in our .NET profile. I'll lave them for later days.

Mono WCF Advent Day 2: Hello WCF

| 4 Comments | No TrackBacks

OK, Day 1 was spent mostly on the introduction. Today I'll start with the simplest pair of a client and a server. I don't explain how to use Mono here. There would be a lot of introductions on Mono itself, so revisit here once you got to know how-tos.

Examples

I start with a simple C# example pair of a client and a service:

// Client
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

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

public class HelloClient : ClientBase<IHelloService>, IHelloService
{
  public HelloClient (Binding binding, EndpointAddress address)
    : base (binding, address)
  {
  }

  public string Greet (string name)
  {
    return Channel.Greet (name);
  }
}

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 HelloClient (binding, address);
    Console.WriteLine (client.Greet (name));
  }
}
// Service
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

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

public class HelloService : IHelloService
{
  public string Greet (string name)
  {
    return "hola, " + name;
  }
}

public class Test
{
  public static void Main (string [] args)
  {
    var binding = new BasicHttpBinding ();
    var address = new Uri ("http://localhost:8080");
    var host = new ServiceHost (typeof (HelloService));
    host.AddServiceEndpoint (
      typeof (IHelloService), binding, address);
    host.Open ();
    Console.WriteLine ("Type [CR] to stop...");
    Console.ReadLine ();
    host.Close ();
  }
}

Now, open two new text files, client.cs and service.cs, for each of above. To create executables, compile them to exes:

$ gmcs client.cs -pkg:wcf
$ gmcs service.cs -pkg:wcf

Here I used a mono-specific command line option: -pkg:wcf. -pkg option is used to give a set of compiler options. It is based on pkgconfig system, so you can see what it gives by running "pkg-config --libs wcf" . Our C# compilers does not automatically add references to non-core assemblies, so you have to add them manually like "gmcs -r:System.ServiceModel.dll foo.cs" unless you use this -pkg option.

Once you got client.exe and service.exe, run them in order (you had better open two console windows or tabs):

$ mono service.exe
Type [CR] to stop...
$ mono client.exe  # without arguments
hola, anonymous joe

$ mono client.exe eno # with an argument
hola, eno

Contract and client

The client example is a typical WCF client generated by either a "Service Reference" in Visual Studio or "svcutil.exe" tool in Windows SDK.

In the code, it first has a "contract" interface IHelloService, which is also included in the service code. The interface type is attributed by [ServiceContract] and its Greet() method is attributed by [OperationContract]. They make up the "service contract".

With an identical contract, it is possible for a client and a server to communicate with each other, as long as they share "address" and "binding". The "address" here is an EndpointAddress, or a Uri which point to "http://localhost:8080" here. The "binding" here is BasicHttpBinding. I don't explain about them right now.

A "Contract" is realized by ClientBase<T> class at client side, and ServiceHost class at service side (it is not most precise explanation, but most of WCF consumers can live with it).

ClientBase<T> is an abstract class and used to be derived with the contract interface itself (see how HelloClient class is declared). To complete the derived class, it just has to implement the contract interface, and it can just use the "Channel" property, which is of the interface type itself (it is automagically generated internally).

Service and communication

While you don't have to "implement" the interface by yourself (well, HelloClient implements Greet(), but there isn't any of your logic code; you just delegated it to the Channel), you have to implement the actual processing of Greet() operation in your service code. The example above hence implements it, by just returning "Hello, " + name.

Once you implemented your contract, then create a ServiceHost object by passing the type of your implementation class. You will then need another magic line of code: AddServiceEndpoint() indicates that a specific contract interface in the implementation class (the service class may implement more than one contract interfaces) is bound to a specific "binding" and an "address" again.

Now the service is ready to run. Open() indicates that the service instance to serve requests. It internally starts a service listener loop threads to process incoming client requests, which are independent of the Main() thread (you can stop the ServiceHost at any time by calling Close() method).

While the service is open, try running client.exe. It internally creates a SOAP request (which is what BasicHttpBinding creates) and sends it to "http://localhost:8080" (the endpoint address), and processes the response received from the service, where the response is a SOAP message that includes "Hello, " + input.

Mono WCF Advent (, sort of) Day 1: Get Started

| 1 Comment | No TrackBacks

OK, ok, I know it's too late to start advent now, but since Mono 2.6 has released, I think it's sort of good timing to write about our WCF stack. In the next few days I'll write about them.

Resources

Our WCF work is ongoing primarily in our SVN trunk, though most of the writings here would apply to 2.6. If you are going to try our WCF with the 2.6 release, check out our download page. If you want to keep up with our ongoing hacking, SVN repository and the build instructions are your starters.

I update a WCF status wiki page from time to time.

We keep track of our missing features by assembly analyses and MonoTODO attributes in our own assemblies. Based on the analyses, our QA team provides a decent class library status pages. You can see if specific WCF features are either missing, wrong, not implemented or imperfect. (You need to know in which assembly the type you would like to know is).

We have mono mailing lists where you can post your questions regarding WCF. mono-list (for users) or mono-devel-list (regarding mono hackings) are the best places. (Historically, we used to have WCF in our "olive" module as well as mono-olive mailing list, which is used to serve new API stuff, but now we don't have WCF stuff there. They are all moved under mcs.) Forums are also bound to the mailing lists, so you can use them instead.

We also have IRC channels. I'm usually in #mono, #monodev and #moonlight while I'm up, logged in as 'eno'.

See if your WCF app runs - MoMA

The entire WCF stack is huge, and I didn't fill everything with regarding the implemented feature sets. If you have WCF apps that you believe should run on Mono, please try MoMA and see what it tells. It won't give perfect reports, but may give you some points why it won't run. And if you give us MoMA report feedback, we can sort out which functionality is lacking and wanted.

Note that what MoMA gives you is just assembly analyses. It won't give you other feature statuses such as configuration section support, ASP.NET integration support, platform dependencies, bug status and lack of support of some assemblies (for example, we don't support WCF Data Services yet and it won't be reported, as we don't even have the corresponding assemblies).