参考:

Build A Windows Service Framework

新建ServiceFramework类库,项目中需引用:

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

三个类BasicServiceStarter、BasicServiceInstaller、BasicService的代码:

class BasicService<T> : ServiceBase where T : IDisposable, new()
    {
        private IDisposable _service;

        protected override void OnStart(string[] args)
        {
            try
            {
                _service = new T();
            }
            catch
            {
                ExitCode = ;
                throw;
            }
        }

        protected override void OnStop()
        {
            _service.Dispose();
        }
    }
static class BasicServiceInstaller
    {
        public static void Install(string serviceName)
        {
            CreateInstaller(serviceName).Install(new Hashtable());
        }

        public static void Uninstall(string serviceName)
        {
            CreateInstaller(serviceName).Uninstall(null);
        }

        private static Installer CreateInstaller(string serviceName)
        {
            var installer = new TransactedInstaller();
            installer.Installers.Add(new ServiceInstaller
            {
                ServiceName = serviceName,
                DisplayName = serviceName,
                StartType = ServiceStartMode.Manual
            });
            installer.Installers.Add(new ServiceProcessInstaller
            {
                Account = ServiceAccount.LocalSystem
            });
            var installContext = new InstallContext(
                serviceName + ".install.log", null);
            installContext.Parameters["assemblypath"] =
                Assembly.GetEntryAssembly().Location;
            installer.Context = installContext;
            return installer;
        }
    }
public static class BasicServiceStarter
    {
        public static void Run<T>(string serviceName) where T : IDisposable, new()
        {
            AppDomain.CurrentDomain.UnhandledException += (s, e) =>
            {
                if (EventLog.SourceExists(serviceName))
                {
                    EventLog.WriteEntry(serviceName,
                        "Fatal Exception : " + Environment.NewLine +
                        e.ExceptionObject, EventLogEntryType.Error);
                }
            };

            if (Environment.UserInteractive)
            {
                var cmd =
                    (Environment.GetCommandLineArgs().Skip().FirstOrDefault() ?? "")
                    .ToLower();
                switch (cmd)
                {
                    case "i":
                    case "install":
                        Console.WriteLine("Installing {0}", serviceName);
                        BasicServiceInstaller.Install(serviceName);
                        break;
                    case "u":
                    case "uninstall":
                        Console.WriteLine("Uninstalling {0}", serviceName);
                        BasicServiceInstaller.Uninstall(serviceName);
                        break;
                    default:
                        using (var service = new T())
                        {
                            Console.WriteLine(
                                "Running {0}, press any key to stop", serviceName);
                            Console.ReadKey();
                        }
                        break;
                }
            }
            else
            {
                ServiceBase.Run(new BasicService<T> { ServiceName = serviceName });
            }
        }
    }

新建控制台应用程序MyWindowsService,引用ServiceFramework

新建服务应用类,在默认构造函数中执行服务的代码:

class MyService:IDisposable
    {
        public MyService()
        {
            Console.WriteLine("服务启动");
            //do something
        }

        public void Dispose()
        {
            Console.WriteLine("服务停止");
        }
    }

在Main中调用服务:

class Program
    {
        private const string Name = "我的服务";
        static void Main(string[] args)
        {
            BasicServiceStarter.Run<MyService>(Name);
        }
    }

服务的调试及安装与上一篇

使用Topshelf部署Windows服务

相同,这里可以在快捷方式中直接加“i"和”u"即可。

依然可以使用log4net来记录日志:

引用log4net:

install-package log4net

