前言
上一篇的學習中碰到一個問題,用地址http://localhost:8080/mex 訪問元數據的時候一直提示400 bad request 錯誤,因為時間太晚了,查了好幾遍代碼,也沒有發現問題。剛剛又試驗了一下,解決方案分兩步
①用管理員方式運行vs,
② 將
<serviceMetadata httpGetEnabled="true" />
改成
<serviceMetadata httpGetEnabled="true" httpGetUrl="mex"/>
也就是 我們給他指定一個httpGetUrl,至於為什么這么做,是參考的serviceMetadata。
最后,要說關於mex endpoint的作用,通俗的來講就是只要客戶端訪問這個地址,他就可以知道關於這個WCF服務一些說明介紹。
第四集 WCF service implementing multiple service contracts
假設有這樣的場景,有個公司需要通過http 給外網提供一個公共服務,同時又需要通過tcp協議給公司防火牆內的內容用戶提供另一個服務,並且,還不想寫多個WCF服務。
所以這一集主要兩點,
- 在一個WCF服務中實現兩個contract
- 通過endpoint配置對外界提供這兩個服務 contract
關於如何搭建一個WCF服務,可以參考上一篇,這集只講一些其他的重點。
首先是新建一個類庫,然后添加一個WCF服務項,取名CompanyService。然后打開ICompanyService.cs,刪除里面原先的ICompanyService接口,添加如下兩個接口。
[ServiceContract] public interface ICompanyPublicService { [OperationContract] string GetPublicInformation(); } [ServiceContract] public interface ICompanyConfidentialService { [OperationContract] string GetConfidentialInformation(); }
解釋一下,我們定義了兩個合約,一個是公用PublicService ,一個是機密的ConfidentialService,里面分別有各自的GetInformation方法。
然后打開CompanyService.cs 文件,修改里面的CompanyService 類為如下內容:
public class CompanyService : ICompanyPublicService, ICompanyConfidentialService { public string GetConfidentialInformation() { return "這是機密內網的服務"; } public string GetPublicInformation() { return "這是外網的公共服務"; } }
解釋一下,我們的服務名稱依舊沒有改變,還是CompanyService,但是他實現了上面定義的兩個有ServiceContract特性的契約接口。
類定義完畢,然后是配置文件部分。關於整體的配置文件,請看上一篇,下面是完整代碼。
<system.serviceModel> <services> <service name="Part4.CompanyService" behaviorConfiguration="mexBehavior"> <endpoint address="CompanyService" binding="basicHttpBinding" contract="Part4.ICompanyPublicService"></endpoint> <endpoint address="CompanyService" binding="netTcpBinding" contract="Part4.ICompanyConfidentialService"></endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"></endpoint> <host> <baseAddresses> <add baseAddress="http://localhost:8080/"/> <add baseAddress="net.tcp://localhost:8090/"/> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors > <behavior name="mexBehavior"> <serviceMetadata httpGetEnabled="true" httpGetUrl="mex"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
因為自己也是初學者,所以在手寫的時候還是會碰到一些問題。比如 service節點 的name 屬性,表示服務的名字,內容是實現接口的帶命名空間的類名;而endpoint里面的contract的名字是定義的時候的帶命名空間的接口名字。同時,為了讓客戶端可以通過添加服務引用的方式來調用,不要忘記了mex endpoint ,以及serviceMetadata元素。
然后新建一個控制台程序,用來托管這個服務。關於如何創建,依舊查看上一篇。啟動服務。
完成之后編寫客戶端代碼來調用。
我們新建一個Asp.net 的空網站,然后添加服務引用:
可以看到,CompanyService里面包含了兩個服務。點擊確定,查看一下網站的web.config 文件。
<system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_ICompanyPublicService" /> </basicHttpBinding> <netTcpBinding> <binding name="NetTcpBinding_ICompanyConfidentialService" /> </netTcpBinding> </bindings> <client> <endpoint address="http://localhost:8080/CompanyService" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ICompanyPublicService" contract="CompanyService.ICompanyPublicService" name="BasicHttpBinding_ICompanyPublicService" /> <endpoint address="net.tcp://localhost:8090/CompanyService" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICompanyConfidentialService" contract="CompanyService.ICompanyConfidentialService" name="NetTcpBinding_ICompanyConfidentialService"> <identity> <userPrincipalName value="LOUSAIBIAO\Sheldon" /> </identity> </endpoint> </client> </system.serviceModel>
這些都是自動生成的代碼,用來配合我們客戶端的調用。
然后給網站添加一個新頁面,拖兩個button ,兩個label (你們都懂得)大致就這個效果。
編寫兩個button的點擊事件。
protected void Button1_Click(object sender, EventArgs e) { //因為有多個endpoint ,所以要指定名字 var client = new CompanyPublicServiceClient("BasicHttpBinding_ICompanyPublicService"); Label1.Text = client.GetPublicInformation(); } protected void Button2_Click(object sender, EventArgs e) { var client = new CompanyConfidentialServiceClient("NetTcpBinding_ICompanyConfidentialService"); Label2.Text = client.GetConfidentialInformation(); }
調試運行該網站,並點擊按鈕,得到如下結果。
至此,實現方面的介紹完畢,有一點要說明的,因為我們是在vs上本機調試,說以,兩個button都能獲取的數據,但如果是過防火牆的外網來訪問,在沒有給控制面板中的防火牆添加額外的入站出站規則的時候,GetConfidential 方法是無效的。
介紹完畢,Thank you。