在託管 Windows 服務中承載 WCF 服務及在客戶端中如何調用服務

開始前先貼出一張最終的項目結構圖:

1.創建新的 Visual Studio控制檯應用程序名爲項目服務

2.添加對下列程序集的引用:

(1)System.ServiceModel.dll

(2)System.ServiceProcess.dll

(3)System.Configuration.Install.dll

注:其中(1)(2)是編寫WCF程序必須的dll (3)是發佈Windows服務所需的dll

3.創建類庫Contracts(這是我測試起的嗎,你可自己起),並創建ICalculator接口用於編寫wcf契約程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace Contracts
{
   
       [ServiceContract(Name = "CalculatorService", Namespace = "http://www.artech.com/")]
       public interface ICalculator
        {
            [OperationContract]
            void Add(double x, double y);
     
            [OperationContract]
            double Subtract(double x, double y);
    
            [OperationContract]
            double Multiply(double x, double y);
    
            [OperationContract]
            double Divide(double x, double y);        
       } 
   }

4.創建Service類庫,用於編寫對鍥約的實現代碼,即wcf術語中的服務:

using Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace Services
{
    public class CalculatorService : ICalculator
    {
        public void Add(double x, double y)
        {
            double result= x + y;           
        }

        public double Divide(double x, double y)
        {
            return x - y;
        }

        public double Multiply(double x, double y)
        {
            return x * y;
        }

        public double Subtract(double x, double y)
        {
            return x / y;
        }
    }
}

好了,現在我們已經創建好了契約和服務的代碼,要讓wcf程序能夠run起來,能夠被遠程所調用,增需要我們的Windows服務模塊出場了,WindowsService模塊負責制定wcf程序的綁定、終結點等以及負責wcf的宿主。

5.創建Windows服務項目,在WindowsService類庫的app.config中添加如下配置(部分註釋見配置代碼):

<system.serviceModel>
    <services>
      <service behaviorConfiguration="CalculatorServiceBehavior" name="Services.CalculatorService">  
        <!--創建終結點,指定終結點的通信方式(這裏是TCP的方式),以及契約的路徑-->
        <endpoint address="" binding="netTcpBinding" bindingConfiguration="" contract="Contracts.ICalculator"></endpoint>
        <host>
          <baseAddresses>
            <!--指定wcf服務的請求路徑,該路徑在客戶端調用時使用-->
            <add baseAddress="net.tcp://127.0.0.1:9000/CalculatorService.svc"/>            
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <!--指定wcf服務元數據請求路徑-->
          <serviceMetadata httpGetEnabled="True" httpGetUrl="http://localhost:8000/ServiceModelSamples/service" />          
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" minFreeMemoryPercentageToActivateService="0" />
    <bindings>
      <netTcpBinding>
        <binding name="defaultBinding" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
          <security mode="None">
            <message clientCredentialType="None"/>
            <transport clientCredentialType="None"></transport>
          </security>
          <readerQuotas />
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>

6.創建CalculatorWindowsService.cs類,並繼承ServiceBase,重寫Onstart和OnStop方法,該類的作用是在Windows服務啓動時負責對wcf程序的宿主:

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;

namespace WindowsService
{
    public class CalculatorWindowsService : ServiceBase
    {
        ServiceHost host = new ServiceHost(typeof(Services.CalculatorService));

        public CalculatorWindowsService()
        {
            // Name the Windows Service
            ServiceName = "WCFWindowsService";
        }
        /// <summary>
        /// 應用程序的主入口點。
        /// </summary>
        public static void Main()
        {
            ServiceBase.Run(new CalculatorWindowsService());
        }

        protected override void OnStart(string[] args)
        {
            try
            {
                host.Open();
            }
            catch (Exception ex)
            {
                
            }
        }

        protected override void OnStop()
        {
            host.Close();
        }
    }
}

現在可以說是完事具備,只欠東風了,而這個東風就是安裝啓動Windows服務的程序,爲了能夠使用Installutil.exe對我們的服務進行安裝,需要在WindowsService下創建ProjectInstaller類:

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

namespace WindowsService
{
    // Provide the ProjectInstaller class which allows 
    // the service to be installed by the Installutil.exe tool
    [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 = "WCFWindowsService";
            Installers.Add(process);
            Installers.Add(service);
        }
    }
}

7.編寫用於安裝、卸載我們Windows服務的批處理文件:

安裝:

@echo off
set /p var=是否要安裝WCF服務(Y/N):
if "%var%" == "y" (goto install) else (goto batexit)

:install
copy C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe  InstallUtil.exe /Y
call InstallUtil.exe D:\vsWorkspace\WcfStudyCenter\WcfStudyCenter\WindowsService\bin\Debug\WindowsService.exe
call sc start "WCFWindowsService"
pause

:batexit
exit

注:運行bat時,記得以管理員方式運行

運行成功後的界面:

卸載:

@echo off
set /p var=是否要卸載 WCF服務(Y/N):
if "%var%" == "y" (goto uninstall) else (goto batexit)

:uninstall
call sc stop "WCFWindowsService"
call sc delete "WCFWindowsService"
pause

:batexit
exit

8.將我們的WindowsService安裝並啓動成功後,就可以在客戶端遠程調用我們的wcf程序了:

調用方式一:

創建自己的項目程序,右鍵引用--->添加服務引用---->在地址框輸入元數據地址

 

點擊確定vs就會替我們生成代理方法,直接引入命名空間調用就可以了。

個人覺得方式一在平時個人玩玩可以使用,但是在正式開發,比如說想要基於wcf搭建分佈系統、微服務等等不太適合,那就可那第二種調用方式。

調用方式二:

 生成Contracts類庫的dll,將Contracts.dll引入自己的客戶端程序中,基於ChannelFactory生成代理程序,以下是編寫的生成代理累的簡單工廠程序,只需要指定契約接口就行:

public class WcfServiceProxy<T>
 {
        public static T CreatServiceProxy()
        {
           var factory = new ChannelFactory<ICalculator>(new NetTcpBinding(), new EndpointAddress("net.tcp://127.0.0.1:9000/CalculatorService.svc"));                                  
           var proxy = factory.CreateChannel();
           return (T)proxy;                    
        }
 }

調用實例如下:

public static void Main() {                   
      var proxy = WcfServiceProxy<ICalculator>.CreatServiceProxy();
      using (proxy as IDisposable)
      {
          Console.WriteLine(proxy.Multiply(2,3));
      }
      Console.ReadKey();
            
}

調用方式三(推薦):

using Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading.Tasks;

namespace CSharpStudyCenter
{
    public class WcfClent : System.ServiceModel.ClientBase<ICalculator>, ICalculator
    {
        public WcfClent(Binding binding, EndpointAddress endpointAddress):base(binding,endpointAddress)
        {

        }
        public void Add(double x, double y)
        {
            base.Channel.Add(x,y);
        }

        public double Divide(double x, double y)
        {
           return base.Channel.Divide(x,y);
        }

        public double Multiply(double x, double y)
        {
            return base.Channel.Multiply(x,y);
        }

        public double Subtract(double x, double y)
        {
            return base.Channel.Subtract(x,y);
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章