C#.NET Windows服務承載WCF

 

Windows服務的製作、安裝可以參考這篇:

C#.NET 操作Windows服務(安裝、卸載) – runliuv – 部落格園 (cnblogs.com)

本篇會在這個解決方案基礎上,繼續修改。

 

一、製作WCF

我們在原有解決方案上添加一個「WCF 服務庫」,為名「WcfYeah」。

在WcfYeah中額外引用System.ServiceModel.Web.dll程式集。

修改IService1.cs:

using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace WcfYeah
{
    // 注意: 使用「重構」菜單上的「重命名」命令,可以同時更改程式碼和配置文件中的介面名「IService1」。
    [ServiceContract]
    public interface IService1
    {        
        [OperationContract]
        [WebInvoke(ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
        CompositeType geta(CompositeType composite);
    }

    // 使用下面示例中說明的數據約定將複合類型添加到服務操作。
    // 可以將 XSD 文件添加到項目中。在生成項目後,可以通過命名空間「WcfYeah.ContractType」直接使用其中定義的數據類型。
    [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; }
        }
    }
}

修改Service1.cs:

using System;
using System.ServiceModel;

namespace WcfYeah
{
    // 調整 ServiceBehavior,使其支援並發
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall, UseSynchronizationContext = false)]
    public class Service1 : IService1
    {
        public CompositeType geta(CompositeType composite)
        {
            CompositeType myret = new CompositeType();
            try
            {
                if(composite==null)
                    myret.StringValue = "[0]輸入實體為空:" + DateTime.Now.ToString();
                else
                    myret.StringValue = "[1]輸入實體不為空:" + DateTime.Now.ToString();
            }
            catch (Exception ex)
            {
                myret.StringValue = "發生異常:" + ex.Message;                 
            }
            return myret;
        }

    }
}

增加一個WCFServer.cs:

using System.Net;
using System.ServiceModel.Web;
using System.Threading;

namespace WcfYeah
{
    public class WCFServer
    {
        public WebServiceHost host = null;

        public WCFServer()
        {
            #region 優化調整
            //對外連接數,根據實際情況加大
            if (ServicePointManager.DefaultConnectionLimit < 100)
                System.Net.ServicePointManager.DefaultConnectionLimit = 100;

            int workerThreads;//工作執行緒數
            int completePortsThreads; //非同步I/O 執行緒數
            ThreadPool.GetMinThreads(out workerThreads, out completePortsThreads);

            int blogCnt = 100;
            if (workerThreads < blogCnt)
            {
                // MinThreads 值不要超過 (max_thread /2  ),否則會不生效。要不然就同時加大max_thread
                ThreadPool.SetMinThreads(blogCnt, blogCnt);
            }
            #endregion
             
            //注意:這裡是實現類,不是介面,否則會報:ServiceHost 僅支援類服務類型。
            host = new WebServiceHost( typeof(WcfYeah.Service1));
        }


        public void Start()
        {
            host.Open();
        }

        public void Close()
        {
            if (host != null)
            {
                host.Close();
            }
        }
    }
}

 

 

二、在Windows服務中調用WCF

在windows服務庫中引用WcfYeah這個項目,再引用System.ServiceModel.dll 和System.ServiceModel.Web.dll程式集。

修改windows服務的OnStart和OnStop方法,完整內容如下:

using CommonUtils;
using System;
using System.ServiceModel;
using System.ServiceProcess;
using WcfYeah;

namespace ADemoWinSvc
{
    public partial class Service1 : ServiceBase
    {
        WCFServer aw = null;
        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            try
            {
                if (aw == null)
                {
                    aw = new WCFServer();
                }
                if (aw.host.State == CommunicationState.Opening || aw.host.State == CommunicationState.Opened)
                {
                    GLog.WLog("[1]服務已啟動。");
                    return;
                }

                aw.Start();

                GLog.WLog("[2]服務已啟動");
            }
            catch (Exception ex)
            {
                GLog.WLog("OnStart ex:" + ex.Message);
            }
        }

        protected override void OnStop()
        {
            try
            {
                aw.Close();

                GLog.WLog("服務已停止");
            }
            catch (Exception ex)
            {
                GLog.WLog("OnStop ex:" + ex.Message);
            }
        }
    }
}

在windows服務庫中添加一個應用配置文件(App.config),用來配置WCF服務,內容如下:

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

  <system.serviceModel>
    <services>
      <service name="WcfYeah.Service1" behaviorConfiguration="behaviorThrottled">
        <host>
          <baseAddresses>
            <add baseAddress = "//localhost:16110/myapi/" />
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <!-- 除非完全限定,否則地址相對於上面提供的基址-->
        <endpoint address="" binding="webHttpBinding" contract="WcfYeah.IService1" bindingConfiguration="WebHttpBinding_IService">
        </endpoint>
      </service>
    </services>
    <bindings>
      <webHttpBinding>
        <binding name="WebHttpBinding_IService"  maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647"
                maxNameTableCharCount="2147483647"/>
        </binding>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="behaviorThrottled">
          <serviceThrottling
            maxConcurrentCalls="96"
            maxConcurrentSessions="600"
            maxConcurrentInstances="696"
          />
          <!-- 為避免泄漏元數據資訊,
          請在部署前將以下值設置為 false -->
          <serviceMetadata httpGetEnabled="False" httpsGetEnabled="False"/>
          <!-- 要接收故障異常詳細資訊以進行調試,
          請將以下值設置為 true。在部署前設置為 false 
          以避免泄漏異常資訊 -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  
</configuration>

 

 

編譯ADemoWinSvc項目,將編譯好的ADemoWinSvc.exe、ADemoWinSvc.exe.config和WcfYeah.dll這3個文件複製到WINFORM程式編譯輸出目錄,與Windows服務操作.exe文件放在一起。

用管理員許可權啟動Windows服務操作.exe,點擊安裝按鈕。

 

進入Logs文件夾,查看Logs文件,如果顯示「[2]服務已啟動」,說明windows服務安裝成功,WCF正常啟動。

 

使用POSTMAN調用。

地址://localhost:16110/myapi/geta

方法:POST

請求報文:

{
    “BoolValue”: true,
    “StringValue”: “11”
}
響應報文:
{
    “BoolValue”: true,
    “StringValue”: “輸入實體不為空:2021/11/30 9:38:41”
}