Published
Thursday, March 27, 2008 5:06 PM
by
mtaulty
This really falls into the category of "just because it's there" because it's something I was thinking about earlier today and wanted to experiment with.
Silverlight 2 applications can make web service calls across domain boundaries if the domain that they are calling to allows that. So, I was thinking about a scenario where perhaps I've got a local application installed such as a WPF application or perhaps a Vista Sidebar gadget and I go and visit a Silverlight website and the Silverlight client can notify the installed application and cause it to maybe "light up" in some fashion.
That is, a Silverlight 2 application communicating with another application that's installed and running on the local machine.
Before Silverlight will allow a cross-domain call it requests one of two files from the root of the site that it's calling to. I chose to use clientaccesspolicy.xml.
So, I wrote a quick "WCF Service" using the System.ServiceModel.Web stuff from .NET Framework V3.5. Service looks like this;
[ServiceContract]
public interface IHandlePolicy
{
[OperationContract]
[WebInvoke(UriTemplate = "clientaccesspolicy.xml", Method="GET", BodyStyle=WebMessageBodyStyle.Bare)]
XElement ReturnPolicy();
}
so if you request a URL clientaccesspolicy.xml then what I'll do is this;
public class PolicyHandler : IHandlePolicy
{
public XElement ReturnPolicy()
{
return (XElement.Load("policy.xml"));
}
}
and that policy.xml file simply looks like this;
<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from>
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/"
include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
I configured that up like this;
<service name="PolicyHandler">
<endpoint address="http://localhost:9091/"
binding="webHttpBinding"
contract="IHandlePolicy"
behaviorConfiguration="webHttpBehaviour"/>
</service>
and with a behaviour like this;
<endpointBehaviors>
<behavior name="webHttpBehaviour">
<webHttp/>
</behavior>
</endpointBehaviors>
and serving it up with code;
static void Main(string[] args)
{
WebServiceHost webHost = new WebServiceHost(typeof(PolicyHandler));
webHost.Open();
Console.WriteLine("Listening...");
Console.ReadLine();
webHost.Close();
}
So, now if I request URL http://localhost:9091/clientaccesspolicy.xml then this service will reply with my policy file.
I then added into the same project another SOAP based service. Aside - I was going to use a the System.ServiceModel.Web stuff here as well but then discovered that Silverlight does not seem to have the webHttpBinding or the WebInvoke/WebGet bits of .NET Framework V3.5 in the beta so I went with SOAP messages to a separate service listening on a sub path of the initial URI.
Here's the service;
[ServiceContract]
public interface IPrintMessages
{
[OperationContract]
void PrintMessage(string message);
}
and the implementation (not too exciting);
public class MessagePrinter : IPrintMessages
{
public void PrintMessage(string message)
{
Console.WriteLine(message);
}
}
and the configuration;
<service name="MessagePrinter"
behaviorConfiguration="metadataBehaviour">
<endpoint address="http://localhost:9091/printer"
binding="basicHttpBinding"
contract="IPrintMessages"/>
<serviceBehaviors>
<behavior name="metadataBehaviour">
<serviceMetadata httpGetEnabled="true"
httpGetUrl="http://localhost:9091/printer"/>
</behavior>
</serviceBehaviors>
and, finally, the hosting code now looks like;
static void Main(string[] args)
{
WebServiceHost webHost = new WebServiceHost(typeof(PolicyHandler));
webHost.Open();
ServiceHost soapHost = new ServiceHost(typeof(MessagePrinter));
soapHost.Open();
Console.WriteLine("Listening...");
Console.ReadLine();
soapHost.Close();
webHost.Close();
}
I built a quick Silverlight application with a TextBox and a Button, added a Service Reference to my web service by pointing at the WSDL file and then wrote a little code;
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
PrintMessagesClient proxy = new PrintMessagesClient();
proxy.PrintMessageAsync(myText.Text);
}
}
and, hey presto, I can see Silverlight requesting my clientaccesspolicy.xml file at runtime and then calling my service and I have my Silverlight app talking to my local app;
Now...whether there's actually a good use for that is another question but it was fun to me for a little while :-)
I put the zipped up project files here in case you want to play with them.