项目框架构建之6:编写通用主机基础类

本文是“项目框架构建”系列之6,本文介绍如何编写通用主机基础类。

1.为了构建通用主机,我们先创建主机接口IAppHost接口

接口需要有配置项,我们定义为HostConfiguration,比如我们希望用户可以设定他的工作目录,就可以放在这里


接口需要有加载的.json的应用程序配置IConfiguration对象
接口还需要有服务管理器IServiceProvider对象
以及接口需要有日志管理ILoggerManager对象


2.构建主机,需要执行方法,所以我们添加了Build()和Run()两个方法
Build()方法是为了生成主机,这是必要方法。
Run()方法是为了启动应用程序,但这并不是必要的,因为主机生成后,您本身可以随时随地去启动你的程序。


3.生命周期以及事件

像主机这种底层结构,为了兼顾扩展性,我们需要提供周期的事件,以便让用户在启动的时候进行参与。


本程序抛砖引玉,提供了4个事件:
HostConfiguring:正在配置IConfiguration中,您可以继续加入其它初始化工作,如加载其它的.json文件
HostConfigurationInitialized:主机的配置已完成且抽象接口IConfiguration已构建
HostServicesInitializing:主机正在构建服务中,您可以继续加入其它服务一起构建
HostReady:主机构建完成已准备就绪


4.扩展依赖注入

为了防止重复添加服务,我们还需要扩展新增一些方法,用于防止重复添加服务。


5.扩展appsettings.cs文件的内容更改

程序运行后,有时可能需要在运行中修改appsettings.json中的配置,但IConfiguration本身不带有这种功能,所以我们需要自行编写扩展


6.编写主机接口IAppHost的抽象实现

我们是通用框架项目,所以需要提供一个抽象的基础实现,依据之前的设计,我们实现它的方法、事件、属性。

我们限定构造函数


程序初始化,初始化应用程序配置以及基础服务


编写Build()方法实现主机的生成


由于Run()函数不是必须的,所以我们把它定义为虚方法


 

下面通过编写事件的虚方法,以便子类能够参与过程

最后,附上完整的主机项目结构图:

也许各位朋友会想要源码,不要慌,等系列文章差不多了后,会开放源码下载。现在也没多少代码,没啥看头的。

下面附上IAppHost的具体实现:

