When creating Line of Business (LoB) applications with Silverlight, the only choice to get the data to the application is through webservices. People having their Silverlight application hosted on the same webserver as the service have almost no problem, but things get interesting when service is not hosted on the same machine as the application, and it gets hairy when you self-host a WCF service. Let’s see how it is done in each scenario.

Background

Generally, RIA applications including Adobe AIR or Microsoft Silverlight due to certain considerations, won’t let your application use a remote service, if the service does not allow you to connect explicitly. This is done through a Client Policy file that should be available at the root of the webserver running the service. The client policy file, which is an XML document, grants the client permission to connect to the service. For example, if your webservice is running on a domain, e.g.

http://server/OrderingService

your client policy file should be located at the root of the same domain, for example for a Silverlight application using the above service, it’d be located at:

http://server/clientaccesspolicy.xml

For more information about this file and content of the file, you can check out the specification here.

Web hosted Web Service

This is the easiest of them all. Since your webservice is hosted in a webserver, you just need to create a xml file and place it at the root of your webserver. To make sure it works, open the address to the Client Policy file in your web browser. This works painlessly for WCF services using basic HTTP binding that are hosted on IIS.

JBoss hosted JAX-WS Service

Since JAX-WS services comply with SOAP standards, these services are considered regular http webservices, so if you have read my series describing how you can use JBoss to host your services and create a Silverlight rich client to consume those services, you already have figured out the basics.

But JBoss is an application server…How can I add a xml file to the root of the ‘application server’? JBoss comes with a built-in Apache webserver and there is a special folder in your JBoss installation that is considered the webserver root. So just like IIS where you copied your file to the root of the webserver, copy the client policy file into:

%JBoss Folder%/server/%installation%/deploy/jboss-web.deployer/ROOT.war/

The above path translates into this on my machine:

C:\Java\JBoss-4.2.3.GA\server\default\deploy\jboss-web.deployer\ROOT.war\

Self-Hosted WCF Service

It gets pretty interesting when you’re hosting the WCF services yourself. When it comes to hosting the WCF service, it is possible to use a Console Application (or much better a Windows Service) to host the services for you. This way, you just have a Windows service or an application, which both are way different than a webserver. Where should you place the client policy file now?

There are many benefits that comes free when hosting the WCF service in IIS, so self-host the services in case you have a good reason to.

To return the client policy file when a request comes through you need to create a special Service Host that does just that. It is mandatory to use WebHttpBinding to make this work. Then you can create a WCF service that returns the content of the client policy. Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[ServiceContract(Namespace = ServiceSettings.Config.GeneralNamespace)]
public interface ICrossDomainService
{
[OperationContract]
[WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream ProvidePolicyFile();
}

public class CrossDomainService : ICrossDomainService
{
public Stream ProvidePolicyFile()
{
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 ConvertToStream(result);
}

private Stream ConvertToStream(string result)
{
WebOperationContext.Current.OutgoingResponse.ContentType = 'application/xml';
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
}

Did you notice the extra WebGet attribute beside the ServiceContract? Specifying the UriTemplate will do the trick and will send the hard-coded content of the client policy when a request at specified Uri comes through.

Make sure you don’t mix up these two bindings. For WCF service to be consumable in Silverlight client, you need to have a BasicHttpBinding but for the client access content binding should be WebHttpBinding.