Windows创建服务(.NET8)

windows服务

Windows服务是一种在Windows操作系统中运行的后台程序,用于在系统启动时启动并在系统关闭时关闭。这些服务可以是Microsoft自己的服务,也可以是第三方软件的服务。它们在后台运行,通常不需要交互式用户界面。 Windows服务通常用于在计算机上提供系统级别的功能和服务,例如打印服务、数据库服务、网络服务、系统安全服务等。 通常,Windows服务可以在服务控制管理器(SCM)中进行配置和管理。其中,SCM是一种Windows组件,用于管理Windows服务和设备驱动程序。

.NET8

在全盘扫描是怎么实现的介绍了下.NET5的架构。目前.NET已经升级到.NET8。Blazor maui AOT更加成熟。微软在不遗余力的布局全平台,提升C#的性能.。ChatGPT最大的BOSS也是微软,只能说微软是真的强,虽错过了移动互联网,但凭借云计算和人工智能的布局,我想会再一次登顶科技圈。不得不说,科技是第一生产力。 .NET8新增功能在这里。
在这里插入图片描述

创建windows服务

本文以打卡程序为例来实践下整个服务的创建过程。

  1. dotnet new worker --name “SmartSign2”
  2. dotnet add package Microsoft.Extensions.Hosting.WindowsServices
  3. 更新项目文件
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <RootNamespace>App.WindowsService</RootNamespace>
    <OutputType>exe</OutputType>
    <PublishSingleFile Condition="'$(Configuration)' == 'Release'">true</PublishSingleFile>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <PlatformTarget>x64</PlatformTarget>
    <UserSecretsId>dotnet-smart_sign-ef6ac77d-c996-482b-8f81-5d63d0c287a5</UserSecretsId>
  </PropertyGroup>
  1. 创建服务
    要爬去网站或者模拟登陆的话,请修改相应的账号密码以及URL
public sealed class JokeService
{
    private string name = "xxx";
    private string password = "xxx";
    public string GetKqMessage()
    {
        String Result = String.Empty;
        IWebDriver wd = null;
        try
        {
            wd = new EdgeDriver();
            wd.Navigate().GoToUrl("http://xxx/#/");
            IWindow window = wd.Manage().Window;
            Thread.Sleep(2000);
            //处理登陆
            wd.FindElement(By.Name("account")).SendKeys(name);
            wd.FindElement(By.Name("password")).SendKeys(password);
            wd.FindElement(By.CssSelector("body > div > div > div > form > button > span")).Click();
            Thread.Sleep(10000);
            //打卡记录
            var record = "body > div.theme_panasonic > div > section > section > div > main > div.el-col.el-col-4.el-col-offset-2 > div > div:nth-child(4) > div:nth-child(5) > div > div > div:nth-child(2) > span";
            wd.FindElement(By.CssSelector(record)).Click();
            Thread.Sleep(5000);
            //每日考勤
            var attendence = "body > div > div > section > section > div > main > div.el-col.el-col-24 > div:nth-child(1) > div.EasyNormalTable > div.el-card.box-card.is-always-shadow > div.el-card__header > div > div > button:nth-child(3) > span";
            wd.FindElement(By.CssSelector(attendence)).Click();
            Thread.Sleep(2000);
            var attendence_time = "body > div > div > section > section > div > main > div.el-col.el-col-24 > div:nth-child(1) > div > div.el-card.box-card.is-always-shadow > div.el-card__body > div.filter-container > span.el-tag.el-tag--success.el-tag--light";
            var total_time = wd.FindElement(By.CssSelector(attendence_time)).Text;
            var tbody = wd.FindElement(By.TagName("tbody"));
            var detail_message = tbody.Text;
            var childrens = tbody.FindElements(By.TagName("tr"));
            // 第一条打卡记录
            var first_record_message = childrens.First().Text;
            String last_record_message = String.Empty;
            if (childrens.Count >= 2)
            {
                last_record_message = childrens[childrens.Count - 2].Text;
            }
            else
            {
                last_record_message = childrens[childrens.Count - 1].Text;
            }
            var record_message = first_record_message + "," + last_record_message;

            Thread.Sleep(2000);
            wd.Navigate().GoToUrl("http://burning.live:3000/counter");
            Thread.Sleep(3000);
            wd.FindElement(By.CssSelector("body > div.page > main > article > div > textarea")).SendKeys("首末次打卡情况:" + record_message + " \r\n" + total_time + "\r\n" + detail_message);
            var btn_send = wd.FindElement(By.CssSelector("#mail"));
            btn_send.Click();
            Thread.Sleep(3000);
            Result = record_message;
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            Result = e.StackTrace;
        }
        finally
        {
            if (wd != null)
            {
                wd.Close();
                wd.Quit();
            }
        }

        return Result;
    }

