詳解WCF服務(wù)中的svc文件
一、新建一個WCF服務(wù)應(yīng)用程序:
文件->新建->項目:選擇WCF下面的WCF服務(wù)應(yīng)用程序

二、分析WcfSvcDemo項目,該項目的結(jié)構(gòu)如下:

在該項目中,會默認生成一個IService1.cs的文件和Service1.svc文件。Service1.svc文件封裝的就是提供給客戶端的服務(wù)引用。
首先查看IService1.cs文件,從名字上面就可以看出這是一個接口文件,里面定義了一個接口IService1,接口上面使用了ServiceContract,意思是把這個接口聲明為服務(wù)契約,服務(wù)契約是對客戶端而言的,就是這個接口可以暴露出來讓客戶端可以看見。接口里面定義了兩個方法,每個方法上面都使用了[OperationContract],意思是把這兩個方法聲明為操作契約。只有把接口里面的方法聲明為操作契約,在客戶端里面才可以看到相應(yīng)的方法,否則在客戶端里面看不到在接口里面定義的方法。
在來看Service.svc文件,可以看到下面有一個Service.svc.cs文件,這個文件里面定義了一個繼承IService1接口的類Service1,并實現(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ù)實現(xiàn)類的完全限定名。CodeBehind是服務(wù)實現(xiàn)類所在的文件名。在運行的時候,宿主程序從svc文件中的Service屬性得到WCF服務(wù)的完全限定名,然后從配置文件中找到同名的servicce,進而找到所有的EndPoint,并根據(jù)其屬性進行實例化。
配置文件中的Service名字必須是Service類名的完全限定名(即Namespace.classname),EndPoint的Contract必須是Service接口的完全限定名。否則,程序就無法從程序集中找到相應(yīng)的類進行加載。
注意:如果要修改接口實現(xiàn)類的名稱,必須使用“重構(gòu)”的方式進行修改,因為只有利用“重構(gòu)”的方式修改Servie類名的時候,.svc文件里面Service的屬性值才會被修改,利用其它方式修改類名,.svc文件里面Service的屬性值會保留原值,這樣在運行的時候,根據(jù)svc里面Service的屬性值查找不到相應(yīng)的類,程序就會報錯。
svc文件里面還有一個重要的參數(shù):ServiceHostFactory。ServiceHostFactory旨在解決從IIS或WAS中訪問自定義ServiceHost的問題。因為從ServiceHost派生的自定義宿主是動態(tài)配置的并且可能為各種類型,所以宿主環(huán)境從不會直接將其實例化。相反,WCF使用工廠模式提供宿主環(huán)境和服務(wù)的具體類型之間的間接層。除非進行通知,否則它使用返回ServiceHost的實例的ServiceHostFactory的默認實現(xiàn)。(在新建的svc文件中默認實現(xiàn)就是CodeBehind屬性的值)。但也可以通過在@ServiceHost指令中指定工廠實現(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();
}
}
}若要使用此工廠,而不使用默認工廠,則應(yīng)該在@ServiceHost指令中提供相應(yīng)的類型名稱:
<%@ ServiceHost Service="CustomSvcDemo.DatabaseService" Factory="Public.CustomService.CustomServiceHostFactory" %>
其中Service是實現(xiàn)類的完全限定名,F(xiàn)actory是自定義ServiceHostFactory的完全限定名,Public是一個dll文件。
若要使用此工廠,而不使用默認工廠,則應(yīng)該在@ServiceHost指令中提供相應(yīng)的類型名稱:
盡管對于從CreateServiceHost返回的ServiceHost可以執(zhí)行什么操作沒有技術(shù)限制,但建議您盡可能使工廠實現(xiàn)簡單化。如果有大量的自定義邏輯,最好將這些邏輯放入宿主內(nèi)而不是工廠內(nèi),以便可以重用它們。
應(yīng)在這里提及另一個承載API的層。WCF還具有ServiceHostBase和ServiceHostFactoryBase,可從中分別派生ServiceHost和ServiceHostFactory。對于您必須通過自己的自定義創(chuàng)建來交換元數(shù)據(jù)系統(tǒng)的大型組件的更高級方案,存在上述這些特性。
下面通過兩個具體的示例程序分別實現(xiàn)上面描述的默認工廠和自定義工廠。
三、使用默認工廠方式
1、刪除新建項目時自動創(chuàng)建的IService1.cs和Service1.svc文件,然后添加一個svc文件,在項目上面右鍵->添加->新建項:

