IT教程 ·

[ASP.NET Core 3框架揭秘] 服务承载系统[2]: 承载长时间运行的服务[下篇]

快速学习的我该如何写好博客?

三、设置选项

真正的运用开发老是会运用到设置选项,如演示程序中机能目标网络的时候距离就应该采纳设置选项的体式格局来指定。由于触及对机能目标数据的发送,所以最好将发送的目标地点定义在设置选项中。假如有多种传输协定可供挑选,就能够定义响应的设置选项。.NET Core运用引荐采纳Options情势来运用设置选项,所以能够定义以下这个MetricsCollectionOptions范例来承载3种设置选项。

public class MetricsCollectionOptions
{
    public TimeSpan CaptureInterval { get; set; }
    public TransportType Transport { get; set; }
    public Endpoint DeliverTo { get; set; }
}

public enum TransportType
{
    Tcp,
    Http,
    Udp
}

public class Endpoint
{
    public string Host { get; set; }
    public int Port { get; set; }
    public override string ToString() => $"{Host}:{Port}";
}

传输协定和目标地点运用在FakeMetricsDeliverer效劳中,所以我们对它举行了响应的改写。以下面的代码片断所示,我们在组织函数中经由过程注入的IOptions<MetricsCollectionOptions>效劳来供应上面的两个设置选项。在完成的DeliverAsync要领中,能够将采纳的传输协定和目标地点输出到掌握台上。

public class FakeMetricsDeliverer : IMetricsDeliverer
{
    private readonly TransportType     _transport;
    private readonly Endpoint     _deliverTo;

    public FakeMetricsDeliverer(IOptions<MetricsCollectionOptions> optionsAccessor)
    {
        var options     = optionsAccessor.Value;
        _transport     = options.Transport;
        _deliverTo     = options.DeliverTo;
    }

    public Task DeliverAsync(PerformanceMetrics counter)
    {
        Console.WriteLine($"[{DateTimeOffset.Now}]Deliver performance counter {counter} to {_deliverTo} via {_transport}");
        return Task.CompletedTask;
    }
}

与FakeMetricsDeliverer提取设置选项相似,在承载效劳范例PerformanceMetricsCollector中一样能够采纳Options情势来供应示意机能目标网络频次的设置选项。以下所示的代码片断是PerformanceMetricsCollector采纳设置选项后的完全定义。

public sealed class PerformanceMetricsCollector : IHostedService
{
    private readonly IProcessorMetricsCollector _processorMetricsCollector;
    private readonly IMemoryMetricsCollector _memoryMetricsCollector;
    private readonly INetworkMetricsCollector _networkMetricsCollector;
    private readonly IMetricsDeliverer _metricsDeliverer;
    private readonly TimeSpan _captureInterval;
    private IDisposable _scheduler;