    public string GetJoke()
    {
        Joke joke = _jokes.ElementAt(
            Random.Shared.Next(_jokes.Count));

        return $"{joke.Setup}{Environment.NewLine}{joke.Punchline}";
    }

    // Programming jokes borrowed from:
    // https://github.com/eklavyadev/karljoke/blob/main/source/jokes.json
    private readonly HashSet<Joke> _jokes = new()
    {
        new Joke("What's the best thing about a Boolean?", "Even if you're wrong, you're only off by a bit."),
        new Joke("What's the object-oriented way to become wealthy?", "Inheritance"),
        new Joke("Why did the programmer quit their job?", "Because they didn't get arrays."),
        new Joke("Why do programmers always mix up Halloween and Christmas?", "Because Oct 31 == Dec 25"),
        new Joke("How many programmers does it take to change a lightbulb?", "None that's a hardware problem"),
        new Joke("If you put a million monkeys at a million keyboards, one of them will eventually write a Java program", "the rest of them will write Perl"),
        new Joke("['hip', 'hip']", "(hip hip array)"),
        new Joke("To understand what recursion is...", "You must first understand what recursion is"),
        new Joke("There are 10 types of people in this world...", "Those who understand binary and those who don't"),
        new Joke("Which song would an exception sing?", "Can't catch me - Avicii"),
        new Joke("Why do Java programmers wear glasses?", "Because they don't C#"),
        new Joke("How do you check if a webpage is HTML5?", "Try it out on Internet Explorer"),
        new Joke("A user interface is like a joke.", "If you have to explain it then it is not that good."),
        new Joke("I was gonna tell you a joke about UDP...", "...but you might not get it."),
        new Joke("The punchline often arrives before the set-up.", "Do you know the problem with UDP jokes?"),
        new Joke("Why do C# and Java developers keep breaking their keyboards?", "Because they use a strongly typed language."),
        new Joke("Knock-knock.", "A race condition. Who is there?"),
        new Joke("What's the best part about TCP jokes?", "I get to keep telling them until you get them."),
        new Joke("A programmer puts two glasses on their bedside table before going to sleep.", "A full one, in case they gets thirsty, and an empty one, in case they don’t."),
        new Joke("There are 10 kinds of people in this world.", "Those who understand binary, those who don't, and those who weren't expecting a base 3 joke."),
        new Joke("What did the router say to the doctor?", "It hurts when IP."),
        new Joke("An IPv6 packet is walking out of the house.", "He goes nowhere."),
        new Joke("3 SQL statements walk into a NoSQL bar. Soon, they walk out", "They couldn't find a table.")
    };
}

readonly record struct Joke(string Setup, string Punchline);
  1. 重写worker类
    可通过事件查看器来查看日志。在指定的时间会调用GetKqMessage,其他时间调用GetJoke
namespace App.WindowsService;

public sealed class WindowsBackgroundService : BackgroundService
{
    private readonly JokeService _jokeService;
    private readonly ILogger<WindowsBackgroundService> _logger;

    private int interval = 0;

    public WindowsBackgroundService(
        JokeService jokeService,
        ILogger<WindowsBackgroundService> logger) =>
        (_jokeService, _logger) = (jokeService, logger);

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                var isNeedTime = (DateTimeOffset.Now.Hour == 20 && DateTimeOffset.Now.Minute == 00) || (DateTimeOffset.Now.Hour == 18 && DateTimeOffset.Now.Minute == 00)
                    || (DateTimeOffset.Now.Hour == 15 && DateTimeOffset.Now.Minute == 00) || (DateTimeOffset.Now.Hour == 10 && DateTimeOffset.Now.Minute == 00);
                if (isNeedTime) 
                {
                    string kqMessage = _jokeService.GetKqMessage();
                    _logger.LogWarning("打卡结束 {kqMessage}", kqMessage);
                }
                else
                {
                    if (interval % 4 == 0)
                    {
                        string joke = _jokeService.GetJoke();
                        _logger.LogWarning("interval is  {interval}, {Joke}, 当前时间是: {time}", interval, joke, DateTimeOffset.Now);
                    }

                }
                await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
                interval++;
                if (interval == 30)
                {
                    Console.Clear();
                    interval = 0;
                }
            }
        }
        catch (OperationCanceledException)
        {
            interval = 0;
            // When the stopping token is canceled, for example, a call made from services.msc,
            // we shouldn't exit with a non-zero exit code. In other words, this is expected...
        }
        catch (Exception ex)
        {
            interval = 0;
            _logger.LogError(ex, "{Message}", ex.Message);

            // Terminates this process and returns an exit code to the operating system.
            // This is required to avoid the 'BackgroundServiceExceptionBehavior', which
            // performs one of two scenarios:
            // 1. When set to "Ignore": will do nothing at all, errors cause zombie services.
            // 2. When set to "StopHost": will cleanly stop the host, and log errors.
            //
            // In order for the Windows Service Management system to leverage configured
            // recovery options, we need to terminate the process with a non-zero exit code.
            Environment.Exit(1);
        }
    }
}
  1. 重写Program.cs
