詳解WCF服務(wù)中的svc文件
一、新建一個WCF服務(wù)應(yīng)用程序:
文件->新建->項目:選擇WCF下面的WCF服務(wù)應(yīng)用程序
二、分析WcfSvcDemo項目,該項目的結(jié)構(gòu)如下:
在該項目中,會默認(rèn)生成一個IService1.cs的文件和Service1.svc文件。Service1.svc文件封裝的就是提供給客戶端的服務(wù)引用。
首先查看IService1.cs文件,從名字上面就可以看出這是一個接口文件,里面定義了一個接口IService1,接口上面使用了ServiceContract,意思是把這個接口聲明為服務(wù)契約,服務(wù)契約是對客戶端而言的,就是這個接口可以暴露出來讓客戶端可以看見。接口里面定義了兩個方法,每個方法上面都使用了[OperationContract],意思是把這兩個方法聲明為操作契約。只有把接口里面的方法聲明為操作契約,在客戶端里面才可以看到相應(yīng)的方法,否則在客戶端里面看不到在接口里面定義的方法。
在來看Service.svc文件,可以看到下面有一個Service.svc.cs文件,這個文件里面定義了一個繼承IService1接口的類Service1,并實(shí)現(xiàn)了IService1接口里面的方法。
刪除Service.svc.cs文件,可以查看Service.svc文件,該文件里面就一行代碼;
<%@ ServiceHost Language="C#" Debug="true" Service="WcfSvcDemo.Service1" CodeBehind="Service1.svc.cs" %>
這里面有兩個重要的參數(shù):Service和CodeBehind。Service是屬性值是WCF的服務(wù)實(shí)現(xiàn)類的完全限定名。CodeBehind是服務(wù)實(shí)現(xiàn)類所在的文件名。在運(yùn)行的時候,宿主程序從svc文件中的Service屬性得到WCF服務(wù)的完全限定名,然后從配置文件中找到同名的servicce,進(jìn)而找到所有的EndPoint,并根據(jù)其屬性進(jìn)行實(shí)例化。
配置文件中的Service名字必須是Service類名的完全限定名(即Namespace.classname),EndPoint的Contract必須是Service接口的完全限定名。否則,程序就無法從程序集中找到相應(yīng)的類進(jìn)行加載。
注意:如果要修改接口實(shí)現(xiàn)類的名稱,必須使用“重構(gòu)”的方式進(jìn)行修改,因?yàn)橹挥欣?ldquo;重構(gòu)”的方式修改Servie類名的時候,.svc文件里面Service的屬性值才會被修改,利用其它方式修改類名,.svc文件里面Service的屬性值會保留原值,這樣在運(yùn)行的時候,根據(jù)svc里面Service的屬性值查找不到相應(yīng)的類,程序就會報錯。
svc文件里面還有一個重要的參數(shù):ServiceHostFactory。ServiceHostFactory旨在解決從IIS或WAS中訪問自定義ServiceHost的問題。因?yàn)閺腟erviceHost派生的自定義宿主是動態(tài)配置的并且可能為各種類型,所以宿主環(huán)境從不會直接將其實(shí)例化。相反,WCF使用工廠模式提供宿主環(huán)境和服務(wù)的具體類型之間的間接層。除非進(jìn)行通知,否則它使用返回ServiceHost的實(shí)例的ServiceHostFactory的默認(rèn)實(shí)現(xiàn)。(在新建的svc文件中默認(rèn)實(shí)現(xiàn)就是CodeBehind屬性的值)。但也可以通過在@ServiceHost指令中指定工廠實(shí)現(xiàn)的CLR類型名稱來提供自己的工廠(用于返回派生宿主)。
下面是用于返回派生的ServiceHost的自定義ServiceHostFactory:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Activation; namespace Public.CustomService { public class CustomServiceHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) { CustomServiceHost customServiceHost = new CustomServiceHost(serviceType, baseAddresses); return customServiceHost; } } }
其中CustomServiceHost是自定義的繼承自ServiceHost的類,用于讀取配置文件的配置,CustomServiceHost類的定義如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Activation; namespace Public.CustomService { public class CustomServiceHost :ServiceHost { public CustomServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { //加載Web.config的配置 log4net.Config.XmlConfigurator.Configure(); } protected override void ApplyConfiguration() { base.ApplyConfiguration(); } } }
若要使用此工廠,而不使用默認(rèn)工廠,則應(yīng)該在@ServiceHost指令中提供相應(yīng)的類型名稱:
<%@ ServiceHost Service="CustomSvcDemo.DatabaseService" Factory="Public.CustomService.CustomServiceHostFactory" %>
其中Service是實(shí)現(xiàn)類的完全限定名,F(xiàn)actory是自定義ServiceHostFactory的完全限定名,Public是一個dll文件。
若要使用此工廠,而不使用默認(rèn)工廠,則應(yīng)該在@ServiceHost指令中提供相應(yīng)的類型名稱:
盡管對于從CreateServiceHost返回的ServiceHost可以執(zhí)行什么操作沒有技術(shù)限制,但建議您盡可能使工廠實(shí)現(xiàn)簡單化。如果有大量的自定義邏輯,最好將這些邏輯放入宿主內(nèi)而不是工廠內(nèi),以便可以重用它們。
應(yīng)在這里提及另一個承載API的層。WCF還具有ServiceHostBase和ServiceHostFactoryBase,可從中分別派生ServiceHost和ServiceHostFactory。對于您必須通過自己的自定義創(chuàng)建來交換元數(shù)據(jù)系統(tǒng)的大型組件的更高級方案,存在上述這些特性。
下面通過兩個具體的示例程序分別實(shí)現(xiàn)上面描述的默認(rèn)工廠和自定義工廠。
三、使用默認(rèn)工廠方式
1、刪除新建項目時自動創(chuàng)建的IService1.cs和Service1.svc文件,然后添加一個svc文件,在項目上面右鍵->添加->新建項:
2、在新建項里面選擇web里面的WCF服務(wù),命名為MyService:
3、點(diǎn)“添加”,除了創(chuàng)建MyService.svc文件以外,還會自動創(chuàng)建一個名為IMyService.cs的接口文件,MyService.svc.cs里面的MyService默認(rèn)實(shí)現(xiàn)IMyService接口.
刪除IMyService接口里面自動生成的方法,添加一個GetCurrentTime的方法,用來返回當(dāng)前的時間,IMyService接口定義如下:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace WcfSvcDemo { // 注意: 使用“重構(gòu)”菜單上的“重命名”命令,可以同時更改代碼和配置文件中的接口名“IMyService”。 [ServiceContract] public interface IMyService { /// <summary> /// 獲取當(dāng)前時間 /// </summary> /// <returns></returns> [OperationContract] DateTime GetCurrentTime(); } }
4、MyService.svc.cs里面的MyService類實(shí)現(xiàn)IMyService接口,MyService類定義如下:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace WcfSvcDemo { // 注意: 使用“重構(gòu)”菜單上的“重命名”命令,可以同時更改代碼、svc 和配置文件中的類名“MyService”。 // 注意: 為了啟動 WCF 測試客戶端以測試此服務(wù),請在解決方案資源管理器中選擇 MyService.svc 或 MyService.svc.cs,然后開始調(diào)試。 public class MyService : IMyService { /// <summary> /// 返回當(dāng)前時間 /// </summary> /// <returns></returns> public DateTime GetCurrentTime() { return DateTime.Now; } } }
5、修改配置文件,增加service、binding等節(jié)點(diǎn),修改后的配置文件如下:
<?xml version="1.0"?> <configuration> <appSettings/> <system.web> <compilation debug="true" targetFramework="4.0"/> <httpRuntime/> </system.web> <system.serviceModel> <services> <service behaviorConfiguration="metadataBehavior" name="WcfSvcDemo.MyService"> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="Contract" name="MyService" contract="WcfSvcDemo.IMyService"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="metadataBehavior"> <!-- 為避免泄漏元數(shù)據(jù)信息,請在部署前將以下值設(shè)置為 false --> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/> <!-- 要接收故障異常詳細(xì)信息以進(jìn)行調(diào)試,請將以下值設(shè)置為 true。在部署前設(shè)置為 false 以避免泄漏異常信息 --> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> <bindings> <basicHttpBinding> <binding name="Contract" closeTimeout="00:00:05" openTimeout="00:00:05" receiveTimeout="11:00:00" sendTimeout="11:00:00" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" transferMode="Buffered"> <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/> </binding> </basicHttpBinding> </bindings> <protocolMapping> <add binding="basicHttpsBinding" scheme="https"/> </protocolMapping> <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> <!-- 若要在調(diào)試過程中瀏覽 Web 應(yīng)用程序根目錄,請將下面的值設(shè)置為 True。 在部署之前將該值設(shè)置為 False 可避免泄露 Web 應(yīng)用程序文件夾信息。 --> <directoryBrowse enabled="true"/> </system.webServer> </configuration>
主要是修改service節(jié)點(diǎn)里面的name是服務(wù)實(shí)現(xiàn)類的完全限定名,contract是服務(wù)接口的完全限定名。
6、把WCF服務(wù)部署到IIS上面
在IIS上面網(wǎng)站->添加網(wǎng)站:
配置網(wǎng)站名稱、路徑、IP地址和端口:
網(wǎng)站配置完成以后,瀏覽.svc文件,驗(yàn)證網(wǎng)站是否配置成功,如出現(xiàn)下面的截圖,說明網(wǎng)站配置成功:
7、創(chuàng)建代理類
客戶端引用WCF的時候一般是靜態(tài)引用,直接添加服務(wù)引用,這種方式如果IP地址和端口號變了,需要用代碼重新編譯然后在部署,這樣不方便。這里使用svcutil代理類的方式進(jìn)行客戶端的調(diào)用。
使用svcutil生成代理類:
新建一個項目,選擇類庫項目,把剛才生成的類文件添加到類庫項目中,項目結(jié)構(gòu)如下:
在類庫項目中新添加一個類,命名為:MyServiceProxy,使用這個類來調(diào)用代理類,MyServiceProxy類的定義如下:
using Public.ConfigBinding; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.ServiceModel; using System.Text; using System.Threading.Tasks; namespace MyProxyService { public class MyServiceProxy { private static MyServiceClient _databaseService; private static MyServiceClient DatabaseService { get { if (_databaseService == null) { string sApServer1 = ConfigurationManager.AppSettings["ApServer1"]; if (sApServer1 == null) { _databaseService = new MyServiceClient(); } else { EndpointAddress endPointAddr = new EndpointAddress(string.Format("{0}/MyService.svc", sApServer1)); _databaseService = new MyServiceClient(HttpBinding.BasicHttpBinding, endPointAddr); } } if (_databaseService.State == CommunicationState.Faulted) { string sApServer2 = ConfigurationManager.AppSettings["ApServer2"]; if (sApServer2 == null) { _databaseService = new MyServiceClient(); } else { EndpointAddress endPointAddr = new EndpointAddress(string.Format("{0}/MyService.svc", sApServer2)); _databaseService = new MyServiceClient(HttpBinding.BasicHttpBinding, endPointAddr); } } return _databaseService; } } /// <summary> /// 返回當(dāng)前時間 /// </summary> /// <returns></returns> public static DateTime GetCurrentTime() { return DatabaseService.GetCurrentTime(); } } }
ApServer1和ApServer2是在配置文件中配置的IP地址和端口號,這樣如果IP地址和端口號變了,只需要修改配置文件就可以。
GetCurrentTime()方法是調(diào)用的代理類里面的方法,把該方法定義為靜態(tài)方法。
8、創(chuàng)建客戶端調(diào)用
在解決方案中,新建一個winform程序,界面上面只有一個button按鈕,點(diǎn)擊按鈕,彈出當(dāng)前時間。需要添加對MyProxyService.dll文件的引用,在配置文件中增加ApServer1和ApServer2兩個節(jié)點(diǎn),配置文件如下:
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings> <add key="ApServer1" value="http://127.0.0.1:8090"/> <add key="ApServer2" value="http://127.0.0.1:8090"/> </appSettings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration>
button按鈕事件代碼如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using MyProxyService; namespace WinformClient { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btn_CurrentTime_Click(object sender, EventArgs e) { DateTime dtNow = MyServiceProxy.GetCurrentTime(); MessageBox.Show("當(dāng)前時間:" + dtNow.ToString()); } } }
點(diǎn)擊按鈕后,運(yùn)行結(jié)果如下:
四、使用自定義工廠的方式
1、新添加一個WCF服務(wù),命名為CustomService,把默認(rèn)生成的CustomService.svc.cs文件刪掉,重新添加一個類:CustomService,該類繼承自生成的ICustomService接口,項目結(jié)構(gòu)如下:
修改CustomService.svc文件:
<%@ ServiceHost Service="WcfSvcDemo.CustomService" Factory="Public.CustomService.CustomServiceHostFactory" %>
CustomServiceHostFactory是在另外的Public.dll里面創(chuàng)建的工廠類,用來返回ServiceHost,Public.dll的項目結(jié)構(gòu)如下:
CustomServiceHost類繼承自ServiceHost類,代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Activation; namespace Public.CustomService { public class CustomServiceHost :ServiceHost { public CustomServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { //加載Web.config的配置 log4net.Config.XmlConfigurator.Configure(); } protected override void ApplyConfiguration() { base.ApplyConfiguration(); } } }
CustomServiceHostFactory是工廠類,繼承自ServiceHostFactory,用來返回ServiceHost,代碼如下;
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Activation; namespace Public.CustomService { public class CustomServiceHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) { CustomServiceHost customServiceHost = new CustomServiceHost(serviceType, baseAddresses); return customServiceHost; } } }
HttpBinding代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.ServiceModel; using System.Text; using System.Threading.Tasks; using System.Xml; namespace Public.ConfigBinding { public class HttpBinding { private static BasicHttpBinding _BasicHttpBinding; public static BasicHttpBinding BasicHttpBinding { get { if (_BasicHttpBinding == null) { _BasicHttpBinding = new BasicHttpBinding(); // 接收的訊息大小上限,默認(rèn)值為65,536字節(jié), // 目前設(shè)定1k * 512,如果資料量大于這個值,請?zhí)岢鲇懻?,ex:8000筆資料大概128k _BasicHttpBinding.MaxReceivedMessageSize = 400 * 8192 * 512; // 由于回傳String長度過長在反串行化時會出錯! // 所以放大最大字符串長度 _BasicHttpBinding.ReaderQuotas.MaxStringContentLength = 8192 * 1022; _BasicHttpBinding.ReaderQuotas.MaxArrayLength = 8192 * 1022; _BasicHttpBinding.SendTimeout = new TimeSpan(0, 5, 0); } return _BasicHttpBinding; } } } }
把CustomService.svc部署到IIS上面、創(chuàng)建代理類的方法、客戶端調(diào)用和默認(rèn)工廠里面的方法一樣,此處不在描述。
項目代碼下載路徑:下載地址
到此這篇關(guān)于WCF服務(wù)中svc文件詳解的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#中winform控制textbox輸入只能為數(shù)字的方法
這篇文章主要介紹了C#中winform控制textbox輸入只能為數(shù)字的方法,包括使用keyPress事件限制鍵盤輸入以及TextChanged事件限制粘貼等情況,來實(shí)現(xiàn)控制輸入為數(shù)字的功能,需要的朋友可以參考下2015-01-01c#實(shí)現(xiàn)從字符串?dāng)?shù)組中把數(shù)字的元素找出來
下面小編就為大家分享一篇c#實(shí)現(xiàn)從字符串?dāng)?shù)組中把數(shù)字的元素找出來的方法,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12C#開發(fā)Android百度地圖手機(jī)應(yīng)用程序(多地圖展示)
這篇文章主要介紹了C#開發(fā)Android百度地圖手機(jī)應(yīng)用程序(多地圖展示)的相關(guān)資料,需要的朋友可以參考下2016-02-02C# PC版微信消息監(jiān)聽自動回復(fù)的實(shí)現(xiàn)方法
這篇文章主要介紹了C# PC版微信消息監(jiān)聽自動回復(fù)的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05在C#中根據(jù)HardwareID獲取驅(qū)動程序信息的實(shí)現(xiàn)代碼
這篇文章主要介紹了C#中根據(jù)HardwareID獲取驅(qū)動程序信息的實(shí)現(xiàn)代碼,需要的朋友可以參考下2016-12-12C# MVC模式中應(yīng)該怎樣區(qū)分應(yīng)用程序邏輯(Controller層)和業(yè)務(wù)邏輯(Model層)?
這篇文章主要介紹了C# MVC模式中應(yīng)該怎樣區(qū)分應(yīng)用程序邏輯(Controller層)和業(yè)務(wù)邏輯(Model層)?,這也小編做.NET項目時經(jīng)常思考和讓人混亂的一個問題,這篇文章寫的挺好,一下清晰了許多,需要的朋友可以參考下2015-06-06