借助 .NET提供的服务承载(Hosting)系统,我们可以将一个或者多个长时间运行的后台服务寄宿或者承载我们创建的应用中。任何需要在后台长时间运行的操作都可以定义成标准化的服务并利用该系统来承载,ASP.NET Core应用最终也体现为这样一个承载服务。(本篇提供的实例已经汇总到《ASP.NET Core 6框架揭秘-实例演示版》)

[S1407]利用IHostApplicationLifetime对象关闭应用(源代码

[S1408]与第三方依赖注入框架的整合(源代码

[S1409]利用配置初始化承载环境(源代码

[S1407]利用IHostApplicationLifetime对象关闭应用

我们接下来通过一个简单的实例演示如何利用IHostApplicationLifetime服务来关闭整个承载应用。我们在一个控制台应用程序中定义了如下这个承载服务类型FakeHostedService,并在其构造函数中注入了IHostApplicationLifetime服务。在得到其三个属性返回的CancellationToken对象之后,我们在它们上面分别注册了一个回调在控制台输出相应的文字。

public sealed class FakeHostedService : IHostedService
{
private readonly IHostApplicationLifetime _lifetime;
private IDisposable? _tokenSource; public FakeHostedService(IHostApplicationLifetime lifetime)
{
_lifetime = lifetime;
_lifetime.ApplicationStarted.Register(() => Console.WriteLine("[{0}]Application started", DateTimeOffset.Now));
_lifetime.ApplicationStopping.Register(() => Console.WriteLine("[{0}]Application is stopping.", DateTimeOffset.Now));
_lifetime.ApplicationStopped.Register(() => Console.WriteLine("[{0}]Application stopped.", DateTimeOffset.Now));
} public Task StartAsync(CancellationToken cancellationToken)
{
_tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token.Register(_lifetime.StopApplication);
return Task.CompletedTask;
} public Task StopAsync(CancellationToken cancellationToken)
{
_tokenSource?.Dispose();
return Task.CompletedTask;
}
}

在实现的StartAsync方法中,我们采用如上的方式在等待5秒之后调用IHostApplicationLifetime对象的StopApplication方法关闭应用程序。FakeHostedService服务最后采用如下所示的方式承载于当前应用程序中。

using App;
Host.CreateDefaultBuilder(args)
.ConfigureServices(svcs => svcs.AddHostedService<FakeHostedService>())
.Build()
.Run();

该程序运行之后在控制台上输出的结果如图1所示,从三条消息输出的时间间隔可以确定当前应用程序正是承载FakeHostedService通过调用IHostApplicationLifetime服务的StopApplication方法关闭的。


图1 调用IHostApplicationLifetime服务关闭应用程序

[S1408]与第三方依赖注入框架的整合

一个Mini版的依赖注入框架》中创建了一个名为Cat的简易版依赖注入框架,并在《与第三方依赖注入框架Cat的整合》中为其创建了一个IServiceProviderFactory<TContainerBuilder>实现类型,具体类型为CatServiceProvider,我们接下来演示一下如何通过注册CatServiceProvider实现与Cat这个第三方依赖注入框架的整合。在创建的演示程序中,我们采用这样的方式定义了三个服务(Foo、Bar和Baz)和对应的接口(IFoo、IBar和IBaz),并在服务类型上标注MapToAttribute特性来定义服务注册信息。

public interface IFoo { }
public interface IBar { }
public interface IBaz { } [MapTo(typeof(IFoo), Lifetime.Root)]
public class Foo : IFoo { } [MapTo(typeof(IBar), Lifetime.Root)]
public class Bar : IBar { } [MapTo(typeof(IBaz), Lifetime.Root)]
public class Baz : IBaz { }

如下所示的FakeHostedService类型表示承载的服务。我们在构造函数中注入了IFoo、IBar和IBaz对象,构造函数提供的调试断言用于验证上述三个服务被成功注入。

public sealed class FakeHostedService: IHostedService
{
public FakeHostedService(IFoo foo, IBar bar, IBaz baz)
{
Debug.Assert(foo != null);
Debug.Assert(bar != null);
Debug.Assert(baz != null);
}
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

我们在如下的演示程序中创建了一个IHostBuilder对象,通过调用其ConfigureServices方法注册了需要承载的FakeHostedService服务后,我们调用它的UseServiceProviderFactory方法完成了对CatServiceProvider的注册。我们随后调用了CatBuilder的Register方法完成了针对入口程序集的批量服务注册。调用IHostBuilder的Build方法构建出作为宿主的IHost对象并启动它之后,承载的FakeHostedService服务将自动被创建并启动(S1408)。

using App;
using System.Reflection; Host.CreateDefaultBuilder()
.ConfigureServices(svcs => svcs.AddHostedService<FakeHostedService>())
.UseServiceProviderFactory(new CatServiceProviderFactory())
.ConfigureContainer<CatBuilder>(
builder => builder.Register(Assembly.GetEntryAssembly()!))
.Build()
.Run();

[S1409]利用配置初始化承载环境

一个HostBuilderContext上下文由承载针对宿主配置的IConfiguration对象和描述当前承载环境的IHostEnvironment对象组成,后者提供的环境名称、应用名称和内容文件根目录路径可以通过前者来指定,具体的配置项名称定义在如下这个静态类型HostDefaults中。

public static class HostDefaults
{
public static readonly string EnvironmentKey = "environment";
public static readonly string ContentRootKey = "contentRoot";
public static readonly string ApplicationKey = "applicationName";
}

下面我们通过一个简单的实例演示如何利用配置的方式来指定上述三个与承载环境相关的属性。我们定义了如下一个名为FakeHostedService的承载服务,并在构造函数中注入IHostEnvironment对象。FakeHostedService派生于抽象类BackgroundService,我们在在ExecuteAsync方法中将与承载环境相关的环境名称、应用名称和内容文件根目录路径输出到控制台上。

public class FakeHostedService : BackgroundService
{
private readonly IHostEnvironment _environment;
public FakeHostedService(IHostEnvironment environment) => _environment = environment;
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
Console.WriteLine("{0,-15}:{1}", nameof(_environment.EnvironmentName), _environment.EnvironmentName);
Console.WriteLine("{0,-15}:{1}", nameof(_environment.ApplicationName),_environment.ApplicationName);
Console.WriteLine("{0,-15}:{1}", nameof(_environment.ContentRootPath),_environment.ContentRootPath);
return Task.CompletedTask;
}
}

FakeHostedService采用如下形式进行承载。如代码片段所示,为了避免输出日志的“干扰”,我们调用IHostBuilder接口的ConfigureLogging扩展方法将注册的ILoggerProvider对象全部清除。如果调用Host静态类型的CreateDefaultBuilder方法时传入当前的命令行参数,创建的IHostBuilder对象会将其作为配置源,所以我们就能以命令行参数的形式来指定承载上下文的三个属性。

using App;
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging=>logging.ClearProviders())
.ConfigureServices(svcs => svcs.AddHostedService<FakeHostedService>())
.Build()
.Run();

我们采用命令行的方式启动这个演示程序,并利用传入的命令行参数指定环境名称、应用名称和内容文件根目录路径(确保路径确实存在)。图2所示的输出结果表明,应用程序当前的承载环境与基于宿主的配置是一致的。


图2 利用配置来初始化承载环境

ASP.NET Core 6框架揭秘实例演示[22]:如何承载你的后台服务[补充]的更多相关文章

  1. ASP.NET Core 6框架揭秘实例演示[07]:文件系统

    ASP.NET Core应用具有很多读取文件的场景,如读取配置文件.静态Web资源文件(如CSS.JavaScript和图片文件等).MVC应用的视图文件,以及直接编译到程序集中的内嵌资源文件.这些文 ...

  2. ASP.NET Core 6框架揭秘实例演示[08]:配置的基本编程模式

    .NET的配置支持多样化的数据源,我们可以采用内存的变量.环境变量.命令行参数.以及各种格式的配置文件作为配置的数据来源.在对配置系统进行系统介绍之前,我们通过几个简单的实例演示一下如何将具有不同来源 ...

  3. ASP.NET Core 6框架揭秘实例演示[09]:配置绑定

    我们倾向于将IConfiguration对象转换成一个具体的对象,以面向对象的方式来使用配置,我们将这个转换过程称为配置绑定.除了将配置树叶子节点配置节的绑定为某种标量对象外,我们还可以直接将一个配置 ...

  4. ASP.NET Core 6框架揭秘实例演示[10]:Options基本编程模式

    依赖注入使我们可以将依赖的功能定义成服务,最终以一种松耦合的形式注入消费该功能的组件或者服务中.除了可以采用依赖注入的形式消费承载某种功能的服务,还可以采用相同的方式消费承载配置数据的Options对 ...

  5. ASP.NET Core 6框架揭秘实例演示[11]:诊断跟踪的几种基本编程方式

    在整个软件开发维护生命周期内,最难的不是如何将软件系统开发出来,而是在系统上线之后及时解决遇到的问题.一个好的程序员能够在系统出现问题之后马上定位错误的根源并找到正确的解决方案,一个更好的程序员能够根 ...

  6. ASP.NET Core 6框架揭秘实例演示[12]:诊断跟踪的进阶用法

    一个好的程序员能够在系统出现问题之后马上定位错误的根源并找到正确的解决方案,一个更好的程序员能够根据当前的运行状态预知未来可能发生的问题,并将问题扼杀在摇篮中.诊断跟踪能够帮助我们有效地纠错和排错&l ...

  7. ASP.NET Core 6框架揭秘实例演示[13]:日志的基本编程模式[上篇]

    <诊断跟踪的几种基本编程方式>介绍了四种常用的诊断日志框架.其实除了微软提供的这些日志框架,还有很多第三方日志框架可供我们选择,比如Log4Net.NLog和Serilog 等.虽然这些框 ...

  8. ASP.NET Core 6框架揭秘实例演示[14]:日志的进阶用法

    为了对各种日志框架进行整合,微软创建了一个用来提供统一的日志编程模式的日志框架.<日志的基本编程模式>以实例演示的方式介绍了日志的基本编程模式,现在我们来补充几种"进阶" ...

  9. ASP.NET Core 6框架揭秘实例演示[15]:针对控制台的日志输出

    针对控制台的ILogger实现类型为ConsoleLogger,对应的ILoggerProvider实现类型为ConsoleLoggerProvider,这两个类型都定义在 NuGet包"M ...

随机推荐

  1. js判断当前浏览设备

    前端开发经常遇到需要判断用户的浏览设备,是pc端还是移动端,移动端使用的是什么手机系统?android.ios.ipad.windows phone等等,有时候还需要知道用户浏览页面是在微信中打开还是 ...

  2. WebLogic11g- 集群化

    其实网上关于weblogic集群的资料非常多[大部分都是从创建新的domain开始,我这篇先介绍怎么样把原本普通的domain改造为集群环境],如果觉得不够,可以啃weblogic的官方文档.下面给几 ...

  3. GRC: 个人信息保护法, 个人隐私, 企业风险合规治理

    声明 个人原创, 转载需注明来源 https://www.cnblogs.com/milton/p/15885344.html 个人信息保护的历史和现状 个人信息保护的立法可追溯至德国黑森州1970年 ...

  4. 基于GDAL库,读取.grd文件(以海洋地形数据为例)Java版

    技术背景 海洋地形数据主要是通过美国全球地形起伏数据(GMT)获得,数据格式为grd(GSBG)二进制数据,打开软件通过是Surfer软件,surfer软件可进行数据的编辑处理,以及进一步的可视化表达 ...

  5. 05 BOM与DOM

    BOM和DOM 1. 什么是BOM和DOM 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的 ...

  6. Solution -「LOCAL」二进制的世界

    \(\mathcal{Description}\)   OurOJ.   给定序列 \(\{a_n\}\) 和一个二元运算 \(\operatorname{op}\in\{\operatorname{ ...

  7. APK修改神器:插桩工具 DexInjector

    本文介绍了一个针对Dex进行插桩的工具,讲解了一下直接修改Dalvik字节码和Dex文件时遇到的问题和解决方法 作者:字节跳动终端技术-- 李言 背景 线下场景中,我们经常需要在APK中插入一些检测代 ...

  8. CobaltStrike逆向学习系列(11):自实现 Beacon 检测工具

    这是[信安成长计划]的第 11 篇文章 关注微信公众号[信安成长计划] 0x00 目录 0x01 检测原理 0x02 检测方案 0x03 存在的问题 0x04 解决方案 0x05 示例代码 0x06 ...

  9. k8s集群搭建EFK日志平台:ElasticSearch + Fluentd + Kibana

    k8s集群 kubectl get node EFK简介 ElasticSearch:分布式存储检索引擎,用来搜索.存储日志 Fluentd:日志采集 Kibana:读取es中数据进行可视化web界面 ...

  10. windev中字符串分隔符的选择以及Contains使用技巧

    字符串分隔符,理论上可以使用任意符号,但作为数据保存,建议只使用以下三种: 1.:分号 2.TAB制表符 3.CR换行符 主要有以下几个原因: 1.组织架构组件,获得的组织路径,使用TAB键分隔,TA ...