Enabling cross-domain calls for SL apps on self-hosted TCP services

On a post a couple of years back, I showed a solution to enable cross-domain calls for Silverlight apps on self-hosted WCF services. In Silverlight 4, we added a new transport (net.tcp), which needs its own policy file as well (see more details at https://blogs.msdn.com/b/silverlightws/archive/2010/04/09/policy-file-for-nettcp.aspx). If you are running IIS (or some other web service) on port 80 the machine on which the TCP service is running, the easiest way to deploy the appropriate policy file is to simply copy the file to its root directory (in IIS it would be something like c:\inetpub\wwwroot), and you're ready to go.

If you don't have IIS, however, you can use a similar solution than the one I had for "normal" (i.e., HTTP-based) WCF services to serve the policy file for the TCP service. Again, if you have IIS (or other web service running on port 80), you don't need to do this, just drop the policy file on the server root directory and you're good to go. Essentially, the code will act as a web server and serve the "policy file" to SL apps when requested. The base address for the WCF REST service would be listening at port 80 on the machine, and its endpoint would be listening at the "" address. Here's the code:

  1. namespace SelfHostedTcpAndSilverlight
  2. {
  3.     [ServiceContract]
  4.     public interface ITest
  5.     {
  6.         [OperationContract]
  7.         string Echo(string text);
  8.     }
  9.     [ServiceContract]
  10.     public interface ITcpPolicyRetriever
  11.     {
  12.         [OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
  13.         Stream GetSilverlightPolicy();
  14.     }
  15.     public class Service : ITest, ITcpPolicyRetriever
  16.     {
  17.         public string Echo(string text)
  18.         {
  19.             return text;
  20.         }
  21.         public Stream GetSilverlightPolicy()
  22.         {
  23.             string result = @"<?xml version=""1.0"" encoding=""utf-8""?>
  24. <access-policy>
  25.     <cross-domain-access>
  26.         <policy>
  27.             <allow-from http-request-headers=""*"">
  28.                 <domain uri=""*""/>
  29.             </allow-from>
  30.             <grant-to>
  31.                 <socket-resource port=""4504"" protocol=""tcp"" />
  32.             </grant-to>
  33.         </policy>
  34.     </cross-domain-access>
  35. </access-policy>";
  36.             WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
  37.             return new MemoryStream(Encoding.UTF8.GetBytes(result));
  38.         }
  39.     }
  40.     class Program
  41.     {
  42.         static void Main(string[] args)
  43.         {
  44.             string baseAddressHttp = "https://" + Environment.MachineName + ":80";
  45.             string baseAddressTcp = "net.tcp://" + Environment.MachineName + ":4504/Service";
  46.             ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddressHttp), new Uri(baseAddressTcp));
  47.             host.AddServiceEndpoint(typeof(ITest), new NetTcpBinding(SecurityMode.None), "");
  48.             host.AddServiceEndpoint(typeof(ITcpPolicyRetriever), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
  49.             ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
  50.             host.Description.Behaviors.Add(smb);
  51.             host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
  52.             host.Open();
  53.             Console.WriteLine("Host opened");
  54.             Console.Write("Press ENTER to close");
  55.             Console.ReadLine();
  56.             host.Close();
  57.         }
  58.     }
  59. }