首页 > 其他分享 >Spectre.Console-处理依赖注入

Spectre.Console-处理依赖注入

时间:2023-06-01 21:57:23浏览次数:40  
标签:依赖 Console Cli Spectre provider new public

引言

之前说的做自动记录 Todo 执行过程中消耗的时间的Todo 项目,由于想持续保持程序执行,就放弃了 Spectre.Console.Cli,后来随着命令越来越多,自己处理觉得很是麻烦,想了想要不试试怎么将这个东西嵌入程序,然后手动传递参数?

本文完整代码可以从项目中获取。

说干就干,研究了一下,发现核心的 CommandApp 并不需要独占的控制台,我们可以随时 new,参数直接将 ReadLine() 获得的参数传递 args 就可以了。

await _commandApp.RunAsync(cmd.Split(' '));

依赖注入问题

        static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();

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

最后一个是拓展方法:


internal static IServiceCollection AddCommandApp(this IServiceCollection services)
{
	return services.AddSingleton(w =>
	{
		var app = new CommandApp();
		app.Configure(config =>
		{
			config.CaseSensitivity(CaseSensitivity.None);
			config.AddBranch<MethodSettings>("del", del =>
			{
				del.SetDefaultCommand<DelCommand<TodoItem>>();
				del.AddCommand<DelCommand<TodoItem>>("todo");
				del.AddCommand<DelCommand<Project>>("pro");
				del.AddCommand<DelCommand<Tag>>("tag");
			});
		
		}
		return app;
	}
}

一切显得非常美好,但是棘手的问题就来了。Spectre.Console.Cli 自带依赖注入功能,会自动管理 Command 中的依赖关系,如果我们的 Command 需要依赖外部的类,那么需要在 Spectre.Console.Cli 中注册才能正常工作。但是这个东西也不自带注册器,我们在外部 DI 中注册的 TodoHolder 并没有什么用。

放弃 Host

虽然 Spectre.Console.Cli 不提供注册的办法,但是提供了一个构造函数,支持接受一个 ITypeRegistrar 作为参数,直接传递 IServiceCollection 就可以,这样在外部注册的类就传递进去了注册系统。官方提供了这个两个类的实现示例:

using Microsoft.Extensions.DependencyInjection;
using Spectre.Console.Cli;

namespace TodoTrack.Cli
{
    public sealed class TypeRegistrar : ITypeRegistrar
    {
        private readonly IServiceCollection _builder;

        public TypeRegistrar(IServiceCollection builder)
        {
            _builder = builder;
        }

        public ITypeResolver Build()
        {
            return new TypeResolver(_builder.BuildServiceProvider());
        }

        public void Register(Type service, Type implementation)
        {
            _builder.AddSingleton(service, implementation);
        }

        public void RegisterInstance(Type service, object implementation)
        {
            _builder.AddSingleton(service, implementation);
        }

        public void RegisterLazy(Type service, Func<object> func)
        {
            if (func is null)
            {
                throw new ArgumentNullException(nameof(func));
            }

            _builder.AddSingleton(service, (provider) => func());
        }
    }
}

using Spectre.Console.Cli;

namespace TodoTrack.Cli
{

    public sealed class TypeResolver : ITypeResolver, IDisposable
    {
        private readonly IServiceProvider _provider;

        public TypeResolver(IServiceProvider provider)
        {
            _provider = provider ?? throw new ArgumentNullException(nameof(provider));
        }

        public object? Resolve(Type? type)
        {
            if (type == null)
            {
                return null;
            }

            return _provider.GetService(type);
        }

        public void Dispose()
        {
            if (_provider is IDisposable disposable)
            {
                disposable.Dispose();
            }
        }
    }
}

CommandApp 的初始化语句还得改成这个形式:

    public static int Main(string[] args)
    {
        // Create a type registrar and register any dependencies.
        // A type registrar is an adapter for a DI framework.
        var registrations = new ServiceCollection();
        registrations.AddSingleton<IGreeter, HelloWorldGreeter>();
        var registrar = new TypeRegistrar(registrations);

        // Create a new command app with the registrar
        // and run it with the provided arguments.
        var app = new CommandApp<DefaultCommand>(registrar);
        return app.Run(args);
    }

这种方法放弃了 Host 创建 HostedService,依赖注入的行为会由 TypeRegistrarTypeResolver 控制。

修改注册器行为

由于 Spectre.Console.Cli 是依照 CLI 工具设计的,这类工具往往执行一次就自动退出返回控制台。因此它的注册器会在每次调用时重新创建 IServiceProvider,如果直接将其改成多次执行,我们会发现所有对象都会重新初始化一遍,和 AddSingleton 之类的行为不同。

修改注册器行为,将其作为一个长期运行的单例执行,这样我们可以继续使用拓展方法注册,并注入到 HostedService 中。

        public void Dispose()
        {
            //if (_provider is IDisposable disposable)
            //{
               // disposable.Dispose();
            //}
        }
        private ITypeResolver _typeResolver;

        public ITypeResolver Build()
        {
            return _typeResolver ??= new TypeResolver(_builder.BuildServiceProvider());
        }

这种方式下,外部的 DI 无法识别 CommandApp 内部注册的 Command 对象,使用时需要小心。

参考

标签:依赖,Console,Cli,Spectre,provider,new,public
From: https://www.cnblogs.com/podolski/p/17450308.html

相关文章

  • ROS2-Beginner:8-使用rqt_console来浏览日志
    目标:了解rqt_console,用于查看日志消息的工具。背景rqt_console是一个图形化工具用于查看ROS2中的日志消息。通常,日志消息在你个终端显示。用rqt_console,可以统一浏览这些日志,过滤、保存以及从文件中加载。任务1、启动rqt_consoleros2runrqt_consolerqt_console启动turt......
  • JVM-常用工具(jps、jstat、jinfo、jmap、jhat、jstack、jconsole、jvisualvm)使用
    场景记录JVM中常用工具。jps:虚拟机进程状态工具jps(JVMProcessStatusTool):虚拟机进程状态工具,可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(MainClass,main()函数所在的类)的名称,以及这些进程的本地虚拟机的唯一ID。命令格式:jps[options][hostid]示例:jps-l ......
  • TTY之register_console
    externvoidregister_console(structconsole*);externintunregister_console(structconsole*);externstructconsole*console_drivers;/**Theconsoledrivercallsthisroutineduringkernelinitialization*toregistertheconsoleprintingproced......
  • springboot整合log4j解决依赖冲突
    首先将web模块的日志排除<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion>......
  • 查看nebula版本号 console里show hosts graph
    (root@nebula)[(none)]>showhostsgraph+-------------+------+----------+---------+--------------+---------+|Host|Port|Status|Role|GitInfoSha|Version|+-------------+------+----------+---------+--------------+---------+|&q......
  • 神器vConsole!快速定位移动端问题,加快开发效率
    大家好,我是程序视点的小二哥!今天小二哥碰到一新来的实习生在使用alert调试H5页面,仿佛看到小二哥年少时羞涩的样子...趁这个机会,就给大家分享一个针对手机网页的前端开发者调试面板工具:vConsole简介vConsole是框架无关的,可以在Vue、React或其他任何框架中使用。现在vC......
  • Spectre.Console-实现自己的CLI
    引言最近发现自己喜欢用的Todo软件总是差点意思,毕竟每个人的习惯和工作流不太一样,我就想着自己写一个小的Todo项目,核心的功能是自动记录Todo执行过程中消耗的时间(尤其面向程序员),按照自己的想法实现一套GTD工作流。不想写Winform,WPF也写腻了,就想着学学MAUI、Avalonia......
  • AngularJS2.0 quick start——其和typescript结合需要额外依赖
    AngularJS2发布于2016年9月份,它是基于ES6来开发的。运行条件!由于目前各种环境(浏览器或Node)暂不支持ES6的代码,所以需要一些shim和polyfill(IE需要)让ES6写的代码能够转化为ES5形式并可以正常运行在浏览器中。从上图可以看出在Es5浏览器下需要以下模块加载器:systemjs -通用模块......
  • sql 求最小依赖集
    步骤1.右切,箭头右边只留一个字母2.除本身求闭包,假设去掉某个条件BCD->A(中的A),利用B,C,D在剩下的条件中求闭包,即求(BCD)+F=??    若闭包中不含有A,则保留这个条件;含有A即能推出(不需要BCD->A),删掉这个条件3.左部最小化,即尽可能压缩左边,例BCD->A,如看看BC能否推D,若能,改原条件......
  • dp-runtime去Kafka依赖方案
    背景现有原生kafkaconnectruntime,在客户环境运行遇到诸多问题,问题列表如下:强依赖Kafka集群做任务分配、connector配置信息、connector状态管理、source进度维护等等当遇到数据量大、并行数多,topic数量较多时,可能引发kakfa集群的不稳定包括(节点宕机,controller切换等)从而引......