本文將部署一個wcf+silverlight簡單實例,以下是詳細步驟:
(環境:服務端win2003,iis6.0,asp.net4.0;客戶端winXP,iis5.1,vs2010,silverlight4.0)
1.新建一個解決方案,方案中新建一個網站(選擇wcf服務)
再新建一個wcf服務庫
此時解決方案結構如下:
2.刪除WCFService.App_code自帶的IService.cs,Service.cs,然后添加引用我們自定義的wcf服務庫WcfServiceLibrary1
打開WCFService宿主網站的Service.svc文件,內容如下:
<%@ ServiceHost Language="C#" Debug="true" Service="Service" CodeBehind="~/App_Code/Service.cs" %>
由於我們刪除了vs自動生成的文件,改用我們自定義的wcf服務庫文件,所以將以上代碼修改為:(刪除掉CodeBehind,修改Service為我們自定義的wcf服務庫中,默認生成的Service1服務契約)
<%@ ServiceHost Language="C#" Debug="true" Service="WcfServiceLibrary1.Service1" %>
接下來設置一下我們的WCFService宿主的配置文件Web.config,可以使用編輯WCF配置工具,方便我們的設置
打開設置工具,首先新建一個服務
找到我們添加引用過來的wcf服務(宿主網站引用的服務.dll一般在Bin文件夾下,如果你添加后沒有看到它,試着重新生成以下解決方案)
選擇我們的模式,由於本例后面將用silverlight程序和wcf通信,宿主也將選擇iis,所以選擇基於http的模式
終結點可以選擇不填
最終獲得配置如下:
保存設置,我們將會得到自定生成后的Web.config
當然,為了部署在我們iis之上,必須設置固定一下宿主網站的端口號,並且修改我們的虛擬路徑
查看我們是否創建服務成功,可以選擇在瀏覽器中查看
創建成功,我們將得到一個返回頁面(記下這個服務的路徑,它將在本例后面添加服務時使用到,本例中的路徑:http://localhost:9090/Service.svc)
3.由於我們獨立出了wcf服務,將會遇到跨域問題,所以要添加一個跨域文件clientaccesspolicy.xml在宿主網站的根目錄下(由於我們將用silverlight程序來通信,所以只需要添加一個clientaccesspolicy.xml跨域文件)
clientaccesspolicy.xml內容如下:
<?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>
4.在我們自定義的wcf服務庫中,簡單寫一個wcf服務契約來完成我們的例子吧
IService1.cs:
namespace WcfServiceLibrary1 { // 注意: 使用“重構”菜單上的“重命名”命令,可以同時更改代碼和配置文件中的接口名“IService1”。 [ServiceContract] public interface IService1 { [OperationContract] string SayHello(); // TODO: 在此添加您的服務操作 } }
Service1.cs:
namespace WcfServiceLibrary1 { // 注意: 使用“重構”菜單上的“重命名”命令,可以同時更改代碼和配置文件中的類名“Service1”。 public class Service1 : IService1 { #region IService1 成員 public string SayHello() { return "Hello WCF"; } #endregion } }
5.接下來我們新建一個silverlight程序,用來和wcf服務通信吧
在解決方案中,新建一個silverlight程序
由於本例中,我們將分開獨立的發布部署wcf服務和silverlight演示網站,所以注意選擇新建的silverlight時,要新建一個Web項目安置,而不要選擇安置在wcf服務的寄宿網站中(無需啟用WCF RIA服務)
此時得到解決方案結構如下:
6.然后我們來完善我們的silverlight程序來完成和wcf服務的通信吧
首先在silverlight程序添加服務引用
這里的地址我們填寫前面測試wcf服務布置成功與否時,返回成功頁面上的地址,本例如下:
確定添加后,得到解決方案結構如下:
vs2010為我們自動生成了服務引用ServiceReference1,和配置文件ServiceReferences.ClientConfig(如果你足夠仔細,一定發現了我們在地址中使用了localhost的本機地址,本機的地址滿足我們在本機開發環境下正常調試即可,而我們將會在稍后部署到服務端服務器的iis上時,再做修改)
簡單的設置一下本例的展示界面吧:
一個button,一個textblock,簡約卻也清楚不是嘛,在button1的點擊事件中,添加代碼如下:
private void button1_Click(object sender, RoutedEventArgs e) { //綁定模式為基本http模式 Binding binding = new BasicHttpBinding(); //終結點地址 EndpointAddress endPoint = new EndpointAddress("http://localhost:9090/Service.svc"); //設置終結點,包括模式和地址 ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(binding, endPoint); //設置調用異步調用完成返回成功的執行方法 client.SayHelloCompleted += new EventHandler<ServiceReference1.SayHelloCompletedEventArgs>(client_SayHelloCompleted); //異步調用 client.SayHelloAsync(); } void client_SayHelloCompleted(object sender, ServiceReference1.SayHelloCompletedEventArgs e) { this.textBlock1.Text = e.Result; }
點擊button1,我們將發出和wcf服務的通信,等待wcf服務返回的結果,演示在textblock1上,重新生成一下解決方案,F5運行一下,看看效果吧:
仔細的你一定會發現,同時起來的還有一個WCF服務主機的窗口,如果WCF服務通信有問題的話,你可以在這里查看異常
7.OK,開心的看着我們的wcf+silverlight的程序已經調試成功了,覺得這還是挺簡單的,但是別忘了,我們的項目還沒有部署呢,離最后的上線還有一個重要的步驟,那就是在服務器上的部署
首先把我們的解決方案中的兩個Web項目發布一下(一個wcf服務宿主Web,一個silverlight寄宿Web),因為winXP環境下,只能安裝iis5.1(iis5.1 只能發布一個網站),所以我們每次只能發布一個,step by step吧
每次發布生成的文件(本例采用文件系統發布在本機的D:\www下),我們分別保存下來,然后放置到服務器上
ok,來看一下我們的服務端的iis配置吧
ServiceTest:安置我們的wcf服務宿主網站,注意端口選擇我們之前約定好固定的9090
asp.net版本4.0
SilverlightTest:安置我們的Silverlight寄宿網站,同樣的設置asp.net版本4.0(iis6.0中,需設置端口,本例的Silverlight寄宿網站端口設8080,服務端ip為192.168.1.131,局域網內訪問)
ok,在客戶端訪問一下我們的成果吧
首先輸入wcf服務的地址,查看返回結果
You have created a service!看來我們的wcf服務布置成功了,接着我們訪問一下演示用的silverlight吧
如果rp不走運的話,會發現有返回的異常,內容如下:
消息: Unhandled Error in Silverlight Application 操作過程中出現異常,結果無效。有關異常的詳細信息,請查看 InnerException。 位於 System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary() 位於 SilverlightApplication1.ServiceReference1.SayHelloCompletedEventArgs.get_Result() 位於 SilverlightApplication1.MainPage.client_SayHelloCompleted(Object sender, SayHelloCompletedEventArgs e) 位於 SilverlightApplication1.ServiceReference1.Service1Client.OnSayHelloCompleted(Object state)
分析一下說明,問題出在silverlight調用wcf服務時出錯,但是你如果返回正常,那一定是因為你本機的9090端口wcf沒關吧
問題出在silverlight調用wcf時,使用的服務地址當時我們用的是localhost,之前由於是在本機調試,服務端客戶端在同一台主機,他們的地址都是localhost,所以問題沒有出現,但是silverlight程序是需要客戶端下載到本地去執行的,當我們試圖訪問放置在真正服務端上的服務時,當然只能去找本機端口的wcf服務,而我們真正的想法是讓它去找服務器端口下的wcf服務
知道了問題所在,開始修改一下我們的silverlight程序吧
首先修改一下我們的silverlight程序引用的wcf服務的地址吧:
這次我們使用服務端的ip地址(本例中服務器ip為192.168.1.131)
同時修改一下我們button1按鍵事件:
private void button1_Click(object sender, RoutedEventArgs e) { //綁定模式為基本http模式 Binding binding = new BasicHttpBinding(); //終結點地址 //EndpointAddress endPoint = new EndpointAddress("http://localhost:9090/Service.svc"); EndpointAddress endPoint = new EndpointAddress("http://192.168.1.131:9090/Service.svc"); //設置終結點,包括模式和地址 ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(binding, endPoint); //設置調用異步調用完成返回成功的執行方法 client.SayHelloCompleted += new EventHandler<ServiceReference1.SayHelloCompletedEventArgs>(client_SayHelloCompleted); //異步調用 client.SayHelloAsync(); }
這樣silverlight程序在調用wcf服務時,就會去真正的服務端查找了(可以先把localhost地址注釋掉,因為我們本機客戶端的ip地址是不可以和服務端的ip相同的,我們還是會用到localhost來調試程序的)
ok,重新生成一下我們的解決方案,將修改過后的silverlight寄宿網站放到服務器上,再次訪問一下,問題解決,結果如下: