C# WCF服務入門


之前在公司用的服務端是wcf寫的,但是沒有深入研究,最近找工作,面試的時候好多人看到這個總提問,這里做個復習

就用微軟官方上的例子,搭一個簡單的wcf服務,分6步

1 定義服務協定也就是契約,其實就是定義一個服務接口,這玩意后邊是公開客戶端用的,然后也告訴后邊承載程序應該如何加載服務

   主要涉及兩個特性:一個是ServiceContract(接口的特性,定義這個是服務契約,里邊又一些設置參數可以設置一下),OperationContract設置接口的方法的,如果不設置,方法就不會唄公開

  這里是直接新建的wcf的服務程序,vs自動給生成了一個接口,就直接在這個里邊添加了幾個計算的接口函數了

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace GettingStartedLib
{

    // 注意: 使用“重構”菜單上的“重命名”命令,可以同時更改代碼和配置文件中的接口名“IService1”。
    //協定
    [ServiceContract(//CallbackContract =typeof(ICallBack),//雙工時的返回協定
        ConfigurationName = "Calculator",//配置文件重的服務名
        Name = "ICalculator",//webservice描述文件重的portType名
        Namespace ="http://SampleWcfTest",//webservice描述文件重的portType命名空間
        ProtectionLevel =System.Net.Security.ProtectionLevel.EncryptAndSign,//保護等級
        SessionMode =SessionMode.Allowed)]//設置會話的支持模式
    public interface ICalculator
    {

        [OperationContract]
        string GetData(int value);

        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);
        //定義方法的操作,帶了該特性才會被公布
        [OperationContract]
        double Add(double n1, double n2);
        [OperationContract]
        double Subtract(double n1, double n2);
        [OperationContract]
        double Multiply(double n1, double n2);
        [OperationContract]
        double Divide(double n1, double n2);

        // TODO: 在此添加您的服務操作
    }
    public interface ICallBack
    {
        [OperationContract(IsOneWay = true)]
        void Reply(string responseToGreeting);
    }

    // 使用下面示例中說明的數據約定將復合類型添加到服務操作。
    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}

2 實現上邊的接口,vs自動生成了svc文件和對應的svc.cs文件,直接雙擊就是對應的實現類了,吧接口實現就好了,這個svc文件右鍵用文本編輯器打開可以進行編輯,如果后邊用IIS加載的時候需要修改里邊的東西

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace GettingStartedLib
{
    // 注意: 使用“重構”菜單上的“重命名”命令,可以同時更改代碼、svc 和配置文件中的類名“Service1”。
    // 注意: 為了啟動 WCF 測試客戶端以測試此服務,請在解決方案資源管理器中選擇 Service1.svc 或 Service1.svc.cs,然后開始調試。
    public class Calculator : ICalculator
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }
        public double Add(double n1, double n2)
        {
            double result = n1 + n2;
            Console.WriteLine("Received Add({0},{1})", n1, n2);
            // Code added to write output to the console window.
            Console.WriteLine("Return: {0}", result);
            return result;
        }

        public double Subtract(double n1, double n2)
        {
            double result = n1 - n2;
            Console.WriteLine("Received Subtract({0},{1})", n1, n2);
            Console.WriteLine("Return: {0}", result);
            return result;
        }

        public double Multiply(double n1, double n2)
        {
            double result = n1 * n2;
            Console.WriteLine("Received Multiply({0},{1})", n1, n2);
            Console.WriteLine("Return: {0}", result);
            return result;
        }

        public double Divide(double n1, double n2)
        {
            double result = n1 / n2;
            Console.WriteLine("Received Divide({0},{1})", n1, n2);
            Console.WriteLine("Return: {0}", result);
            return result;
        }
    }
}