2、在新建項里面選擇web里面的WCF服務(wù),命名為MyService:

3、點“添加”,除了創(chuàng)建MyService.svc文件以外,還會自動創(chuàng)建一個名為IMyService.cs的接口文件,MyService.svc.cs里面的MyService默認實現(xiàn)IMyService接口.
刪除IMyService接口里面自動生成的方法,添加一個GetCurrentTime的方法,用來返回當前的時間,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>
/// 獲取當前時間
/// </summary>
/// <returns></returns>
[OperationContract]
DateTime GetCurrentTime();
}
}4、MyService.svc.cs里面的MyService類實現(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>
/// 返回當前時間
/// </summary>
/// <returns></returns>
public DateTime GetCurrentTime()
{
return DateTime.Now;
}
}
}5、修改配置文件,增加service、binding等節(jié)點,修改后的配置文件如下:
<?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"/>
<!-- 要接收故障異常詳細信息以進行調(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é)點里面的name是服務(wù)實現(xiàn)類的完全限定名,contract是服務(wù)接口的完全限定名。
6、把WCF服務(wù)部署到IIS上面
在IIS上面網(wǎng)站->添加網(wǎng)站:

配置網(wǎng)站名稱、路徑、IP地址和端口:

網(wǎng)站配置完成以后,瀏覽.svc文件,驗證網(wǎng)站是否配置成功,如出現(xiàn)下面的截圖,說明網(wǎng)站配置成功:

7、創(chuàng)建代理類
客戶端引用WCF的時候一般是靜態(tài)引用,直接添加服務(wù)引用,這種方式如果IP地址和端口號變了,需要用代碼重新編譯然后在部署,這樣不方便。這里使用svcutil代理類的方式進行客戶端的調(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>
/// 返回當前時間
/// </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按鈕,點擊按鈕,彈出當前時間。需要添加對MyProxyService.dll文件的引用,在配置文件中增加ApServer1和ApServer2兩個節(jié)點,配置文件如下:
<?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("當前時間:" + dtNow.ToString());
}
}
}點擊按鈕后,運行結(jié)果如下:

四、使用自定義工廠的方式
1、新添加一個WCF服務(wù),命名為CustomService,把默認生成的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();
// 接收的訊息大小上限,默認值為65,536字節(jié),
// 目前設(shè)定1k * 512,如果資料量大于這個值,請?zhí)岢鲇懻摚琫x: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)用和默認工廠里面的方法一樣,此處不在描述。
項目代碼下載路徑:下載地址
到此這篇關(guān)于WCF服務(wù)中svc文件詳解的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#中winform控制textbox輸入只能為數(shù)字的方法
這篇文章主要介紹了C#中winform控制textbox輸入只能為數(shù)字的方法,包括使用keyPress事件限制鍵盤輸入以及TextChanged事件限制粘貼等情況,來實現(xiàn)控制輸入為數(shù)字的功能,需要的朋友可以參考下2015-01-01
c#實現(xiàn)從字符串數(shù)組中把數(shù)字的元素找出來
下面小編就為大家分享一篇c#實現(xiàn)從字符串數(shù)組中把數(shù)字的元素找出來的方法,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
C#開發(fā)Android百度地圖手機應(yīng)用程序(多地圖展示)
這篇文章主要介紹了C#開發(fā)Android百度地圖手機應(yīng)用程序(多地圖展示)的相關(guān)資料,需要的朋友可以參考下2016-02-02
C# PC版微信消息監(jiān)聽自動回復(fù)的實現(xiàn)方法
這篇文章主要介紹了C# PC版微信消息監(jiān)聽自動回復(fù)的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
在C#中根據(jù)HardwareID獲取驅(qū)動程序信息的實現(xiàn)代碼
這篇文章主要介紹了C#中根據(jù)HardwareID獲取驅(qū)動程序信息的實現(xiàn)代碼,需要的朋友可以參考下2016-12-12
C# 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