using App.WindowsService;
using Microsoft.Extensions.Logging.Configuration;
using Microsoft.Extensions.Logging.EventLog;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddWindowsService(options =>
{
    options.ServiceName = "SmartSign2";
});

LoggerProviderOptions.RegisterProviderOptions<
    EventLogSettings, EventLogLoggerProvider>(builder.Services);

builder.Services.AddSingleton<JokeService>();
builder.Services.AddHostedService<WindowsBackgroundService>();

IHost host = builder.Build();
host.Run();
  1. 发布应用
    在这里插入图片描述
  2. 创建 Windows 服务
    sc.exe create “SmartSign2” binpath=“C:\Users\yy\source\Python_Kq (1)\smart\smart_sign\bin\Release\net8.0\win-x64\publish\smart_sign.exe”
  3. 配置 Windows 服务
    sc qfailure “SmartSign2”
  4. 启动 Windows 服务
    sc.exe start “SmartSign2”
  5. 停止 Windows 服务
    sc.exe stop “SmartSign2”
  6. 删除 Windows 服务
    sc.exe delete “SmartSign2”

参考

使用 BackgroundService 创建 Windows 服务

更多内容,欢迎关注我的微信公众号:半夏之夜的无情剑客。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/222779.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

BearPi Std 板从入门到放弃 - 后天篇(2)(I2C1读写EEPROM)

简介 基于 BearPi Std 板从入门到放弃 - 后天篇&#xff08;1&#xff09;(I2C1 读取 光照强度)&#xff0c; 使用同一个I2C接口访问EEPROM, 同时读取光照亮度 主芯片: STM32L431RCT6 LED : PC13 \ 推挽输出即可 \ 高电平点亮 串口: Usart1 I2C : I2C1 光照强度传感器&#xf…

微软 Power Platform 零基础 Power Pages 网页搭建高阶实际案例实践(四)

微软 Power Platform 零基础 Power Pages 网页搭建教程之高阶案例实践学习(四) Power Pages 实际案例学习进阶 微软 Power Platform 零基础 Power Pages 网页搭建教程之高阶案例实践学习(四)1、新增视图,添加List页面2、新增下载Excel功能3、添加视图权限,根据登录人自动…

【文章学习系列之模型】TimeGPT-1

本章内容 文章概况模型结构数据集实验结果调包使用一般性报错API报错 总结 文章概况 《TimeGPT-1》是2023年公开于arXiv的一篇文章&#xff0c;该文章以chatgpt为灵感&#xff0c;提出一种基础时序大模型TimeGPT。该方案的提出致力于解决数据集规模不够大、模型泛化能力不强以…

python+requests接口自动化测试框架实例详解教程

前段时间由于公司测试方向的转型&#xff0c;由原来的web页面功能测试转变成接口测试&#xff0c;之前大多都是手工进行&#xff0c;利用postman和jmeter进行的接口测试&#xff0c;后来&#xff0c;组内有人讲原先web自动化的测试框架移驾成接口的自动化框架&#xff0c;使用的…

中庸行者 - 华为机试真题题解

给定一个m * n的整数矩阵作为地图&#xff0c;短阵数值为地形高度&#xff1b; 中庸行者选择地图中的任意一点作为起点&#xff0c;尝试往上、下、左、右四个相邻格子移动; 移动时有如下约束: 中庸行者只能上坡或者下坡&#xff0c;不能走到高度相同的点不允许连续上坡或者连续…

SpectralGPT: Spectral Foundation Model 论文翻译3

遥感领域的通用大模型 2023.11.13在CVPR发表 原文地址&#xff1a;[2311.07113] SpectralGPT: Spectral Foundation Model (arxiv.org) E.消融研究 在预训练阶段&#xff0c;我们对可能影响下游任务表现的各种因素进行了全面研究。这些因素包括掩蔽比、ViT patch大小、数据规…

matplotlib学习

显示两个figure 坐标上刻度修改 plt.xlim() 下标范围 plt.xticks() 替换新的下标 图例显示 散点图 subplot多合一显示

LDAP协议和AD活动目录的讲解

目录 LDAP协议 LDAP基本概念 LDAP目录的数据结构 LDAP交互过程以及相关报文 AD&#xff08;Active Directory&#xff09; AD基本概念 AD域与工作组、本地组的区别 AD DS&#xff08;AD域服务&#xff09; 信任关系 组策略和安全组 LDAP协议 LDAP基本概念 LDAP&…