using System;
using System.IO;
using Xejen.Hosting.Extensions;
using Xejen.Logger;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Xejen.Hosting
{
    /// <summary>
    /// <inheritdoc cref="IAppHost"/>基类 
    /// </summary>
    /// <creator>marc</creator>
    public abstract class AppHostBase : IAppHost
    {
        private readonly ILogger _logger;
        private readonly ILoggerManager _loggerManager;
        /// <inheritdoc cref="ILogger"/>
        protected ILogger Logger => _logger;

        /// <summary>
        /// 服务列表
        /// </summary>
        internal IServiceCollection Services;

        /// <inheritdoc cref="HostConfiguration"/>
        public HostConfiguration HostConfig { get; private set; }
        /// <inheritdoc/>
        public IConfiguration Configuration { get; private set; }
        /// <inheritdoc/>
        public IServiceProvider ServiceProvider { get; private set; }
        /// <inheritdoc/>
        public ILoggerManager LoggerManager => _loggerManager;

        /// <inheritdoc/>
        public event EventHandler<IConfigurationBuilder> HostConfiguring;
        /// <inheritdoc/>
        public event EventHandler<IConfiguration> HostConfigurationInitialized;
        /// <inheritdoc/>
        public event EventHandler<IServiceCollection> HostServicesInitializing;
        /// <inheritdoc/>
        public event EventHandler HostReady;

        /// <inheritdoc cref="AppHostBase"/>
        /// <param name="args">启动参数</param>
        /// <param name="loggerManager">采用的日志方式</param>
        protected AppHostBase(string[] args, ILoggerManager loggerManager) : this(loggerManager)
        {
            HostConfig = HostConfiguration.Load(args);

            Initialize();
        }

        /// <summary>
        /// 将 ILoggerManager 添加到构造函数中
        /// </summary>
        /// <param name="loggerManager"><inheritdoc cref="ILoggerManager" path="/summary"/></param>
        private AppHostBase(ILoggerManager loggerManager)
        {
            Check.NotNull(loggerManager, nameof(loggerManager));

            _loggerManager = loggerManager;
            _logger = _loggerManager.CreateLogger(typeof(AppHostBase));
        }

        /// <inheritdoc cref="AppHostBase"/>
        /// <param name="configuration"><inheritdoc cref="HostConfiguration" path="/summary"/></param>
        /// <param name="loggerManager"><inheritdoc cref="ILoggerManager" path="/summary"/></param>
        protected AppHostBase(HostConfiguration configuration, ILoggerManager loggerManager) : this(loggerManager)
        {
            Check.NotNull(configuration, nameof(configuration));

            HostConfig = configuration;

            Initialize();
        }

        private void Initialize()
        {
            _logger.LogInformation($"应用程始启动,开始初始化");

            InitializeConfiguration(HostConfig.ConfigDirectory);
            InitializeServices();
        }

        /// <inheritdoc/>
        public IAppHost Build()
        {
            ConfigureServices(Services);

            ServiceProvider = Services.BuildServiceProvider();

            _logger.LogInformation($"服务初始化完毕,共 {Services.Count} 项服务");

            _logger.LogInformation($"程序初始化完毕");

            OnHostReady(this);

            return this;
        }

        /// <inheritdoc/>
        public virtual void Run() { }

        private void InitializeConfiguration(string configDirectory)
        {
            _logger.LogInformation($"准备加载配置文件");
            if (string.IsNullOrEmpty(configDirectory))
            {
                configDirectory = AppDomain.CurrentDomain.BaseDirectory;
            }

            string appsettingFileName = HostConfig.DefaultSettingsFileName;
            if (!File.Exists(Path.Combine(configDirectory, appsettingFileName)))
            {
                throw new FileNotFoundException($"未找到 {appsettingFileName} 文件,查找目录在:\r\n{configDirectory}");
            }

            var builder = new ConfigurationBuilder()
                .SetBasePath(configDirectory)
                .AddJsonFile(appsettingFileName, optional: true, reloadOnChange: true);

            ConfigureJsonFiles(builder);

            OnHostConfiguring(this, builder);

            Configuration = builder.Build();

            OnHostConfigurationInitialized(this, Configuration);

            _logger.LogInformation($"配置文件加载完成,工作目录: {configDirectory}");
        }

        /// <summary>
        /// 配置json文件,基类已自动完成<see langword="appsettings.json"/>文件的加载,您只需加载您其它的配置文件即可
        /// </summary>
        /// <param name="configuration">传入过来的<see cref="IConfigurationBuilder"/>接口对象</param>
        protected virtual void ConfigureJsonFiles(IConfigurationBuilder configuration)
        {

        }

        /// <summary>
        /// 初始化基础服务
        /// </summary>
        private void InitializeServices()
        {
            _logger.LogInformation($"准备初始化服务");
            var services = new ServiceCollection();
            Services = services;

            // 添加服务
            // services.AddTransient<IService, ServiceImplementation>();
            // 添加主机服务:public class AppHostedService : IHostedService,该类要实现StartAsync以及StopAsync方法
            // services.AddHostedService<AppHostedService>();

            services.AddSingleton(_loggerManager);
            services.AddSingleton(Configuration);
            services.AddSingleton(HostConfig);

            OnHostServicesInitializing(this, services);
        }

        /// <summary>
        /// 配置服务,各子项目可以重写此方法来注册各项服务
        /// </summary>
        /// <param name="services">服务集合</param>
        protected virtual void ConfigureServices(IServiceCollection services)
        {

        }

        /// <inheritdoc cref="HostConfiguring" path="/summary"/>
        /// <param name="sender"><inheritdoc cref="IAppHost" path="/summary"/></param>
        /// <param name="builder">用于构建应用程序配置的构建器</param>
        protected virtual void OnHostConfiguring(IAppHost sender, IConfigurationBuilder builder)
        {
            HostConfiguring?.Invoke(sender, builder);
        }

        /// <inheritdoc cref="HostConfigurationInitialized" path="/summary"/>
        /// <param name="sender"><inheritdoc cref="IAppHost" path="/summary"/></param>
        /// <param name="builder">应用程序配置</param>
        protected virtual void OnHostConfigurationInitialized(IAppHost sender, IConfiguration builder)
        {
            HostConfigurationInitialized?.Invoke(sender, builder);
        }

        /// <inheritdoc cref="HostServicesInitializing" path="/summary"/>
        /// <param name="sender"><inheritdoc cref="IAppHost" path="/summary"/></param>
        /// <param name="builder">服务列表</param>
        protected virtual void OnHostServicesInitializing(IAppHost sender, IServiceCollection builder)
        {
            HostServicesInitializing?.Invoke(sender, builder);
        }

        /// <inheritdoc cref="HostReady" path="/summary"/>
        /// <param name="sender"><inheritdoc cref="IAppHost" path="/summary"/></param>
        protected virtual void OnHostReady(IAppHost sender)
        {
            HostReady?.Invoke(sender, EventArgs.Empty);
        }
    }
}