3 承載服務,承載服務有幾種方式,同時又設計到協議的綁定問題,

  綁定分類:BasicHttpBinding  最基礎的http綁定,
        NetTcpbingding  TCP的  

        NetNamePipeBinding  IPC,也就是進程間通信,沒用過。。

        WSHttpBinding  這個是特殊的http/Https協議 加了其他東西的

        NetMsmqBindiing,這個是消息隊列,我沒用過,這玩意好像需要額外裝微軟的消息隊列才可以用

  這里我基本就用wshttpbinding來實現,

  承載方式:1)用控制台程序,直接用servicehost來承載服務,自己構造終結點:

            //服務的地址
            Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/");
            //承載服務的宿主
            ServiceHost selfHost = new ServiceHost(typeof(Calculator), baseAddress);

            try
            {
                selfHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "Calculator");
                ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                smb.HttpGetEnabled = true;
                selfHost.Description.Behaviors.Add(smb);
                selfHost.Open();
                Console.WriteLine("The service is ready.");
                Console.WriteLine("input<exit> to terminate service.");
                Console.WriteLine();
                while ("exit" == Console.ReadLine())
                {
                    selfHost.Close();
                }
            }
            catch (CommunicationException ex)
            {
                Console.WriteLine(ex.Message);
                selfHost.Abort();
                Console.ReadLine();
            }

    2) 用IIS承載,這里又兩種方式,通過internet的方式 這個可以直接在vs中調試的,選中svc文件點調試會彈出一個wcf的客戶端測試程序,可以直接進行測試,但是這個客戶端不能測試異步,只能測同步

    這中方式主要是需要配置一個web.config文件,部署的話,直接在IIS添加網站服務程序,把生成的DLL和web.config放在一個目錄下應該跟這個調試是一樣的(這種方式IIS5 6 只支持HTTP)

    還可以通過WAS(進程激活服務,支持的協議比上邊多,這個就沒有深入研究了···)

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5.2" />
    <httpRuntime targetFramework="4.5.2"/>
  </system.web>
  <system.serviceModel>
    <services>
      <service name="GettingStartedLib.Calculator" behaviorConfiguration="MyServiceTypeBehaviors" >
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8001/"/>
          </baseAddresses>
        </host>
        <endpoint address="CalculatorService" binding="wsHttpBinding" contract="Calculator">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyServiceTypeBehaviors" >
          <!-- 將下列元素添加到服務行為配置中。 -->
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <system.webServer>
    <!--<modules runAllManagedModulesForAllRequests="true"/>-->
    <!--
        若要在調試過程中瀏覽 Web 應用程序根目錄,請將下面的值設置為 True。
        在部署之前將該值設置為 False 可避免泄露 Web 應用程序文件夾信息。
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

  3)通過windows服務程序承載,這個內部起始也是servicehost來實現,只不過是掛在windows服務程序上,需要自己實現一個windows服務,也就是繼承servicebase類,重寫onstart,在onstart中用servicehost加載服務,在stop中停止服務,同時需要配置文件就是程序的配置文件app.config記得生成到目錄下,配置終結點。服務類生成的程序需要安裝,還需要繼承install實現一個安裝類,把生成的服務程序安裝到windows系統服務去,然后就可以在服務中啟動服務,

這個安裝是在管理員權限下進入對應的.netframework目錄下運行installutil path(程序目錄) 這里用的是4.5 ,就是v4.0。。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GettingStartedLib;
using System.ServiceModel.Description;
using System.ServiceModel;
using System.ServiceProcess;
using System.Configuration.Install;
using System.ComponentModel;

namespace WcfConsole
{
    public class serviceCalss : ServiceBase
    {
        public ServiceHost serviceHost = null;
        public serviceCalss()
        {
            ServiceName = "WCFWindowsServiceSample";

        }
        protected override void OnStart(string[] args)
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
            }
            serviceHost = new ServiceHost(typeof(Calculator));