2023年【高压电工】考试报名及高压电工试题及解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 高压电工考试报名考前必练&#xff01;安全生产模拟考试一点通每个月更新高压电工试题及解析题目及答案&#xff01;多做几遍&#xff0c;其实通过高压电工理论考试很简单。 1、【单选题】 12m电杆埋设深度宜()。&…

每天一点python——day88

#每天一点Python——88 #编程两大思想【面向过程与面向对象】 #如图&#xff1a; 面向过程的线性思维&#xff1a; 类似于做菜一步步的来&#xff0c;先怎么样怎么样&#xff0c;再怎么样 如果不一步步的来&#xff0c;例如先炒菜再点火&#xff0c;这样是做不好的 面向对象&a…

MySQL系列(一):索引篇

为什么是B树&#xff1f; 我们推导下&#xff0c;首先看下用哈希表做索引&#xff0c;是否可以满足需求。如果我们用哈希建了索引&#xff0c;那么对于如下这种SQL&#xff0c;通过哈希&#xff0c;可以快速检索出数据&#xff1a; select * from t_user_info where id1;但是这…

十年前端之离别的旋律

在一家名叫“梦想家”的小公司里&#xff0c;有一个普通的程序员&#xff0c;他的名字叫做小帅。每天默默地坐在角落里&#xff0c;默默地写着代码&#xff0c;默默地为公司付出。他的眼睛里总是充满了对工作的热爱和对生活的热情&#xff0c;但他的内心却隐藏着一个秘密&#…

R语言学习

Part1阶段1&#xff1a;入门基础 1安装R和RStudio&#xff1a; 下载并安装R&#xff1a;https://cran.r-project.org/ 下载并安装RStudio&#xff1a;https://www.rstudio.com/products/rstudio/download/ 2Hello World&#xff1a; 学习如何在R中输出"Hello, World!"…

Vue2、Vue3的Diff算法比较

前言 diff算法是vue更新dom前&#xff0c;比较新旧vdom的一种优化方式 特点&#xff1a; 只会在同一级比较 从两边往中间收拢 差别 vue2 和 vue3的差别在于处理完头尾节点后&#xff0c;对设于节点的处理方式vue2 是遍历旧节点&#xff0c;将旧节点映射到map里&#xff0…

npm : 无法加载文件 D:\nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本。

今天在使用vscode下载项目的依赖时&#xff0c;输入 pnmp install,结果报错: npm : 无法加载文件 D:\nodejs\node_global\npm.ps1&#xff0c;因为在此系统上禁止运行脚本。原因&#xff1a; 因为在此系统上禁止运行脚本&#xff0c;也就是说没有权限&#xff0c;查一下&#…

每天一点python——day87

#每天一点Python——87 #Pycharm程序调试 #例&#xff1a;【我想输出1-10】 i1 while i<10:print(i) #会一直输出1{我想输出一到十&#xff0c;但是他一直输出1}【如果想找到问题出现在什么地方&#xff1a;就需要一步步调试】 #那么怎么调试呢 #前面声明是没有错的&#x…

Java——面试:异常处理所用到的关键字有哪些?具体有什么作用?

1.异常处理所用到的关键字有哪些&#xff1f; Java异常处理所使用的到的关键字有&#xff1a;try、catch、finally、throw、throws五个 2.具体有什么作用&#xff1f; try&#xff1a;用于捕获异常&#xff0c;后面必须跟一个或多个catch块或者一个finally块&#xff1b;捕获到…

AdaBoost 详解

AdaBoost Boosting Boosting 是指&#xff0c;仅通过训练精度比随机猜想&#xff08;50%&#xff09;稍高的学习器&#xff0c;通过集成的方式过建出强学习器。 其中boosting中最有名的是AdaBoost算法。AdaBoost是英文"Adaptive Boosting"&#xff08;自适应增强&…

祸害了人民3年的新冠消失了,但有些奇怪现象,让人百思不得其解

真是没想到啊&#xff0c;祸害我们3年的新冠病毒突然就消失了&#xff0c;但是紧接着呢&#xff0c;却有一个非常奇怪的现象出现了&#xff0c;真的是令人百思不得其解&#xff01; 新冠病毒&#xff0c;于2020年的开始&#xff0c;可以说根本就没有任何缓冲期&#xff0c;一开…

微信小程序基础bug

1.苹果11手机小程序请求数据不显示 设置-》隐私-》分析与改进-》开启 ”与开发者共享“ 2.<navigator>组件回退delta不成功 tabBar 页面是不能实现后退的效果的. 因为, 当我们跳转到 tabBar 页面&#xff0c;会关闭其他所有非tabBar 页面,所以当处于 tabBar 页面时, 无…