Asp.net Core 2.1 new function Generic Host (general host) deep learning

What is Generic Host?

image

 

This is the addition of a new Host in Asp. Net Core 2.1, and now in version 2.1, there are two available Hosts.

  • Web Host –Host for hosting Web programs is a common WebHost created in the Mai function of an Asp. Net Core application using CreateWebHostBuilder.

clip_image001

  • Generic Host (ASP.NET Core 2.1Version only) – suitable for hosting non Web applications (for example, running background tasks). In future releases, the universal host will be applicable to hosting any type of application, including Web applications. The universal host will eventually replace the Web host, which is probably the same type.The reason why hosts are called generic hosts is that in this blog, we’ll discuss how generic hosts work with source code.

Why use a universal host?

Generic hosts, which allow me to simplify the creation of console applications (personal opinions) by writing Asp. Net Core ideas (such as control inversion, dependency injection, IOC containers), are responsible for program startup and lifecycle management, which is useful for applications that don’t handle HTTP requestsThe order is very useful (Web applications handle HTTP requests, hosted by Web Host), and the goal of a generic host is to pull the HTTP pipeline out of Web Host so that the Asp. Net Core suite applies to other. Net Cores as well.E program.

Demodownload

Before you can follow me to analyze the universal host, you can download the official Demo at Github.

https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/host/generic-host/samples/

If you think downloading an entire one is slow, you can download it from my Github repository. There is no extra content. Domestic Github is slow. If you download it from the official repository, it may take a long time or even fail.

https://github.com/liuzhenyulive/Generic-Host-Demo

 

Generic Host Comparison with Web Host

First of all, you can download the official Demo and enter the Main function.

image

As you can see, this is a very compact version of the ASP. Net Core application, and you’re familiar with Asp. Net Core Web applications for all the methods that appear in this Main function, so I’m familiar with Asp. net core’s Web application.Host made a comparison to help you find the feeling.

