I'm trying to get a Server application to expose some status information using WCF. In particular I'm after using WCF services with RESTful "API". I'm hitting somewhat of a wall when it comes to consuming the REST api from a silverlight app/page that I want to have as an additional type of client...
So far I've been successful in defining a status interface:
public static class StatusUriTemplates
{
public const string Status = "/current-status";
public const string StatusJson = "/current-status/json";
public const string StatusXml = "/current-status/xml";
}
[ServiceContract]
public interface IStatusService
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, UriTemplate = StatusUriTemplates.StatusJson)]
StatusResultSet GetProgressAsJson();
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = StatusUriTemplates.StatusXml)]
StatusResultSet GetProgressAsXml();
[OperationContract]
[WebGet(UriTemplate = StatusUriTemplates.Status)]
StatusResultSet GetProgress();
}
Implementing it in the server:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class ServerStatusService : IStatusService
{
public StatusResultSet GetProgressAsJson()
{ return GetProgress(); }
public StatusResultSet GetProgressAsXml()
{ return GetProgress(); }
public StatusResultSet GetProgress()
{
return StatusResultSet.Empty;
}
}
Exposing it from my code at runtime:
var service = new ServerStatusService();
var binding = new WebHttpBinding();
var behavior = new WebHttpBehavior();
var host = new WebServiceHost(service, new Uri("http://localhost:8000/server"));
host.AddServiceEndpoint(typeof(IStatusService), binding, "status");
host.Open();
I've even been successful with consuming the service from a .NET console/winfoems/WPF application using something along the line of this:
var cf = new WebChannelFactory<IStatusService>(new Uri("http://localhost:8000/server/status"));
var ss = cf.CreateChannel();
Console.WriteLine(ss.GetProgress().TimeStamp);
The "wall" I'm hitting is that there is NO WebChannelFactory for SliverLight.
Period.
This means that when it comes to silverlight code, my options are:
- Write ugly code using WebClient, which ultimately means I will have to update two sets of code whenever I have a change to my API
- Use SOAP/WS for the WebService and keep updating the service reference from Visual Studio
Is there a way to keep the "clean" implementation with WebChannelFactory in SilverLight? Perhaps a public domain / open source WebChannelFactory for SilverLight?
Any help with this will be greatly appreciated!
I almost hate to suggest it but would you feel comfortable with reimplementing the WebChannelFactory<T> class?
From a cursory glance through the Silverlight API it looks like you won't get much help from Microsoft out of the box. You'd need to reimplement a channel class and a factory for it.
Perhaps another way to create the channel and to isolate yourself from the platform-specific code is to create a custom implementation of it? Specifically what I mean is, you create yet another factory class, and the factory class either calls to the WebChannelFactory when it's available, or goes through the hoops of setting it up for you.
Sorry I don't have a more in-depth suggestion. :)
So far I have found a few alternatives to WebChannelFactory for consuming REST services in Silverlight. They have all seen praise in forums and blogs, but I have yet to try any of them myself. I believe all three use generics to easily deserialize request responses into CLR objects.
I am leaning towards RestSharp, because its examples look both simple and extensible to me.
I recently ran into the same problem and decided to create a class that has a simplified REST client interface for Silverlight, more or less like WebChannelFactory. Has synchronous-like behavior also.
http://regular-language.blogspot.com/2011/06/wcf-webhttp-rest-client-for-silverlight.html
If this is a simple Xml REST service, why not use the WebClient in Silverlight to capture the XML using Linq to XML? I know you said its messy, but it all depends on how you look at it. if you change your service interface at anytime you're going to have to update your code in multiple places. Thats just the way it is.
So to do this, you will need to capture the data in an async fashion from the WebClient and then parse it with LINQ to XML.
Time Heuer has a good example on his site: http://timheuer.com/blog/archive/2008/03/14/calling-web-services-with-silverlight-2.aspx
Essentially, it looks like this:
Then in your "rest_DownloadStringCompleted" you'd parse the string as XML. Like so:
I've done the same thing with home grown REST Services from WCF and Silverlight and it worked great.
You are missing Spring.Rest : http://springframework.net/index.html#spring-rest-1.0.0-released