加入log4net.config配置文件,主要此文件一定要始终复制到输出目录

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
  </configSections>
  <log4net>
    <!--定义输出到文件中-->
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <!--定义文件存放位置-->
      <file value="log\\"/>
      <!--是否追加到文件,默认为true,通常无需设置-->
      <appendToFile value="true"/>
      <!--多线程时采用最小锁定-->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
      <!--变换的形式为日志大小-->
      <!--这种情况下MaxSizeRollBackups和maximumFileSize的节点设置才有意义-->
      <!--<rollingStyle value="Size"/>-->
      <!--每天记录的日志文件个数,与maximumFileSize配合使用-->
      <!--<MaxSizeRollBackups value="/>-->
      <!--每个日志文件的最大大小-->
      <!--可用的单位:KB|MB|GB-->
      <!--不要使用小数,否则会一直写入当前日志-->
      <!--<maximumFileSize value="2MB"/>-->

      <!--变换的形式为日期,这种情况下每天只有一个日志-->
      <!--此时MaxSizeRollBackups和maximumFileSize的节点设置没有意义-->
      <rollingStyle value="Date"/>

      <!--每分钟写一个文件-->
      <!--<datePattern value="yyyyMMdd-HHmm" />-->
      <!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置-->

      <datePattern value="yyyyMMdd\\HH'.txt'"/>
      <staticLogFileName value="false"/>
      <param name="/>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%newline %n记录时间:%date %n描述:%message"/>
        <!--<conversionPattern value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别:  %-5level %n出错类:%logger property: [%property{NDC}] - %n错误描述:%message%newline %n"/>-->
      </layout>
    </appender>

    <!--定义输出到MySql中-->
    <!--注意 Mysql.data 引用属性中复制本地一定要选True-->
    <appender name="AdoNetAppender_MySql" type="log4net.Appender.AdoNetAppender">
      <bufferSize value="/>
      <param name="ConnectionType" value="MySql.Data.MySqlClient.MySqlConnection, MySql.Data"/>
      <param name="ConnectionString" value="server=localhost;database=test;uid=root;pwd=maocaiming;"/>
      <commandText value="INSERT INTO mylog111 (log_datetime,log_thread,log_level,log_logger,log_message,Exception) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)"/>
      <parameter>
        <parameterName value="@log_date"/>
        <dbType value="DateTime"/>
        <layout type="log4net.Layout.RawTimeStampLayout"/>
      </parameter>
      <parameter>
        <parameterName value="@thread"/>
        <dbType value="String"/>
        <size value="/>
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%thread"/>
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@log_level"/>
        <dbType value="String"/>
        <size value="/>
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%level"/>
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@logger"/>
        <dbType value="String"/>
        <size value="/>
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%logger"/>
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@message"/>
        <dbType value="String"/>
        <size value="/>
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%message"/>
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@exception"/>
        <dbType value="String"/>
        <size value="/>
        <layout type="log4net.Layout.ExceptionLayout"/>
      </parameter>
    </appender>
    <root>
      <!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF-->
      <!--比如定义级别为INFO,则INFO级别向下的级别,比如DEBUG日志将不会被记录-->
      <!--如果没有定义LEVEL的值,则缺省为DEBUG-->
      <level value="ALL"/>
      <!--文件形式记录日志-->
      <appender-ref ref="RollingLogFileAppender"/>
      <!--<appender-ref ref="AdoNetAppender_MySql"/>-->
    </root>
  </log4net>
</configuration>

更新后的Main:

    class Program
    {
        private const string Name = "我的服务";
        static void Main(string[] args)
        {
            FileInfo fi = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log4net.config");
            XmlConfigurator.ConfigureAndWatch(fi);
            BasicServiceStarter.Run<MyService>(Name);
        }
    }

这里用Path.Combine方法更好:

FileInfo fi = new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory , "log4net.config"));
            XmlConfigurator.ConfigureAndWatch(fi);

更新后的MyService:

class MyService:IDisposable
    {
        readonly Timer _timer;
        readonly ILog _log = LogManager.GetLogger(typeof(MyService));
        public MyService()
        {
            Console.WriteLine("服务启动");
            _log.Info("Service is Started");
            //do something
            _timer = ) { AutoReset = true };
            _timer.Elapsed += new ElapsedEventHandler(OnTick);
            _timer.Elapsed += (sender, eventArgs) => Console.WriteLine("It is {0} and all is well", DateTime.Now);
            _timer.Start();
        }
        protected virtual void OnTick(object sender, ElapsedEventArgs e)
        {
            _log.Debug("Tick:" + DateTime.Now.ToLongTimeString());
        }
        public void Dispose()
        {
            Console.WriteLine("服务停止");
            _log.Info("Service is Stopped");
        }
    }

