2011-06-13 109 views
4

我有一個Silverlight 4應用程序,我想將其作爲Kiosk應用程序加倍。它必須是全屏,觸摸式的,最重要的是要有充分的信任。我正在考慮使用WPF應用程序來承載Silverlight XAP。我知道WPF/XNA SilverlightViewport,但似乎此解決方案不提供WPF和Silverlight之間的通信。如何在WPF 4應用程序中託管Silverlight 4應用程序?

這真的會爲我節省很多時間。我不必維護完全相同的兩個不同的應用程序,而且每次我進行更改時都不需要部署到數百個自助服務終端。

回答

3

我知道這是一個老問題,但我確實有一個解決方案。

我做這個確切的情況。我在WPF主機中託管Silverlight應用程序。我使用自己託管的WCF來提供雙工網絡TCP服務。要做到這一點,你還必須擁有一個HTTP託管的clientaccesspolicy.xml,我也自己從同一個服務託管。

我希望我能解釋得足以讓球滾動。我會盡可能包括一些樣本,但由於該項目,我無法分享所有內容。首先,需要注意的一點: 1)Silverlight和WPF之間的net tcp不安全,因爲Silverlight(從版本4開始 - 只是測試版本5)不能執行安全連接,所以如果你需要自己加密是用這個。

2)有兩種做雙工WCF的方法,一種是使用HTTP。 HTTP方法'輪詢'服務以查看是否有來自主機的任何命令來自客戶端。這固有地使它比net tcp慢得多。另一個是淨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主機引用。

到Host它在一個控制檯應用程序(你需要將其轉換爲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

0

最好的辦法是採用WCF/RIA服務和處理服務器端所有業務邏輯的三層架構方法。

通過保持您的客戶端精簡併主要關注視圖和查看邏輯,然後交換出不同的客戶端應該像換出任何其他組件一樣簡單。

在這個說明中,如果您將Silverlight用於您的客戶端,那麼您可以從Web運行它或作爲獨立應用程序運行,這意味着它們也是您想要使用WPF的幾個理由。

+0

@maple,我的商業邏輯是抽象出來的。我正在使用WCF/RIA服務。我的表示層是我正在嘗試重用的。它相當複雜(因爲這是最終用戶而不是內部業務應用程序)。 – Jordan 2011-06-13 17:15:59

+0

這很棒,但你仍然沒有解釋爲什麼你必須同時使用WPF和Silverlight。主要的問題是,您將有數百個不同的Kiosk應用程序在進行更改時需要部署,並且Silverlight會爲您解決這個問題。一個帶有一些小javascript的標準網頁足以託管XAP文件,而且這個XAP文件將始終是基於部署到IIS的最新版本。 (續...) – 2011-06-13 17:30:18

+0

Silverlight無法擴展的地方,您可以使用棱鏡來填補空白。 http://msdn.microsoft.com/en-us/magazine/dd943055.aspx。此框架有助於解決Silverlight技術的空白。 – 2011-06-13 17:32:36

0

我有完全一樣的要求。我的解決方案使用WPF在Web瀏覽器控件中託管Silverlight。它們之間的通信是使用WPF託管的WCF服務在一個很好的獨立包中設置的。您可以爲WPF組件設置ClickOnce以簡化更新。我利用WPF在客戶端機器上擴展Silverlight(無需提升信任度),通過公開WCF服務以消耗SL(例如GetComputerName,...)。唯一的問題是您使用的WCF RIA服務無法在IIS之外託管。希望它有幫助

相關問題