参考:

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. Word图片上传控件(WordPaster)更新-2.0.15版本

    更新说明: 1.   增加对webp图片的支持,支持微信公众号图片的下载. 效果参考:http://www.ncmem.com/doc/view.aspx?id=9761f8ce4fe04d0ab0f ...

  2. HDU1349 Minimum Inversion Number 2016-09-15 13:04 75人阅读 评论(0) 收藏

    B - Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d &a ...

  3. ajax如何向后台传递数组,在后台该如何接收的问题(项目积累)

    一.后台如何接收从前台接收的数组: 使用request.getParameterValues(String xxx); <input type="text" name=&qu ...

  4. sun.jersey使用Jackson转换数据

    差点被com.sun.jersey自身的json转换吓死,遇到List等类型,会把这些也转换为json对象,而不是jsonarray. 被园里的同行拯救了,在web.xml中配置一下就ok. < ...

  5. 初识构建工具-gradle

    构建工具的作用 依赖管理 测试,打包,发布 主流的构建工具 Ant:提供编译,测试,打包 Maven:在Ant的基础上提供了依赖管理和发布的功能 Gradle:在Maven的基础上使用Groovy管理 ...

  6. 构建NetCore应用框架之实战篇(六):BitAdminCore框架架构小结

    本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.小结 1.前面已经完成框架的第一个功能,本篇做个小结. 2.直接上 ...

  7. Restframework 渲染器 render 组件实例-4

    渲染器默认存放位置: 在默认配置下 default-settings里 (APIVIEW点击去--> 1. renderer_classes = api_settings.DEFAULT_REN ...

  8. TCP BBR - 一键开启脚本

    这是秋水逸冰提供的TCP BBR一键开启脚本,脚本详细说明地址: https://teddysun.com/489.html 按照说明操作就可以了,注意问题:这个脚本获取有的时候可能有问题,如果提示脚 ...

  9. javascript中的数据类型和变量

    Number JavaScript不区分整数和浮点数,统一用Number表示,以下都是合法的Number类型: 123; // 整数123 0.456; // 浮点数0.456 1.2345e3; / ...

  10. 对数组排序三种方式sort、asort与ksort

    关联数组是 键值(key)=>值(value)形式. sort只对值进行排序,键值不参与排序: asort对值进行排序,键值参与排序: ksort对键值进行排序,值参与排序: 实例,比如数组: ...