            serviceHost.Open();
        }

        protected override void OnStop()
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
                serviceHost = null;
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {

            ServiceBase.Run(new serviceCalss());

            //服務的地址
            Uri baseAddress = new Uri("http://localhost:8000/GettingStarted/");
            //承載服務的宿主
            ServiceHost selfHost = new ServiceHost(typeof(Calculator), baseAddress);

            //try
            //{
            //    selfHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "Calculator");
            //    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
            //    smb.HttpGetEnabled = true;
            //    selfHost.Description.Behaviors.Add(smb);
            //    selfHost.Open();
            //    Console.WriteLine("The service is ready.");
            //    Console.WriteLine("input<exit> to terminate service.");
            //    Console.WriteLine();
            //    while ("exit" == Console.ReadLine())
            //    {
            //        selfHost.Close();
            //    }
            //}
            //catch (CommunicationException ex)
            //{
            //    Console.WriteLine(ex.Message);
            //    selfHost.Abort();
            //    Console.ReadLine();
            //}
        }
    }

    [RunInstaller(true)]
    public class ProjectInstaller : Installer
    {
        private ServiceProcessInstaller process;
        private ServiceInstaller service;

        public ProjectInstaller()
        {
            process = new ServiceProcessInstaller();
            process.Account = ServiceAccount.LocalSystem;
            service = new ServiceInstaller();
            service.ServiceName = "WCFWindowsServiceSample";
            Installers.Add(process);
            Installers.Add(service);
        }
    }
}

對應的配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
  <system.serviceModel>
    <services>
      <!-- This section is optional with the new configuration model
           introduced in .NET Framework 4. -->
      <service name="GettingStartedLib.Calculator"
               behaviorConfiguration="CalculatorServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/"/>
          </baseAddresses>
        </host>
        <endpoint address=""
                  binding="wsHttpBinding"
                  contract="Calculator" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="False"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

4 服務端承載好了,就可以用客戶端調用服務了,又兩種方式

  客戶端直接引用已經運行的服務,vs會自動生成一個對應的client類,里邊又設置好的服務路徑和接口之類的,也可以自己指定路徑,只用他的函數,記得close

           // CalculatorClient client = new CalculatorClient();
            var client = myChannelFactory.CreateChannel();


            double value1 = 100.00D;
            double value2 = 15.99D;
            double result = client.Add(value1, value2);
            Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

  也可以用ChannelFactory<TChannel>類來構造一個client,這種模式是引用服務的契約接口,

     var myBinding = new WSHttpBinding();
            EndpointAddress myEndpoint = new EndpointAddress("http://localhost:8000/GettingStarted/");
            //EndpointAddress myEndpoint = new EndpointAddress("http://localhost:8000/"); 
            ChannelFactory<ICalculator> myChannelFactory = new ChannelFactory<ICalculator>(myBinding, myEndpoint);

  這里邊都可以用配置文件來設置終結點,也就是綁定類型和地址,配置方式與服務端類似

5,6就是配置和調用,這里就不說了

這里只是簡單的wcf實例,

實際還有內容沒有涉及:

1 不同的綁定類型,怎么選擇,網上有個圖是判斷什么情況選擇對應的綁定類型,其實就是選擇協議

2 加密,因為之間的程序用的是basichttpbingding就是就是基本的http綁定,客戶端沒用引用服務端,服務端以web服務的形式公開服務,客戶端直接以http請求的形式來與服務端通信,這樣客戶端cs和bs可以公用一個服務端,但是沒有加密,傳輸的內容是完全公開的··講道理web服務這玩意本來就是發過去給人看的·公開應該也沒啥好像····,面試的時候問到這個問題直接懵逼了···這里暫時沒寫 ··這玩意好像挺麻煩的···

3 這里在4.5的環境下編寫的,服務公開以后會自動生成對應的異步執行方法,與之前的方式不同,之前是老式的beginxxx的異步方式,返回一個Iasyncresult的結果,這里是4.5的async/await的形式來執行異步操作

4 wcf服務是可以兼容asp.net ,也可以返回json格式的對象··這個可以通過設置方法的操作特性可以設置

5 wcf服務支持雙工,這個就很流弊了,不過講道理tcp這種本身就支持雙工,沒具體研究

6 在雙工模式下支持回調,這個意思好像是客戶端請求完成再出發一個回調服務么··· 沒研究···

。。。。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM