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”
}