General-purpose host WebHost
new HostBuilder() WebHost.CreateDefaultBuilder(args)
ConfigureAppConfiguration
(Used to configure Configuration)
WebHostThere is also this method, but you may not call it by default.
image
ConfigureServices
(Used to configure Service, that is, dependency injection.
WebHostIn fact, there are ConfigureServices methods that can be called.
image
But we rarely use this, and it’s usually placed in Startup’s ConfigureServices method for dependency injection.
ConfigureLogging
(Is the configuration, not necessary for this application.
WebHostOr do you have it!
image
builder.RunConsoleAsync()
image
RunConsoleAsyncIn fact, it is for hostbuilder.
BuilderThen Run
CreateWebHostBuilder(args).Build().Run();

That is, Build ().Run () in the Main function.


Nothing but nothing and nothing
StartupThe Configure () method in
Asp.net coreConfigure the Http request pipeline in this method.

 

To sum up, I have done the following summary.

  1. Generic Host has some Web Host.
  2. Web HostHttp Pipeline, Startup.Configure (), does not exist in the general host.

This should prove the beginning:The goal of a generic host is to separate the HTTP pipeline from Web Host so that the Asp. Net Core suite can be applied to other. Net Core programs.

How to use it?

RunFunction interpretation

I think to know how to use it, we first need to know what’s going on inside Host’s Run method.

So we go deep into the source code, all the way to F12!

builder.RunConsoleAsync(); =>hostBuilder.UseConsoleLifetime().Build().RunAsync(cancellationToken);=> await host.StartAsync(token);

Finally found, the most critical here.

public async Task StartAsync(CancellationToken cancellationToken = default (CancellationToken))
    {
      this._logger.Starting();
      TaskCompletionSource<object> completionSource1 = new TaskCompletionSource<object>();

      ref CancellationToken local = ref cancellationToken;
      TaskCompletionSource<object> completionSource2 = completionSource1;
      local.Register((Action<object>) (obj => ((TaskCompletionSource<object>) obj).TrySetCanceled()), (object) completionSource2);

      IHostLifetime hostLifetime1 = this._hostLifetime;
      TaskCompletionSource<object> completionSource3 = completionSource1;
      hostLifetime1.RegisterDelayStartCallback((Action<object>) (obj => ((TaskCompletionSource<object>) obj).TrySetResult((object) null)), (object) completionSource3);

      IHostLifetime hostLifetime2 = this._hostLifetime;
      ApplicationLifetime applicationLifetime = this._applicationLifetime;
      hostLifetime2.RegisterStopCallback((Action<object>) (obj => (obj as IApplicationLifetime)?.StopApplication()), (object) applicationLifetime);

      object task = await completionSource1.Task;
      

this._hostedServices = this.Services.GetService<IEnumerable<IHostedService>>(); foreach (IHostedService hostedService in this._hostedServices) await hostedService.StartAsync(cancellationToken).ConfigureAwait(false

);

      this._applicationLifetime?.NotifyStarted();
      this._logger.Started();
    }

 

Knowing that everyone likes the color Yellow, I’ve marked the most critical code with Yellow, so what does that mean?

this._hostedServices = this.Services.GetService<IEnumerable<IHostedService>>();

The meaning of this line is to remove all services that have implemented IHostedService from the container.

This means that after we have implemented the IHostedService, we need to register the Service into the IOC container.

foreach (IHostedService hostedService in this._hostedServices)
      await hostedService.StartAsync(cancellationToken).ConfigureAwait(false);

Perform the StartAsync method for each service.

So, did you guess how to use it?Laugh loudly.</p>
<p>The steps I have summarized are as follows:</p>
<ol>
<li>Customize a Service and inherit the IHostedService interface.</li>
<li>Implement the StartAsync method of IHostedService and put the tasks that need to be implemented in this method.</li>
<li>Register the service in the IOC container (ServiceCollection).</li>
</ol>
<h2>Custom task running</h2>
<h4>For steps 1 and 2, the corresponding code is as follows:</h4>
<div class=

public class PrintTextToConsoleService : IHostedService, IDisposable
    {
        private readonly ILogger _logger;
        private readonly IOptions<AppConfig> _appConfig;
        private Timer _timer;

        public PrintTextToConsoleService(ILogger<PrintTextToConsoleService> logger, IOptions<AppConfig> appConfig)
        {
            _logger = logger;
            _appConfig = appConfig;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Starting");

            _timer = new Timer(DoWork, null, TimeSpan.Zero,
                TimeSpan.FromSeconds(5));

            return Task.CompletedTask;
        }

        private void DoWork(object state)
        {
            _logger.LogInformation($"Background work with text: {_appConfig.Value.TextToPrint}");
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Stopping.");

            _timer?.Change(Timeout.Infinite, 0);

            return Task.CompletedTask;
        }

        public void Dispose()
        {
            _timer?.Dispose();
        }
    }

As you can see, in StartAsync, you define a timed task that executes the DoWork method every five seconds with a timed task.

In the DoWork method, the log logger records a paragraph.

Because in the Main method, Log is configured as follows.

image

So once log is recorded, the content will be output in the console.

For step 3, the corresponding code is as follows

public static async Task Main(string[] args)
        {
            var builder = new HostBuilder()    //Instantiate a universal host
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddJsonFile("appsettings.json", optional: true);
                    config.AddEnvironmentVariables();

                    if (args != null)
                    {
                        config.AddCommandLine(args);
                    }
                }) //Configure Configuration
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddOptions();
                    services.Configure<AppConfig>(hostContext.Configuration.GetSection("AppConfig"));
                    services.AddSingleton

<IHostedService, PrintTextToConsoleService>

();
                })    //Configure Service (dependency injection)
                .ConfigureLogging((hostingContext, logging) => {
                    logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                    logging.AddConsole();
                });   //Configure Log (in this project, use Log to output content in console).

            await builder.RunConsoleAsync();    //Running general host in console application
        }

The yellow part registers the PrintTextToConsoleService that implements the IHostedService interface into the container.

 

F5 Function

image

As you can see, every five seconds in the console, the content output indicates that the DoWork method is executed once every five seconds, and that StartAsync of the PrintTextToConsoleService is successfully invoked.

 

Hope this article can help you understand the general purpose host, if you are interested in. Net Core source analysis, new trend technology

Welcome to pay attention to me.

I will introduce practical work from time to time, thank you!

Reference

https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.1