Rich Web client development with Silverlight,LINQ , WCF and now Prism

Tuesday, March 10, 2009

Building a WCF self Hosted service for Silverlight and WPF access

It is easy to build a WCF service that is callable from WPF by just defining an endpoint (1) below that uses net.tcp as we are interested in perfomance as in:


<system.serviceModel>
<services>
<service behaviorConfiguration="CustomersServer.Service1Behavior"
name="CustomersServer.Service1">
(1) <endpoint address="" binding="netTcpBinding" contract="CustomersServer.IGetCustomers">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8000" />
<add baseAddress="http://localhost:8002" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CustomersServer.Service1Behavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>


This is easily callable from my WPF application by adding a Service reference for
CustomersServer.IGetCustomers (net.tcp://localhost:8000) and adding code like:
GetCustomers.GetCustomersClient proxy = new WpfApplication1 .GetCustomers.GetCustomersClient();
//bind customer objects to DataGrid
toolkitGrid.ItemsSource = proxy.GetCustomers("a");

One can then easily add a basic HTTP endpoint and this should be callable from our Silverlight app. However there is a big problem with the Cross Domain Policy file that SL needs to find at the root of the web server (opps ..What web server as we are self
hosted). I struggled with this till I found the following article:
http://http://blogs.msdn.com/carlosfigueira/archive/2008/03/07/enabling-cross-domain-calls-for-silverlight-apps-on-self-hosted-web-services.aspx

Briefly this technique involves adding a WebHttpBinding endpoint that was added with 3.5 (usually used for Restful services). This will let us satisfy the HTTP GET for the clientaccesspolicy.xml that SL will issue. I ended up progammatically adding the endpoints for the BasicHttpBinding and WebHttpBinding as I was having issues with the declarative app,config. this looks like:

host.AddServiceEndpoint(typeof(IGetCustomers), new BasicHttpBinding(), "basic");
host.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());


this code and the above config file will result in 4 endpoints:
1 net.tcp://localhost:8000
2 http://localhost:8002/mex metadata discovery
3 http://localhost:8002/basic SL usable
4 http://localhost:8002 HTTP GET for clientaccesspolicy

For completeness my service contract looks like:

[ServiceContract]
public interface IGetCustomers
{
[OperationContract]
List GetCustomers(string startsWith);
}
[ServiceContract]
public interface IPolicyRetriever
{
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream GetSilverlightPolicy();

}
public class Service1 : IGetCustomers, IPolicyRetriever
{
public Stream GetSilverlightPolicy()
{
string result = <?xml version=""1.0"" encoding=""utf-8""?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers=""*"">
<domain uri=""*""/>
</allow-from>
<grant-to>
<resource path=""/"" include-subpaths=""true""/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>";
return StringToStream(result);
}
Stream StringToStream(string result)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}

}

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]



<< Home