当前位置:首页 > 技术 > 正文内容

通过Windows服务托管WCF服务的实现方法

访客 技术 2026年8月25日 1

延续之前关于WCF服务部署到IIS和控制台应用程序的内容,本节介绍如何将WCF服务托管于Windows服务中。该方式具备系统自启动能力,无需人工干预,适合长期稳定运行的服务场景。

1. 创建Windows服务项目

在现有解决方案中新建一个名为 WinSvcHost 的Windows服务项目。

2. 引用必要组件

  • 添加对 System.ServiceModel 的引用。
  • 引用已有的WCF服务类库项目(如 WcfServiceLib)。

3. 实现服务宿主逻辑

创建服务类并重写启动与停止方法,代码结构如下:

using System;
using System.ServiceModel;
using System.ServiceProcess;

namespace WinSvcHost
{
    public partial class WcfHostService : ServiceBase
    {
        private const string SERVICE_NAME = "WcfHostViaWindowsService";
        private ServiceHost _host;

        public WcfHostService()
        {
            InitializeComponent();
            ServiceName = SERVICE_NAME;
        }

        protected override void OnStart(string[] args)
        {
            try
            {
                _host = new ServiceHost(typeof(BookService));
                if (_host.State != CommunicationState.Opened)
                    _host.Open();

                Log($"{SERVICE_NAME} 服务已于 {DateTime.Now} 启动。");
            }
            catch (Exception ex)
            {
                Log($"启动失败: {ex.Message}");
                throw;
            }
        }

        protected override void OnStop()
        {
            _host?.Close();
            _host = null;
            Log($"{SERVICE_NAME} 服务已停止。");
        }

        private static void Log(string message) => Console.WriteLine(message);
    }
}

4. 添加安装程序支持

右键服务设计界面,选择"添加安装程序",系统会自动生成 ProjectInstaller.cs 文件。

5. 配置安装器属性

  • 设置 serviceInstaller1ServiceNameDescription
  • 设置 serviceProcessInstaller1 的账户类型(如 LocalSystem 或 NetworkService)。

6. 实现命令行安装/卸载功能

修改主程序入口,支持通过参数安装或卸载服务:

using System;
using System.Configuration.Install;
using System.Reflection;
using System.ServiceProcess;

namespace WinSvcHost
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                ServiceBase.Run(new ServiceBase[] { new WcfHostService() });
            }
            else if (args[0].Equals("/i", StringComparison.OrdinalIgnoreCase))
            {
                InstallService();
            }
            else if (args[0].Equals("/u", StringComparison.OrdinalIgnoreCase))
            {
                UninstallService();
            }
        }

        static void InstallService()
        {
            if (!ServiceExists("WcfHostViaWindowsService"))
            {
                var installer = new AssemblyInstaller(Assembly.GetExecutingAssembly().Location, null);
                installer.Install(null);
                installer.Commit(null);

                var controller = new ServiceController("WcfHostViaWindowsService");
                controller.Start();
                controller.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
                Console.WriteLine("服务安装并启动成功。");
            }
        }

        static void UninstallService()
        {
            if (ServiceExists("WcfHostViaWindowsService"))
            {
                var installer = new AssemblyInstaller(Assembly.GetExecutingAssembly().Location, null);
                installer.Uninstall(null);
                Console.WriteLine("服务卸载完成。");
            }
        }

        static bool ServiceExists(string serviceName)
        {
            return ServiceController.GetServices()
                .Any(s => s.ServiceName.Equals(serviceName, StringComparison.OrdinalIgnoreCase));
        }
    }
}

7. 配置WCF服务端点

App.config 中配置服务行为和终结点:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ExposeMetadata">
          <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8080/BookSvc/metadata" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <services>
      <service name="WcfServiceLib.BookService" behaviorConfiguration="ExposeMetadata">
        <endpoint address="http://localhost:8080/BookSvc"
                  binding="wsHttpBinding"
                  contract="WcfServiceLib.IBookService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

8. 创建批处理脚本

编写两个批处理文件用于快速操作:

REM install.bat
WinSvcHost.exe /i
pause
REM uninstall.bat
WinSvcHost.exe /u
pause

9. 验证安装与运行

执行安装脚本后,打开"服务"管理器,应能看到新注册的服务项。启动服务后,可使用先前开发的客户端程序调用其接口进行测试。

返回列表

上一篇:XXL-Job 定时任务的 Cron 表达式解析

没有最新的文章了...

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。