    public PerformanceMetricsCollector(
        IProcessorMetricsCollector processorMetricsCollector,
        IMemoryMetricsCollector memoryMetricsCollector,
        INetworkMetricsCollector networkMetricsCollector,
        IMetricsDeliverer metricsDeliverer,
        IOptions<MetricsCollectionOptions> optionsAccessor)
    {
        _processorMetricsCollector = processorMetricsCollector;
        _memoryMetricsCollector = memoryMetricsCollector;
        _networkMetricsCollector = networkMetricsCollector;
        _metricsDeliverer = metricsDeliverer;
        _captureInterval = optionsAccessor.Value.CaptureInterval;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _scheduler = new Timer(Callback, null, TimeSpan.FromSeconds(5), _captureInterval);
        return Task.CompletedTask;

        async void Callback(object state)
        {
            var counter = new PerformanceMetrics
            {
                Processor = _processorMetricsCollector.GetUsage(),
                Memory = _memoryMetricsCollector.GetUsage(),
                Network = _networkMetricsCollector.GetThroughput()
            };
            await _metricsDeliverer.DeliverAsync(counter);
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _scheduler?.Dispose();
        return Task.CompletedTask;
    }
}

运用设置文件能够供应上述3个设置选项,所以我们在根目次下增加了一个名为appSettings.json的设置文件。由于演示的运用程序采纳的SDK范例为“Microsoft.NET.Sdk”,程序运转过程当中会将编译程序集的目标目次作为当前目次,所以须要将设置文件的“Copy to output directory”属性设置为“Copy always”,如许能够确保它在编译时老是被复制到目标目次。我们经由过程在设置文件中定义以下内容来供应上述3个设置选项。

{
  "MetricsCollection": {
    "CaptureInterval": "00:00:05",
    "Transport": "Udp",
    "DeliverTo": {
      "Host": "192.168.0.1",
      "Port": 3721
    }
  }
}

下面针对设置选项的运用对演示程序做响应的修正。以下面的代码片断所示,我们挪用了IHostBuilder对象的ConfigureAppConfiguration要领,并应用供应的Action<IConfigurationBuilder>对象注册了指向设置文件appsettings.json的JsonConfigurationSource对象。从称号能够看出,ConfigureAppConfiguration要领的目标在于初始化运用程序所需的设置。

class Program
{
    static void Main()
    {
        var collector = new FakeMetricsCollector();
        new HostBuilder()
            .ConfigureAppConfiguration(builder=>builder.AddJsonFile("appsettings.json"))
            .ConfigureServices((context,svcs) => svcs
                .AddSingleton<IProcessorMetricsCollector>(collector)
                .AddSingleton<IMemoryMetricsCollector>(collector)
                .AddSingleton<INetworkMetricsCollector>(collector)
                .AddSingleton<IMetricsDeliverer, FakeMetricsDeliverer>()
                .AddSingleton<IHostedService, PerformanceMetricsCollector>()

                .AddOptions()
                .Configure<MetricsCollectionOptions>(context.Configuration.GetSection("MetricsCollection")))                
            .Build()
            .Run();
    }
}

之前针对依靠效劳的注册是经由过程挪用IHostBuilder对象的ConfigureServices要领应用作为参数的Action<IServiceCollection>对象完成的,IHostBuilder接口另有一个ConfigureServices要领重载,它的参数范例为Action<HostBuilderContext, IServiceCollection>,作为上下文的HostBuilderContext对象能够供应运用的设置,我们在上面挪用的就是ConfigureServices要领重载。

如上面的代码片断所示,我们应用供应的Action<HostBuilderContext, IServiceCollection>对象经由过程挪用IServiceCollection接口的AddOptions扩大要领注册了Options情势所需的中心效劳,然后挪用Configure<TOptions>扩大要领从供应的HostBuilderContext对象中提掏出当前运用的设置,并将它和对应的设置选项范例MetricsCollectionOptions做了绑定。我们修正后的程序运转以后在掌握台上输出的效果以下图所示,能够看出,输出的效果与设置文件的内容是婚配的。(源代码从下载)

四、承载环境

运用程序老是针对某个详细的环境举行布置,开发(Development)、预发(Staging)和产物(Production)是3种典范的布置环境。这里的布置环境在承载体系中统称为承载环境(Hosting Environment)。一般来讲,差别的承载环境每每具有差别的设置选项,下面演示如作甚差别的承载环境供应响应的设置选项。

《》已演示了怎样供应针对详细环境的设置文件,详细的做法很简单:将同享或许默许的设置定义在基本设置文件(如appsettings.json)中,将差异化的部份定义在针对详细承载环境的设置文件(如appsettings.staging.json和appsettings.production.json)中。关于我们演示的实例来讲,能够采纳以下图所示的体式格局增加分外的两个设置文件来供应针对预发和产物环境的差异化设置。

关于演示实例供应的3个设置选项来讲,假定针对承载环境的差异化合营仅限于发送的目标终结点(IP地点和端口),就能够采纳以下体式格局将它们定义在针对预发环境的appsettings.staging.json和针对产物环境的appsettings.production.json中。

appsettings.staging.json

{
  "MetricsCollection": {
    "DeliverTo": {
      "Host": "192.168.0.2",
      "Port": 3721
    }
  }
}

appsettings.production.json

{
  "MetricsCollection": {
    "DeliverTo": {
      "Host": "192.168.0.2",
      "Port": 3721
    }
  }
}

在供应了针对详细承载环境的设置文件以后,还须要处理两个问题:第一,怎样将它们注册到运用采纳的设置框架中;第二,怎样肯定当前的承载环境。前者能够挪用IHostBuilder接口的ConfigureAppConfiguration要领来完成,从定名能够看出,这个要领注册的是针对“运用”层面的设置。我们能够将这里所谓的“运用”理解为承载的效劳,也就是说,采纳这类体式格局注册的设置是为承载的效劳运用的。实际上,IHostBuilder接口另有一个ConfigureHostConfiguration要领,它注册的效劳是供效劳宿主(Host)本身运用的,而当前的承载环境就能够应用此设置来指定。

我们将上述这两个问题的处理方案完成在改写的程序中。以下面的代码片断所示,为了使演示的运用程序能够采纳命令行的情势来指定承载环境,能够挪用HostBuilder接口的ConfigureHostConfiguration要领,并应用供应的Action<IConfigurationBuilder>对象注册了针对命令行的设置源。为了注册针对承载环境的设置,能够挪用范例为Action<HostBuilderContext, IConfigurationBuilder>的ConfigureAppConfiguration要领,由于我们须要HostBuilderContext上下文对象获得当前的承载环境。

class Program
{
    static void Main(string[] args)
    {
        var collector = new FakeMetricsCollector();
        new HostBuilder()
            .ConfigureHostConfiguration(builder => builder.AddCommandLine(args))
            .ConfigureAppConfiguration((context, builder) => builder
                .AddJsonFile(path: "appsettings.json", optional: false)
                .AddJsonFile(
                    path: $"appsettings.{context.HostingEnvironment.EnvironmentName}.json", 
                    optional: true))
            .ConfigureServices((context, svcs) => svcs
                .AddSingleton<IProcessorMetricsCollector>(collector)
                .AddSingleton<IMemoryMetricsCollector>(collector)
                .AddSingleton<INetworkMetricsCollector>(collector)
                .AddSingleton<IMetricsDeliverer, FakeMetricsDeliverer>()
                .AddSingleton<IHostedService, PerformanceMetricsCollector>()

                .AddOptions()
                .Configure<MetricsCollectionOptions>(context.Configuration.GetSection("MetricsCollection")))
            .Build()
            .Run();
    }
}

我们挪用ConfigureAppConfiguration要领注册了两个设置文件:一个是承载基本或许默许设置的appsettings.json文件,另一个是针对当前承载环境的appsettings.{environment}.json文件。前者是必须的,后者是可选的,如许做的目标在于确保纵然当前承载环境不存在对应设置文件的状况也不会抛出非常(此时运用只会运用appsettings.json文件中定义的设置)。

下面以命令行的情势运转修正后的运用程序,承载环境经由过程命令行参数environment来指定。下图是前后4次运转演示实例获得的输出效果,从输出的IP地点能够看出,运用程序确实是依据当前承载环境加载对应的设置文件的。输出效果还表现了另一个细节:运用程序默许运用的是产物(Production)环境。(源代码从下载)

五、日记

在详细的运用开发时不可防止地会触及许多针对“诊断日记”的编程,下面演示在经由过程承载体系承载的运用中怎样纪录日记。关于演示实例来讲,它用于发送机能目标的FakeMetricsDeliverer对象会将网络的目标数据输出到掌握台上,下面将这段笔墨以日记的情势举行输出,为此我们将这个范例举行了以下改写。

public class FakeMetricsDeliverer : IMetricsDeliverer
{
    private readonly TransportType _transport;
    private readonly Endpoint _deliverTo;
    private readonly ILogger _logger;
    private readonly Action<ILogger, DateTimeOffset, PerformanceMetrics, Endpoint, TransportType, Exception> _logForDelivery;

