Consuming REST/POX services in Silverlight 4

Silverlight 4, which was just released, comes with some functionality to consume REST/POX services with the same programming model in WCF (i.e., the functionality equivalent to the WebChannelFactory<T> in the desktop version). The support is limited to XML services (i.e., JSON is not supported by default), but there are some extensibility points which can be used to enable sending / receiving strongly-typed JSON data to REST services as well. The support includes the [WebGet]/[WebInvoke] attributes, with full UriTemplate semantics.

Just like in the desktop framework, the "Add Service Reference" dialog won't create a client / proxy for REST services, so a common usage scenario is to define an interface with the Begin/End variation of the methods to be compiled in Silverlight projects. The code below can be shared between a service implementation (which would have the synchronous version of the operations) and the Silverlight client (which would see the async methods which can be called by SL).

[ServiceContract]
public interface IRestService
{
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
  #if !SILVERLIGHT
  [OperationContract]
string Concat(string text1, string text2);
  #else
  [OperationContract(AsyncPattern = true)]
  IAsyncResult BeginConcat(string text1, string text2, AsyncCallback callback, object state);
  string EndConcat(IAsyncResult asyncResult);
  #endif
  [WebGet(UriTemplate = "/ConcatGet/{text1}?t2={text2}")]
  #if !SILVERLIGHT
  [OperationContract]
string ConcatGet(string text1, string text2);
  #else
  [OperationContract(AsyncPattern = true)]
  IAsyncResult BeginConcatGet(string text1, string text2, AsyncCallback callback, object state);
  string EndConcatGet(IAsyncResult asyncResult);
  #endif
}

The WebHttpBinding class (commonly used in the desktop to consume POX services) is not available in SL4, nor is the WebMessageEncodingBindingElemnet class. However, for XML services, the TextMessageEncodingBindingElement class can be used, when it's used with MessageVersion.None:

IRestService CreateProxy()
{
    CustomBinding binding = new CustomBinding(
        new TextMessageEncodingBindingElement(MessageVersion.None, Encoding.UTF8),
        new HttpTransportBindingElement { ManualAddressing = true });
    string address = GetServiceAddress();
    ChannelFactory<IRestService> factory = new ChannelFactory<IRestService>(binding, new EndpointAddress(address));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
    IRestService proxy = factory.CreateChannel();
((IClientChannel)proxy).Closed += delegate { factory.Close(); };
    return proxy;
}

At this point, the code can invoke the REST/POX server just like a "normal" WCF service:

private void btnConcatPost_Click(object sender, RoutedEventArgs e)
{
    IRestService proxy = CreateProxy();
proxy.BeginConcat(this.txtText1.Text, this.txtText2.Text, new AsyncCallback(ConcatPostCallback), proxy);
}
void ConcatPostCallback(IAsyncResult asyncResult)
{
IRestService proxy = (IRestService)asyncResult.AsyncState;
string result = proxy.EndConcat(asyncResult);
this.Dispatcher.BeginInvoke(() => this.txtResult.Text = text);
((IClientChannel)proxy).BeginClose(new AsyncCallback(CloseCallback), proxy);
}
void CloseCallback(IAsyncResult asyncResult)
{
IRestService proxy = (IRestService)asyncResult.AsyncState;
((IClientChannel)proxy).EndClose(asyncResult);
}

The WebHttpBehavior class is located in the SDK assembly System.ServiceModel.Web.Extensions.dll. The complete solution with this sample can be found in the Code Gallery repository at https://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=silverlightws&ReleaseId=4059 ("Client for REST/POX services")