我知道这是一个老问题,但我确实有解决方案。
我做了这个确切的场景。我在 WPF 主机中托管 Silverlight 应用程序。我使用自托管 WCF 来提供双工网络 tcp 服务。为此,您还必须有一个 HTTP 托管的 clientaccesspolicy.xml,我也从同一服务自行托管。
我希望我能解释得足以让事情顺利进行。我会尽可能包含一些示例,但是由于项目的原因,我无法分享所有内容。
首先,一些注意事项:
1) Silverlight 和 WPF 之间的 net tcp 不安全,因为 Silverlight(从第 4 版开始 - 仅测试第 5 版)无法进行安全连接,因此如果要使用它,您必须自己进行加密。
2) 做双工WCF有两种方法,一种是使用HTTP。 HTTP 方法“轮询”服务以查看是否有任何命令来自客户端的主机。这本质上使它比 net tcp 慢得多。另一种是使用 net tcp(如前所述)。只有 http 方法支持开箱即用的加密。
3) 当您在 WPF 主机中托管 Silverlight 应用程序时,当您开始调试时,您将无法调试您的 Silverlight 应用程序,因为调试器不会连接到(如它所见)外部 Silverlight 应用程序,只有 WPF。要解决此问题,您必须在启动 WPF 主机时“激活”到 Silverlight 应用程序的附件。
现在是代码:
远程服务接口:
using System.ServiceModel;
namespace RemoteService
{
[ServiceContract(CallbackContract = typeof(IRemoteCallbackService))]
public interface IRemoteService
{
[OperationContract]
void TestCallback();
// TODO: Add your service operations here
}
[ServiceContract]
public interface IRemoteCallbackService
{
[OperationContract(IsOneWay = true)]
void OnTestCallbackComplete();
// TODO: Add your service operations here
}
}
您的策略侦听器接口:
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace RemoteService
{
[ServiceContract]
public interface IPolicyRetriever
{
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream GetSilverlightPolicy();
[OperationContract, WebGet(UriTemplate = "/crossdomain.xml")]
Stream GetFlashPolicy();
}
}
实际的服务实现:
using System.Text;
namespace RemoteService
{
public class RemoteService : IRemoteService, IPolicyRetriever
{
IRemoteCallbackService client = null;
public void TestCallback()
{
client = OperationContext.Current.GetCallbackChannel<IRemoteCallbackService>();
client.OnTestCallbackComplete();
}
#region Cross Domain Policy Implementation
private Stream StringToStream(string result)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
//<grant-to>
//<resource path="/" include-subpaths="true"/>
//<socket-resource port="4502-4534" protocol="tcp" />
//</grant-to>
Stream IPolicyRetriever.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""/><socket-resource port=""4502-4534"" protocol=""tcp"" /></grant-to></policy></cross-domain-access></access-policy>";
return StringToStream(result);
}
Stream IPolicyRetriever.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);
}
#endregion Cross Domain Policy Implementation
}
}
以上内容应位于一个 dll 项目中的不同类中,然后由您的 WPF 主机引用。
并将其托管在控制台应用程序中(您需要将其转换为 WPF):
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using LocalService;
using RemoteService;
namespace Host
{
internal class Program
{
/// <summary>
/// Main host entry point, this starts our listeners
/// </summary>
/// <param name="args">The args.</param>
private static void Main(string[] args)
{
// Start our listeners
StartListeners(80, 4504, true);
}
/// <summary>
/// Starts the listeners.
/// </summary>
private static void StartListeners(int HttpPort = 80, int NetTcpPort = 4504, bool StartRemoteService = true)
{
Console.WriteLine("Starting Policy Listener");
string policyaddress = "http://" + Environment.MachineName + ":" + HttpPort.ToString();
string locallistener = "net.tcp://" + Environment.MachineName + ":" + NetTcpPort.ToString();
// Start our policy listener and (if required) our remote http service:
using (System.ServiceModel.ServiceHost policyandremoteservicehost = new System.ServiceModel.ServiceHost(typeof(RemoteService.RemoteService), new Uri(policyaddress)))
{
policyandremoteservicehost.AddServiceEndpoint(typeof(IPolicyRetriever), new System.ServiceModel.WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
// if we are to start our remote service here too, then add that endpoint in:
if (StartRemoteService)
{
policyandremoteservicehost.AddServiceEndpoint(typeof(IRemoteService), new System.ServiceModel.PollingDuplexHttpBinding(), "RemoteService");
}
ServiceMetadataBehavior psmb = new ServiceMetadataBehavior();
psmb.HttpGetEnabled = true;
psmb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
policyandremoteservicehost.Description.Behaviors.Add(psmb);
policyandremoteservicehost.Open();
Console.WriteLine("WCF Host Running...");
Console.WriteLine("Press <enter> to shutdown");
Console.ReadLine();
Console.WriteLine("Closing connections, please wait");
policyandremoteservicehost.Close();
Console.WriteLine("Closed policy and remote services");
}
}
}
}
这应该会给你一些工作。 startremoteservice bool 可用于将其设置为策略文件侦听器,这样您就可以连接到远程服务,而无需远程服务托管策略文件。
请记住,Silverlight 只能连接到 HTTP/HTTPS 端口,以及 4502-4534 范围内的 TCP 端口。包含的 clientaccesspolicy.xml 是完全不受限制的。
我希望这对某人有用:)。
如果你愿意,请随时问我问题,我会留意的。
注意几点:您可以通过此解决方案为您托管的 xap 提供服务,因此不需要 IIS。您可以在浏览器之外运行 Silverlight xap 并仍然使用这些服务。
调试答案在这里:Debugging Silverlight hosted in WPF