ASP.NET Core 一: 承载(主机),服务,依赖注入和控制反转,Windows服务

说明概念:

承载(Hosting),也叫做主机,相当于一个功能与资源的容器,持续运行,提供服务功能,承载能同时提供多个服务。(Microsoft.Extension.Hosting)

服务(Service),也就是实现的具体的功能。

依赖注入(DI),提供具体的对象的注入,由承载的框架注入,也包括注入服务,即实例化服务的同时可以为服务的构造函数参数提供已经实例化的对象。当然这里是可以嵌套的。

Windows服务,Windows的服务托管程序,可以托管各种Hosting,即在Windows启动的时候托管启动具体的应用承载服务而不用手动启动,可以通过打开任务管理器=》服务查看各种服务。.netFramwork有一个Windows服务编写的框架API。对于net core的承载程序可以调用.UseWindowsService()(Microsoft.Extension.Hosting.WindowsServices),然后按照正常的服务创建过程,用cmd命令创建Windows服务。

 托管的关系(这里暂且把程序关系都称为托管,也即提供启动过程或者),可以由这样的级联关系,服务功能托管到Host,发布的asp.net core web Host程序托管到iis,iis托管到windows服务。Web Host不一定要托管到IIS,也可以使用上面的.UseWindowsService()直接托管到Windows服务,使得Windows启动时直接启动Host应用程序。当然同一个应用程序下也可以同时运行多个承载。

参考资料

承载运行详解博客:[ASP.NET Core 3框架揭秘] 服务承载系统[1]: 承载长时间运行的服务[上篇] - Artech - 博客园 (cnblogs.com)

后台程序:在 ASP.NET Core 中使用托管服务实现后台任务 | Microsoft Docs

官方文档:ASP.NET Core 中的 .NET 通用主机 | Microsoft Docs

异步和多线程编程。

Composition编程

 

创建项目模板:

在Visual Studio可以通过创建【Worker Service】模板来创建承载的模板程序。这是一个基本的每秒计时程序,Worker是注入的具体的后台计时服务程序,运行时按下Ctrl+C退出运行

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });
    }

 

添加可运行的承载服务:

如果一个服务需要可运行,必须继承于IHostedService,例如上面的服务Worker所继承的类BackgroundService就是继承于IHostedService

 示例,顺便,这里_IContainer实例化到RunServiceDemo的过程就是依赖注入。

    public interface IContainer
    {
        string ContainerName { get; set; }
    }

    class MyContainer:IContainer
    {
        protected string containerName = "Custom my ontainer";

        public string ContainerName
        {
            get { return containerName; }
            set { containerName = value; }
        }
    }

 

    public class RunServiceDemo : IHostedService
    {
        private readonly IContainer _IContainer;

        public RunServiceDemo(IContainer container)//通过构造函数提供对象注入
        {
            _IContainer = container;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("程序开始-------" + _IContainer);
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("程序结束-------"+_IContainer);
            return Task.CompletedTask;
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }
        
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)//.UseWindowsService()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddTransient<IContainer, MyContainer>();//配置依赖注入关系

                    services.AddHostedService<RunServiceDemo>();//AddHostedService注入具体的服务
                });
    }

 

 多个服务:

模板自带后台计时服务类Worker

    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly IContainer _IContainer;

        public Worker(ILogger<Worker> logger,IContainer container)
        {
            _logger = logger;
            _IContainer = container;
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("work start at :{time}", DateTimeOffset.Now);
            return base.StartAsync(cancellationToken);
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation($"{_IContainer.ContainerName}  Worker running at: {DateTimeOffset.Now}");
                await Task.Delay(1000, stoppingToken);
            }
        }

        public override Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("work stop at :{time}", DateTimeOffset.Now);
            return base.StopAsync(cancellationToken);
        }
    }

Asp.net core后台计时服务示例类TimedHostedService

    public class TimedHostedService : IHostedService, IDisposable
    {
        private int executionCount = 0;
        private readonly ILogger<TimedHostedService> _logger;
        private Timer _timer;
        private readonly IContainer _IContaner;

        public TimedHostedService(ILogger<TimedHostedService> logger, IContainer container)
        {
            _logger = logger;
            _IContaner = container;
        }

        public Task StartAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Timed Hosted Service running.");

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

            return Task.CompletedTask;
        }

        private void DoWork(object state)
        {
            var count = Interlocked.Increment(ref executionCount);

            _logger.LogInformation(
                "Timed Hosted Service is working. Count: {Count}", count);
        }

        public Task StopAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Timed Hosted Service is stopping.");

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

            return Task.CompletedTask;
        }

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

 

同时把两个不同的计时服务注入到承载中

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }
        
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)//.UseWindowsService()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddTransient<IContainer, MyContainer>();//配置依赖注入关系

                    services.AddHostedService<RunServiceDemo>();
                    services.AddHostedService<TimedHostedService>();//注入计时服务
                    services.AddHostedService<Worker>();//注入计时
                });
    }

从运行结果可以看到,两个服务都在各自运行

 

 建立Windows服务

建立服务程序后,正常发布程序。然后使用SC命令建立Windows服务(命令窗口使用管理员启动)。如果是Linux系统,那么使用Microsoft.Extensions.Hosting.Systemd

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args).UseWindowsService()//需要调用UseWindowsService(),才能正常在Windows中正常启动服务
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddTransient<IContainer, MyContainer>();//配置依赖注入关系

                    services.AddHostedService<RunServiceDemo>();
                    services.AddHostedService<TimedHostedService>();//注入计时服务
                    services.AddHostedService<Worker>();//注入计时
                });

 

依赖注入和控制反转

网络上往往把这两个概念用大量的篇幅进行解释。导致读者看了一头雾水头大。这里我只想用简单的语言描述清楚。

依赖注入(DI):就是构造函数或者其他方法有一个参数,这个参数的实例化对象,并且调用方法或者构造函数的时候,使用这个对象作为参数的时候,即为依赖注入过程。再局限一些,就是类A类B,类A有一个属性或者成员是类B(即类A依赖于类B),实例化类A的时候要实例化一个类B的对象作为类A的属性或者成员,这里可以通过构造函数或者其他方法,这就是依赖注入过程。这也是我们编程过程中随时在做的事。

控制反转(IOC):就是依赖注入的整个过程是自动化的,这个自动化的过程就是控制反转。而实现这个自动化过程的工具这里称之为容器(IOC),也可以当作一个特殊的工厂类。

手动的依赖注入不在演示,平时编程都在使用,上面的IHoting里面已经内置了IOC容器,下面单独使用IOC类库来实现控制反转的过程。

 三个类A,B,C具有相互依赖关系

    public class A
    {
        private B _b;
        public A(B b)
        {
            this._b = b;
        }

        public override string ToString()
        {
            return "A" + "--->" + _b;
        }
    }


    public class B
    {
        public override string ToString()
        {
            return "B";
        }
    }


    public class C
    {
        private A _a;

        public C(A a)
        {
            _a = a;
        }

        public override string ToString()
        {
            return "C--->"+_a;
        }
    }

 

        public static void Main(string[] args)
        {
            var services = new ServiceCollection();
            services.AddTransient<A>();
            services.AddTransient<B>();
            services.AddTransient<C>();

            IServiceProvider serviceProvider = services.BuildServiceProvider();

            C c = serviceProvider.GetService<C>();//通过容器(Ioc)获取C的实例化对象
            Console.WriteLine("Hello "+c);
        }

 

 

 

posted @ 2021-10-06 02:50  小辉歌  阅读(267)  评论(0编辑  收藏  举报