Debugging tips and small examples for WCF
In order for a Silverlight (or Flash) app coming from one domain to be able to consume data from services in a different domain, the service must "allow" the app to do so by providing a policy file which grants access (to prevent all sorts of cross-site scripting attacks). This policy file must be located in the root of the "domain" (hostname + port), so if your service is located at http://my.service.com:8000/Service/CoolService.svc/Endpoint, the policy file must be located at http://my.service.com:8000/ClientAccessPolicy.xml (or http://my.service.com:8000/crossdomain.xml in case of the Flash format). That's fairly easy to do on a IIS-hosted service (simply put the static policy file in the root of the web), but for self-hosted apps it isn't as simple (there's no "root" of the web).
To solve this problem for self-hosted WCF services, you can use the web programming model support fairly easily. Basically, you'd define the base address at the root of the domain, and have a web endpoint at the "" address. All the "real" service endpoints would then be in different addresses. The example below shows it in action:
public class SelfHostedServiceWithSilverlightPolicy
{
[ServiceContract]
public interface ITest
{
[OperationContract]
string Echo(string text);
}
[ServiceContract]
public interface IPolicyRetriever
{
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream GetSilverlightPolicy();
[OperationContract, WebGet(UriTemplate = "/crossdomain.xml")]
Stream GetFlashPolicy();
}
public class Service : ITest, IPolicyRetriever
{
public string Echo(string text) { return text; }
Stream StringToStream(string result)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
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);
}
public Stream GetFlashPolicy()
{
string result = @"<?xml version=""1.0""?>
<!DOCTYPE cross-domain-policy SYSTEM ""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">
<cross-domain-policy>
<allow-access-from domain=""*"" />
</cross-domain-policy>";
return StringToStream(result);
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "basic");
host.AddServiceEndpoint(typeof(IPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add(smb);
host.Open();
Console.WriteLine("Host opened");
Console.Write("Press ENTER to close");
Console.ReadLine();
host.Close();
}
}
Anonymous comments are disabled
About carlosfigueira
Software Design Engineer in Test at the Connected Frameworks team at Microsoft.