祝您用餐愉快,下一篇我们将编写如何使用主机框架的实际应用,敬请期待

1-3-5 $ 3-5-5-4 带着田螺回四堡 3-5-2-4

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/293194.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

GLEE:一个模型搞定目标检测/实例分割/定位/跟踪/交互式分割等任务!性能SOTA!

GLEE&#xff0c;这是一个面向目标级别的基础模型&#xff0c;用于定位和识别图像和视频中的目标。通过一个统一的框架&#xff0c;GLEE实现了对开放世界场景中任意目标的检测、分割、跟踪、定位和识别&#xff0c;适用于各种目标感知任务。采用了一种协同学习策略&#xff0c;…

C之BS开发

一、 BS 概述与 boa 搭建 1.1 BS 模式开发概述 BS 模式&#xff1a; 浏览器与服务器模式&#xff0c; 即通过浏览器访问服务器的 Web 资源。 1.1.1 web 前端开发技术 主要包含&#xff1a; HTML 、 CSS 、 XML/JSON 、 Javascript 、 AJAX HTML 超文本标记语言 ( 英文全称…

华为欧拉安装部署:Oracle11g

一、环境准备 1、下载安装低版本的libaio包&#xff1b;libaio版本太高&#xff0c;会造成编译错误 查看libaio1库版本不能大于0.3.109 [oracles3 install]$ rpm -qa libaio libaio-0.3.110-12.el8.x86_64# 查看欧拉操作系统版本 [oraclelocalhost bin]$ cat /etc/os-release…

stable diffusion 基础教程-提示词之艺术风格用法

展现夕阳 golden hour, (rim lighting):1.2, warm tones, sun flare, soft shadows, vibrant colors, hazy glow, painterly effect, dreamy atmosphere阴影 chiaroscuro, (high contrast):1.2, dramatic shadows, bold highlights, moody atmosphere, captivating inte…

5-sql注入之文件读写

文章目录 SQL注入之文件读写1、文件读写注入的原理2、文件读写注入的条件读取文件写入文件 SQL注入之文件读写 1、文件读写注入的原理 就是利用文件的读写权限进行注入&#xff0c;它可以写入一句话木马&#xff0c;也可以读取系统文件的敏感信息。 2、文件读写注入的条件 …

02 Deep learning algorithm

Neural Networks target&#xff1a; inference&#xff08;prediction&#xff09;training my own modelpractical advice for building machine learning systemdecision Tress application: speech&#xff08;语音识别&#xff09; ----> images(计算机视觉)—> t…

MS713/MS713T:CMOS 低压、4Ω四路单刀单掷开关,替代ADG713

产品简述 MS713/MS713T 是一款单芯片 CMOS 4 路可选择开关&#xff0c;具有低 功耗、高开关速度、低导通阻抗、低漏电和高带宽特性。其工作 电压范围是 1.8V 到 5.5V &#xff0c;可以广泛应用在电池供电仪器仪表、新 一代的模数转换和数模转换系统中。其高带宽特性可用在 …

代码+视频,手把手教你R语言使用forestploter包绘制单组及双组森林图

森林图在论文中很常见&#xff0c;多用于表示多因素分析中的变量与结果变量的比值效应&#xff0c;可以用图示的方法比较直观的绘制出来。既往我们在文章《R语言快速绘制多因素回归分析森林图&#xff08;1&#xff09;》已经介绍了怎么绘制森林图&#xff0c;但是绘图比较简单…

SecOC中新鲜度值和MAC都按照完整的值来生成,但是在发送和认证的时候只会截取一部分。这边截取的部分一般取多长?由什么参数设定?

新鲜度值(Freshness Value, FV)和消息验证码(Message Authentication Code, MAC)是SecOC协议中用于保证数据的真实性和新鲜度的重要信息。它们的长度取决于不同的因素,如加密算法、安全级别、通信带宽等。 一般来说,FV和MAC的长度越长,安全性越高,但也会占用更多的通信…

Docker随笔

