借助 .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. git rm 与 git rm --cached 的区别

    感谢原文作者:book_02 原文链接:https://www.jianshu.com/p/1c442fd398b7 git rm : 同时从工作区和索引中删除文件.即本地的文件也被删除了. git ...

  2. 设置程序启动时加载的storyboard

    这个设置表明:程序启动时会加载Main.storyboard

  3. python篇第6天【数据类型】

    Python有五个标准的数据类型: Numbers(数字) String(字符串) List(列表) Tuple(元组) Dictionary(字典) Python数字 数字数据类型用于存储数值. 他 ...

  4. Docker入门的亿点点学习

    前段时间花了些时间学习了亿点点docker,也算是入门了吧,顺便记了一下笔记拿出来分享给想要接触docker的兄弟们. 没有服务器的兄嘚可以去腾讯云或者阿里云领取免费的试用产品嗷,如果已经领取过了,又 ...

  5. js reduce累加器

    ​ reduce 是es6 新增的数组操作方法 意为累加器 使用方法如下 [1,1,1,1].reduce((total,currentValue,index)=>{ },initialValu ...

  6. 10、Linux基础--find、正则、文本过滤器grep

    笔记 1.晨考 1.每个月的3号.5号和15号,而且这天是星期六时执行 00 00 3,5,15 * 6 2.每天的3点到15点,每隔3分钟执行一次 */3 3-15 * * * 3.每周六早上2点半 ...

  7. Solution -「LOJ #6053」简单的函数

    \(\mathcal{Description}\)   Link.   积性函数 \(f\) 满足 \(f(p^c)=p\oplus c~(p\in\mathbb P,c\in\mathbb N_+) ...

  8. php发送邮件 (phpmailer)

    1.首先下载phpMailer文件官方文件https://sourceforge.net/projects/phpmailer/: 还有class.smtp.php. 2.去配置一下发送邮件的服务器, ...

  9. corn定时任务

    (1) Seconds Minutes Hours DayofMonth Month DayofWeek Year (2)Seconds Minutes Hours DayofMonth Month ...

  10. JavaScript ==原理与分析

    JavaScript原始类型 ECMAScript 有 5 种原始类型(primitive type),即 Undefined.Null.Boolean.Number 和 String. typeof ...