Spectre.Console-处理依赖注入
引言
之前说的做自动记录 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,依赖注入的行为会由 TypeRegistrar 与 TypeResolver 控制。
修改注册器行为
由于 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 对象,使用时需要小心。
参考
Spectre.Console-处理依赖注入的更多相关文章
- ASP.NET Core 2.2 基础知识(一) 依赖注入
依赖: 类A用到了类B,我们就说类A依赖类B.如果一个类没有任何地方使用到,那这个类基本上可以删掉了. public class Test { private MyDependency md = ne ...
- Console app 里的依赖注入及其实例生命周期
依赖注入是 ASP.NET Core 里的核心概念之一,我们平常总是愉快地在Startup类的ConfigureServices方法里往IServiceCollection里注册各种类型,以致有一些同 ...
- .NET CORE——Console中使用依赖注入
我们都知道,在 ASP.NET CORE 中通过依赖注入的方式来使用服务十分的简单,而在 Console 中,其实也只是稍微绕了个小弯子而已.不管是内置 DI 组件或者第三方的 DI 组件(如Auto ...
- ASP.NET Core中如影随形的”依赖注入”[下]: 历数依赖注入的N种玩法
在对ASP.NET Core管道中关于依赖注入的两个核心对象(ServiceCollection和ServiceProvider)有了足够的认识之后,我们将关注的目光转移到编程层面.在ASP.NET ...
- ASP.NET Core中如影随形的”依赖注入”[上]: 从两个不同的ServiceProvider说起
我们一致在说 ASP.NET Core广泛地使用到了依赖注入,通过前面两个系列的介绍,相信读者朋友已经体会到了这一点.由于前面两章已经涵盖了依赖注入在管道构建过程中以及管道在处理请求过程的应用,但是内 ...
- 模拟AngularJS之依赖注入
一.概述 AngularJS有一经典之处就是依赖注入,对于什么是依赖注入,熟悉spring的同学应该都非常了解了,但,对于前端而言,还是比较新颖的. 依赖注入,简而言之,就是解除硬编码,达到解偶的目的 ...
- angular2系列教程(八)In-memory web api、HTTP服务、依赖注入、Observable
大家好,今天我们要讲是angular2的http功能模块,这个功能模块的代码不在angular2里面,需要我们另外引入: index.html <script src="lib/htt ...
- angularjs 依赖注入--自己学着实现
在用angular依赖注入时,感觉很好用,他的出现是 为了"削减计算机程序的耦合问题" ,我怀着敬畏与好奇的心情,轻轻的走进了angular源码,看看他到底是怎么实现的,我也想写个 ...
- 在.NET Core控制台程序中使用依赖注入
之前都是在ASP.NET Core中使用依赖注入(Dependency Injection),昨天遇到一个场景需要在.NET Core控制台程序中使用依赖注入,由于对.NET Core中的依赖注入机制 ...
- ASP.NET Core中的依赖注入(2):依赖注入(DI)
IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...
随机推荐
- 主机CPU散热器过重可能导致系统不稳定
CPU散热器越大,散热能力越强?其实散热器重量只是其中一个指标,还有风道设计也很重要.那么问题来了,为什么处理器散热器重量过重也可能导致系统运行不稳定? 本人用的配置为AMD R7 2700X 处理器 ...
- Go 语言:通过TDD驱动开发创建一个 Web 服务器,用户可以在其中跟踪玩家赢了多少场游戏。
你被要求创建一个 Web 服务器,用户可以在其中跟踪玩家赢了多少场游戏. GET /players/{name} 应该返回一个表示获胜总数的数字 POST /players/{name} 应该为玩 ...
- java开发技术栈如何选型
前言 2023泰山景区门票免费政策是从1月21日到3月31,今天4.1起不再免费啦,泰山的人.山和系统终于平安的渡劫过去! 洪峰时疯狂的抢票.各类攻击,分销MT两次凌晨抗洪事件,我及其我的团队又一次得 ...
- 图与网络分析—R实现(二)
图与网络 网络在各种实际背景问题中以各种各样的形式存在.交通.电子和通讯网络遍及我们日常生活的各个方面,网络规划也广泛用于解决不同领域中的各种问题,如生产.分配.项目计划.厂址选择.资源管理和财务策划 ...
- 自编写二进制安装kubernetes脚本v2.0版本
一键安装 二进制安装Kubernetes(k8s) v2.0 手动安装:https://github.com/cby-chen/Kubernetes 脚本安装:https://github.com/c ...
- PyCharm在Linux安装出现报错-Java Runtime (class file version 55.0)
在Linux桌面下安装PyCharm的时候出现如下报错 root@ubuntu:~# cd pycharm-community-2021.1.1 root@ubuntu:~/pycharm-commu ...
- 【SSM项目】尚筹网(五)项目改写:使用前后端分离的SpringSecurityJWT认证
在项目中加入SpringSecurity 1 加入依赖 <!-- SpringSecurity --> <dependency> <groupId>org.spri ...
- Ubuntu编译安装protobuf-3.6.1
一.下载源码包 下载源码URL:https://github.com/protocolbuffers/protobuf/releases/download/v3.6.1/protobuf-all-3. ...
- 迁移学习(CLDA)《CLDA: Contrastive Learning for Semi-Supervised Domain Adaptation》
论文信息 论文标题:CLDA: Contrastive Learning for Semi-Supervised Domain Adaptation论文作者:Ankit Singh论文来源:NeurI ...
- day01-项目介绍&功能实现
项目介绍&功能实现 1.项目介绍&环境搭建 一个以社交平台为核心的轻电商项目,功能如下: 短信登录.商户查询缓存.优惠券秒杀.达人探店.好友关注.附近的商户.用户签到.UV统计 1.1 ...