可调试Windows服务框架的更多相关文章

  1. Topshelf一个用于使用.NET构建Windows服务框架

    1 Topshelf是什么? Topshelf是用于托管使用.NET框架编写的Windows服务的框架.服务的创建得到简化,从而使开发人员可以创建一个简单的控制台应用程序,可以使用Topshelf将其 ...

  2. Windows服务框架与服务的编写

    从NT内核开始,服务程序已经变为一种非常重要的系统进程,一般的驻守进程和普通的程序必须在桌面登录的情况下才能运行,而许多系统的基础程序必须在用户登录桌面之前就要运行起来,而利用服务,可以很方便的实现这 ...

  3. 使用Topshelf组件构建简单的Windows服务

    很多时候都在讨论是否需要了解一个组件或者一个语言的底层原理这个问题,其实我个人觉得,对于这个问题,每个人都有自己的看法,个人情况不同,选择的方式也就会不同了.我个人觉得无论学习什么,都应该尝试着去了解 ...

  4. 如何使用Topshelf与.NET泛型主机建立Windows服务

    1 前置阅读 在阅读本文章之前,你可以先阅读: Topshelf一个用于使用.NET构建Windows服务框架 2 使用 2.1 创建应用程序 首先,创建一个新的控制台应用程序并从nuget获取Top ...

  5. RDIFramework.NET框架SOA解决方案(集Windows服务、WinForm形式与IIS形式发布)-分布式应用

    RDIFramework.NET框架SOA解决方案(集Windows服务.WinForm形式与IIS形式发布)-分布式应用 RDIFramework.NET,基于.NET的快速信息化系统开发.整合框架 ...

  6. 使用C语言编写windows服务一般框架

    原文:使用C语言编写windows服务一般框架 编写windows服务和编写windows应用程序一样,有一些回调函数必须填写且向windows 服务管理器(service manager)进行注册, ...

  7. NET框架SOA解决方案(集Windows服务、WinForm形式与IIS形式发布)-分布式应用

    NET框架SOA解决方案(集Windows服务.WinForm形式与IIS形式发布)-分布式应用 RDIFramework.NET,基于.NET的快速信息化系统开发.整合框架,给用户和开发者最佳的.N ...

  8. Topshelf 一个简化Windows服务开发的宿主服务框架

    Topshelf是 基于.net框架开发的宿主服务框架.该框架简化了服务的创建,开发人员只需要使用 Topshelf编写一个控制台程序,就能安装为Windows服务.之所以这样原因非常简单:调试一个控 ...

  9. RDIFramework.NET框架SOA解(集Windows服务、WinForm形式和IIS发布形式)-分布式应用程序

    RDIFramework.NET框架SOA解决方式(集Windows服务.WinForm形式与IIS形式公布)-分布式应用 RDIFramework.NET,基于.NET的高速信息化系统开发.整合框架 ...

随机推荐

  1. (线段树 区间查询)The Water Problem -- hdu -- 5443 (2015 ACM/ICPC Asia Regional Changchun Online)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=5443 The Water Problem Time Limit: 1500/1000 MS (Java/ ...

  2. [Android]高低API版本兼容之@TargetApi

    使用@TargetApi annotaion, 使高版本API的代码在低版本SDK不报错 例如: AsyncTask.THREAD_POOL_EXECUTOR, 这个静态变量是API11才有的, 设置 ...

  3. linux环境下(非UI操作)所有软件的安装与卸载总结

    UI界面的软件管理 linux下的软件一般都是经过压缩的,主要的格式有这几种:rpm.tar.tar.gz.tgz等.所以首先拿到软件后第一件事就是解压缩. 在xwindow下以rpm格式的软件安装比 ...

  4. java web 入门实例servlet篇(显示后台数据库列表,删除某一条记录并显示)

    编写过程中需要注意的问题: 1.建立eclipse动态web工程时,需要改写编译后class文件的位置,通常情况下是这个位置:/WebContent/WEB-INF/classes 2.配置的页面链接 ...

  5. ABP 基础设施层——集成 Entity Framework

    本文翻译自ABP的官方教程<EntityFramework Integration>,地址为:http://aspnetboilerplate.com/Pages/Documents/En ...

  6. [Openwrt 项目开发笔记]:PHP+Nginx安装(七)

    [Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 在上一节中,我们已经搭建了MySQL数据库了,因 ...

  7. Index--过滤索引和参数化

    --============================================ 领导指点我去给某台数据库调优下,结果屁颠屁颠地干完,还自我感觉良好,刚刚别人博客时,才发现自己踩坑了!! ...

  8. C#操作Xml树的扩展类

    本文提供一个操作Xml树的扩展类,与将xml字符串直接映射成实体对象的使用方法,供大家参考,学习. 下面附上源码 using System; using System.Collections.Gene ...

  9. Docker Compose 部署前后端分离应用

    部署前后端分离应用 容器化 Abp 应用 关于 Abp 应用的容器化,其实和普通的 ASP.NET Core 应用差不多,大家可以参考我此前的文章. 唯一需要注意的是:因为 Abp 解决方案中有多个项 ...

  10. Godot开发环境与学习资源

    记得第一次听到Godot的名字时还在深圳工作,刚刚接触Unity快一年,只是匆匆在Github上star了,就没有继续了.后面时不时翻开它的Git主页,然而一直没有下载过,每每想看看开源引擎都去看Or ...