如何在.NET CORE 下開發(fā) "windows 服務"

原文鏈接:https://blog.zhuliang.ltd/2019/04/backend/build-windowsservice-netcore.html

在.NET Core中并沒有像 .NET Framework下的 "windows服務"可創(chuàng)建,但我們依然可以通過powershell這個工具,將.NET CORE 下創(chuàng)建的項目以"windows服務"的形式來寄宿運行褂傀。

0.新建項目

新建柒室、使用一個 web 應用程序 項目即可

本次示例所用.NET CORE 版本為 2.1

image

項目結構如下:

image

1.修改項目csproj,增加RuntimeIdentifiers和IsTransformWebConfigDisabled

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <RuntimeIdentifiers>win10-x64;win81-x64</RuntimeIdentifiers>
    <IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
  </PropertyGroup>
  • 將Windows運行時標識符(RID)添加到包含目標框架的<PropertyGroup>蛉抓。
    • 如果要發(fā)布到多個Rids庆尘,則 <RuntimeIdentifier>需要用復數(shù): <RuntimeIdentifiers>,并且不同Rid之間用分號分割巷送,如:
<RuntimeIdentifiers>win10-x64;win81-x64</RuntimeIdentifiers>

2.添加包引用:

Microsoft.AspNetCore.Hosting.WindowsServices

Microsoft.Extensions.Logging.EventLog -------為了啟用windows事件日志

啟用 windows日志 start

創(chuàng)建一個自定義類驶忌,繼承自 WebHostService ,用來重寫onstarting等事件

    public class MqWebHostService : WebHostService
    {
        private ILogger _logger;

        public MqWebHostService(IWebHost host) : base(host)
        {
            _logger = host.Services
                .GetRequiredService<ILogger<MqWebHostService>>();
        }

        protected override void OnStarting(string[] args)
        {
            _logger.LogInformation("OnStarting method called.");
            base.OnStarting(args);
        }

        protected override void OnStarted()
        {
            _logger.LogInformation("OnStarted method called.");
            base.OnStarted();
        }

        protected override void OnStopping()
        {
            _logger.LogInformation("OnStopping method called.");
            base.OnStopping();
        }
    }

創(chuàng)建一個IHost的擴展方法惩系,用來運行自定義的服務:MqWebHostService

    public static class WebHostServiceExtensions
    {
        public static void RunAsCustomService(this IWebHost host)
        {
            var webHostService = new MqWebHostService(host);
            ServiceBase.Run(webHostService);
        }
    }

3.修改Program.Main方法:

    public class Program
    {
        public static void Main(string[] args)
        {
            var isService = !(Debugger.IsAttached || args.Contains("--console"));

            if (isService)
            {
                var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
                var pathToContentRoot = Path.GetDirectoryName(pathToExe);
                Directory.SetCurrentDirectory(pathToContentRoot);
            }

            var builder = CreateWebHostBuilder(
                args.Where(arg => arg != "--console").ToArray());

            var host = builder.Build();

            if (isService)
            {
                // To run the app without the CustomWebHostService change the
                // next line to host.RunAsService();
                host.RunAsCustomService();
            }
            else
            {
                host.Run();
            }
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args)
        {
            var hostingConfig = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("hostsettings.json", optional: true)
                .Build(); //指定 urls 鍵值即可位岔,需要注意不能用IIS EXPRESS,另外對于端口而言需要避免一些不安全端口堡牡,如6000端口
            return WebHost.CreateDefaultBuilder(args)
                .ConfigureLogging((hostingContext, logging) =>
                {
                    logging.SetMinimumLevel(LogLevel.Trace);
                    logging.AddFilter("System", LogLevel.Warning);
                    logging.AddFilter("Microsoft", LogLevel.Warning);
                    if (Environment.OSVersion.Platform == PlatformID.Unix)
                    {
                        logging.AddLog4Net("log4net.linux.config");
                    }
                    else
                    {
                        logging.AddLog4Net();
                    }
                })
                .ConfigureAppConfiguration((context, config) =>
                {
                    // Configure the app here.

                })
                .UseConfiguration(hostingConfig)
                .UseStartup<Startup>()
                ;
        }
    }

4.發(fā)布

  • SCD部署
使用 dotnet public -c release 進行 
  • FDD部署
dotnet public -c release -r win81-x64

7.使用 powershell注冊windows服務:

需要6.1.3 或以上版本抒抬,下載:https://github.com/PowerShell/PowerShell/releases

以下使用 localservice 這個系統(tǒng)服務作為用戶名進行注冊服務。

New-Service -Name "MqConsumerForMemberCenter" -BinaryPathName "D:\Services\MemberCenterMqConsumer\SanbenTech.MC.Mq.Subscriber.exe"  -Description "會員中心消息隊列 Consumer晤柄,定位用戶使用小程序時的區(qū)域" -DisplayName "MqConsumerForMemberCenter" -StartupType Automatic

刪除服務:

remove-service -Name "MqConsumerForMemberCenter"

也可以做成一個批處理擦剑,如下:

registerService.ps1