OverView 为什么需要Docker 如果我需要部署一个服务&#xff0c;那么我需要提前部署其他应用栈&#xff0c;不同的应用栈会依赖于不用的操作系统和环境。这样做会产生一些负面影响&#xff1a; 不同版本依赖较长的部署时间不同的Dev/Test/Prod环境 这时我们需要一个工具去解…

JumpServer3.0版本-资产管理

资产列表 资产列表可展示资产树和类型树,可以查看添加的所有资产 新增资产也是在此页面 在资产树上面右键可以创建新的子节点 比如这里我新建了个“腾讯云”节点 选中腾讯云节点,点击中间的“创建”按钮,新增资产 选择你的主机类型,我这是Linux 填写你资产的名称、IP必…

Java Arrays.copyOfRange的用法

Arrays.copyOfRange的使用方法&#xff1a; 将一个数组拷贝至另一个数组中 参数&#xff1a; original&#xff1a;第一个参数为要拷贝的数组对象 from&#xff1a;第二个参数为拷贝的开始位置&#xff08;包含&#xff09; to&#xff1a;第三个参数为拷贝的结束位置&#x…

AIGC实战——自回归模型(Autoregressive Model)

AIGC实战——自回归模型 0. 前言1. 长短期记忆网络基本原理2. Recipes 数据集3. 处理文本数据3.1 文本与图像数据处理的差异3.2 文本数据处理步骤 4. 构建 LSTM 模型4.1 模型架构4.2 LSTM 计算流程4.3 训练 LSTM 5. LSTM 模型分析小结系列链接 0. 前言 自回归模型 (Autoregres…

【LMM 010】MiniGPT-v2:使用独特的标识符实现视觉语言多任务学习的统一的多模态大模型

论文标题&#xff1a;MiniGPT-v2: Large Language Model As a Unified Interface for Vision-Language Multi-task Learning 论文作者&#xff1a;Jun Chen, Deyao Zhu, Xiaoqian Shen, Xiang Li, Zechun Liu, Pengchuan Zhang, Raghuraman Krishnamoorthi, Vikas Chandra, Yun…

gitlab高级功能之Kubernetes Agent介绍

文章目录 1. 前置条件2. 简介3. GitLab Kubernetes Agent 的部署3.1 启用 Agent 服务端3.2 创建 Agent 配置和清单仓库 4. 安装agent4.1 连接k8s集群4.2 在集群中部署4.3 修改资源清淡&#xff0c;调整pod的副本数 5. 思考 1. 前置条件 gitlab 14.5 专业版k8s集群helm客户端工…

linux 使用iniparser读取.ini文件的配置信息

为什么要用项目配置文件 对于很多程序中要用的参数如果是可变的&#xff0c;那么最好的处理方式就是通过main(int argc,char **argv) 函数参数传递&#xff0c;或者从别的地方去获取&#xff0c;这其中之一就是配置文件&#xff0c;但是在一个成熟和架构完善的系统&#xff0c…

Spring的依赖注入(DI)

1.DI 概述&#xff1a;DI&#xff08;Dependency Injection&#xff09;依赖注入&#xff0c;在Spring创建对象的同时&#xff0c;为其属性赋值&#xff0c;称之为依赖注入。 1.1构造函数注入 顾名思义&#xff0c;就是使用类中的构造函数&#xff0c;给成员变量赋值。注意&…

ts相关笔记(基础必看)

推荐一下小册 TypeScript 全面进阶指南&#xff0c;此篇笔记来源于此&#xff0c;记录总结&#xff0c;加深印象&#xff01; 另外&#xff0c;如果想了解更多ts相关知识&#xff0c;可以参考我的其他笔记&#xff1a; vue3ts开发干货笔记TSConfig 配置&#xff08;tsconfig.…

安全cdn有哪些优势

1. 免备案&#xff1a;在中国大陆地区&#xff0c;进行网站建设需要先进行备案手续&#xff0c;而安全cdn可以避免这一繁琐的步骤&#xff0c;节省时间和精力。 2. 精品线路&#xff1a;安全cdn使用的是覆盖范围更广、速度更快的香港CN2 GIA优化线路。 3. 高速稳定&#xff1a…

Java多线程技术10——线程池ThreadPoolExecutor之Executor接口

1 概述 在开发服务器软件项目时&#xff0c;经常需要处理执行时间很短并且数据巨大的请求&#xff0c;如果为每一个请求创建一个新的线程&#xff0c;则会导致性能上的瓶颈。因为JVM需要频繁地处理线程对象的创建和销毁&#xff0c;如果请求的执行时间很短&#xff0c;则有可能…