    public FakeMetricsDeliverer(IOptions<MetricsCollectionOptions> optionsAccessor, ILogger<FakeMetricsDeliverer> logger)
    {
        var options = optionsAccessor.Value;
        _transport = options.Transport;
        _deliverTo = options.DeliverTo;
        _logger = logger;
        _logForDelivery = LoggerMessage.Define<DateTimeOffset, PerformanceMetrics, Endpoint, TransportType>(LogLevel.Information, 0, "[{0}]Deliver performance counter {1} to {2} via {3}");
    }

    public Task DeliverAsync(PerformanceMetrics counter)
    {
        _logForDelivery(_logger, DateTimeOffset.Now, counter, _deliverTo, _transport, null);
        return Task.CompletedTask;
    }
}

如上面的代码片断所示,我们直接在组织函数中注入了ILogger<FakeMetricsDeliverer>对象并应用它来纪录日记。为了防止对同一个音讯模板的反复剖析,能够运用静态范例LoggerMessage供应的托付对象来输出日记,这也是FakeMetricsDeliverer中采纳的编程情势。为了将日记框架引入运用程序,我们须要在初始化运用时注册响应的效劳,为此须要将运用程序做响应的改写。以下面的代码片断所示,我们挪用IHostBuilder接口的ConfigureLogging扩大要领注册了日记框架的中心效劳,并应用供应的Action<ILoggingBuilder>对象注册了针对掌握台作为输出渠道的ConsoleLoggerProvider。

class Program
{
    static void Main(string[] args)
    {
        var collector = new FakeMetricsCollector();
        new HostBuilder()
            .ConfigureHostConfiguration(builder => builder.AddCommandLine(args))
            .ConfigureAppConfiguration((context, builder) => builder
                .AddJsonFile(path: "appsettings.json", optional: false)
                .AddJsonFile( path: $"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true))
            .ConfigureServices((context, svcs) => svcs
                .AddSingleton<IProcessorMetricsCollector>(collector)
                .AddSingleton<IMemoryMetricsCollector>(collector)
                .AddSingleton<INetworkMetricsCollector>(collector)
                .AddSingleton<IMetricsDeliverer, FakeMetricsDeliverer>()
                .AddSingleton<IHostedService, PerformanceMetricsCollector>()

                .AddOptions()
                .Configure<MetricsCollectionOptions>(context.Configuration.GetSection("MetricsCollection")))
             .ConfigureLogging(builder => builder.AddConsole())
            .Build()
            .Run();
    }
}

再次运转修正后的程序,掌握台上的输出效果以下图所示。由输出效果能够看出,这些笔墨是由我们注册的ConsoleLoggerProvider供应的ConsoleLogger对象输出到掌握台上的。由于承载体系本身在举行效劳承载过程当中也会输出一些日记,所以它们也会输出到掌握台上。

假如对输出的日记举行过滤,能够将过滤划定规矩定义在设置文件中。假定关于种别以Microsoft.为前缀的日记,我们只愿望品级不低于Warning的才会被输出,如许会防止太多的音讯被输出到掌握台上造成对机能的影响,所以能够将产物环境对应的appsettings.production.json文件的内容做以下修正。

{
  "MetricsCollection": {
    "DeliverTo": {
      "Host": "192.168.0.3",
      "Port": 3721
    }
  },
  "Logging": {
    "LogLevel": {
      "Microsoft": "Warning"
    }
  }
}

为了运用日记设置,我们还须要对运用程序做响应的修正。以下面的代码片断所示,在对ConfigureLogging扩大要领的挪用中,能够应用HostBuilderContext上下文对象获得当前设置,进而获得名为Logging的设置节。我们将这个设置节作为参数挪用ILoggingBuilder对象的AddConfiguration扩大要领将承载的过滤划定规矩运用到日记框架上。

class Program
{
    static void Main(string[] args)
    {
        var collector = new FakeMetricsCollector();
        new HostBuilder()
            .ConfigureHostConfiguration(builder => builder.AddCommandLine(args))
            .ConfigureAppConfiguration((context, builder) => builder
                .AddJsonFile(path: "appsettings.json", optional: false)
                .AddJsonFile(
                    path: $"appsettings.{context.HostingEnvironment.EnvironmentName}.json", 
                    optional: true))
            .ConfigureServices((context, svcs) => svcs
                .AddSingleton<IProcessorMetricsCollector>(collector)
                .AddSingleton<IMemoryMetricsCollector>(collector)
                .AddSingleton<INetworkMetricsCollector>(collector)
                .AddSingleton<IMetricsDeliverer, FakeMetricsDeliverer>()
                .AddSingleton<IHostedService, PerformanceMetricsCollector>()

                .AddOptions()
                .Configure<MetricsCollectionOptions>(context.Configuration.GetSection("MetricsCollection")))
             .ConfigureLogging((context,builder) => builder
                .AddConfiguration(context.Configuration.GetSection("Logging"))
                .AddConsole())
            .Build()
            .Run();
    }
}

假如此时离别针对开发(Development)环境和产物(Production)环境以命令行的情势启动修正后的运用程序,就会发明针对开发环境掌握台上会输出范例前缀为“Microsoft.”的日记,然则针对产物环境的掌握台上却找不到它们的踪迹。

 

小白学 Python 数据分析(10):Pandas (九)数据运算

参与评论