#Requires -Version 6.1.3
#Requires -RunAsAdministrator

param(
    [Parameter(mandatory=$true)]
    $Name,
    [Parameter(mandatory=$true)]
    $DisplayName,
    [Parameter(mandatory=$true)]
    $Description,
    [Parameter(mandatory=$true)]
    $Path,
    [Parameter(mandatory=$true)]
    $Exe,
    [Parameter(mandatory=$true)]
    $User
)

$cred = Get-Credential -Credential $User

$acl = Get-Acl $Path
$aclRuleArgs = $cred.UserName, "Read,Write,ReadAndExecute", "ContainerInherit, ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $aclRuleArgs
$acl.SetAccessRule($accessRule)
$acl | Set-Acl $Path

New-Service -Name $Name -BinaryPathName "$Path\$Exe" -Credential $cred -Description $Description -DisplayName $DisplayName -StartupType Automatic

如果需要用其他用戶來管理服務,則可以:

1.新建用戶

#創(chuàng)建用戶
net user {mcRabbitMqSubscriber}  {mypwd} /add /expires:never 
#添加到組
net localgroup {GROUP} {USER ACCOUNT} /add
#刪除用戶
net user {user account} /delete

2.給用戶賦予權限:作為服務登錄

icacls "{PATH}" /grant "{USER ACCOUNT}:(OI)(CI){PERMISSION FLAGS}" /t
    # {PATH} – Path to the app's folder.
    # {USER ACCOUNT} – The user account (SID).
    # (OI) – Object Inherit標志將權限傳播給從屬文件。
    # (CI) – Container Inherit標志將權限傳播到下級文件夾惠勒。
    # {PERMISSION FLAGS} – Sets the app's access permissions.
    # Write (W)
    # Read (R)
    # Execute (X)
    # Full (F)
    # Modify (M)
    # /t – 遞歸應用于現(xiàn)有的從屬文件夾和文件赚抡。
#如:(注意這里把useraccount OI,CI纠屋,PERMISSION FLAGS 用雙引號括起來涂臣,否則報錯)
icacls "X:\publish" /grant “mcRabbitMqSubscriber:(OI)(CI)WRX” /t    

3.調(diào)整注冊服務

registerService.ps1

#Requires -Version 6.1.3
#Requires -RunAsAdministrator

param(
    [Parameter(mandatory=$true)]
    $Name,
    [Parameter(mandatory=$true)]
    $DisplayName,
    [Parameter(mandatory=$true)]
    $Description,
    [Parameter(mandatory=$true)]
    $Path,
    [Parameter(mandatory=$true)]
    $Exe,
    [Parameter(mandatory=$true)]
    $User
)

$cred = Get-Credential -Credential $User

$acl = Get-Acl $Path
$aclRuleArgs = $cred.UserName, "Read,Write,ReadAndExecute", "ContainerInherit, ObjectInherit", "None", "Allow"
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $aclRuleArgs
$acl.SetAccessRule($accessRule)
$acl | Set-Acl $Path

New-Service -Name $Name -BinaryPathName "$Path\$Exe" -Credential $cred -Description $Description -DisplayName $DisplayName -StartupType Automatic

參考:

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-2.1

https://docs.microsoft.com/zh-cn/powershell/scripting/learn/using-familiar-command-names?view=powershell-6

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市售担,隨后出現(xiàn)的幾起案子赁遗,更是在濱河造成了極大的恐慌,老刑警劉巖族铆,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岩四,死亡現(xiàn)場離奇詭異,居然都是意外死亡哥攘,警方通過查閱死者的電腦和手機剖煌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逝淹,“玉大人耕姊,你說我怎么就攤上這事〈撮希” “怎么了箩做?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長妥畏。 經(jīng)常有香客問我邦邦,道長,這世上最難降的妖魔是什么醉蚁? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任燃辖,我火速辦了婚禮,結果婚禮上网棍,老公的妹妹穿的比我還像新娘黔龟。我一直安慰自己,他們只是感情好滥玷,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布氏身。 她就那樣靜靜地躺著,像睡著了一般惑畴。 火紅的嫁衣襯著肌膚如雪蛋欣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天如贷,我揣著相機與錄音陷虎,去河邊找鬼到踏。 笑死,一個胖子當著我的面吹牛尚猿,可吹牛的內(nèi)容都是我干的窝稿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼凿掂,長吁一口氣:“原來是場噩夢啊……” “哼伴榔!你這毒婦竟也來了?” 一聲冷哼從身側響起缠劝,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤潮梯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后惨恭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡耙旦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年脱羡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片免都。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡锉罐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绕娘,到底是詐尸還是另有隱情脓规,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布险领,位于F島的核電站侨舆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏绢陌。R本人自食惡果不足惜挨下,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脐湾。 院中可真熱鬧臭笆,春花似錦、人聲如沸秤掌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闻鉴。三九已至茵乱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間椒拗,已是汗流浹背似将。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工获黔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人在验。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓玷氏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親腋舌。 傳聞我的和親對象是個殘疾皇子盏触,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容