|
Spectre.Console大家可能都不陌生,写控制台程序美化还是不错的,支持着色,表格,图标等相当nice,如果对这个库不熟悉我强烈推荐你了解一下,对于写一些CLI小工具还是相当方便的, 本文主要讲讲 Spectre.Console.Cli的服务注入, TA是 Spectre.Console 库的一部分,用于创建命令行界面(CLI)应用程序。它提供了一个强大且易于使用的API来定义命令、参数和选项,同时支持 Spectre.Console 的丰富输出格式化功能。
一个官方极简的例子,定义一个GreetCommand:- public class GreetCommand : Command<GreetCommand.Settings>
- {
- public class Settings : CommandSettings
- {
- [CommandArgument(0, "<name>")]
- [Description("The name of the person to greet.")]
- public string Name { get; set; }
- [CommandOption("-r|--repeat <times>")]
- [Description("The number of times to repeat the greeting.")]
- [DefaultValue(1)]
- public int Repeat { get; set; }
- }
- public override int Execute(CommandContext context, Settings settings)
- {
- for (int i = 0; i < settings.Repeat; i++)
- {
- Console.WriteLine($"Hello, {settings.Name}!");
- }
- return 0;
- }
- }
复制代码 接下来,在程序的入口点配置Command- public class Program
- {
- public static int Main(string[] args)
- {
- var app = new CommandApp();
- app.Configure(config =>
- {
- config.AddCommand<GreetCommand>("greet");
- });
- return app.Run(args);
- }
- }
复制代码 对于Spectre.Console.Cli的常规使用我这里不做过多介绍,感兴趣的同学可以移步官方文档,本文主要讲一下在CLI程序中如何注入服务
那么我们需要在GreetCommand中注入服务应该怎么做呢? 比如下面的一个服务:- public class HelloService(ILogger<HelloService> logger)
- {
- public Task<string> SayHello(string name, int age)
- {
- //注入的logger
- logger.LogInformation("SayHello called with name:{name},age:{age}", name, age);
- return Task.FromResult($"Hello,My name is {name}, I`m {age} years old!");
- }
- }
复制代码 其实Spectre.Console.Cli内置了最简单的方式,我们只需要在app.Configure中完成:- var services = new ServiceCollection();
- //添加服务
- services.AddSingleton<HelloService>();
- //添加日志
- services.AddLogging(config =>
- {
- config.AddConsole();
- });
- var sp = services.BuildServiceProvider();
- app.Configure(config =>
- {
- //添加Commands
- config.AddCommand<OneCommand>("one");
- config.AddCommand<AnotherCommand>("another");
- //注册Services
- config.Settings.Registrar.RegisterInstance(sp.GetRequiredService<HelloService>());
- });
复制代码 注册的服务就可以直接使用了:- public class HelloCommand(HelloService helloService) : AsyncCommand<HelloCommand.HelloSettings>
- {
- private readonly HelloService _helloService = helloService;
- public class HelloSettings : CommandSettings
- {
- [CommandArgument(0, "<name>")]
- [Description("The target to say hello to.")]
- public string Name { get; set; } = null!;
- }
- public override async Task<int> ExecuteAsync(CommandContext context, HelloSettings settings)
- {
- var message = await _helloService.SayHello(settings.Name, settings.Age);
- AnsiConsole.MarkupLine($"[blue]{message}[/]");
- return 0;
- }
- }
复制代码 另外的一个注入方式是实现ITypeRegistrar,官方提供MSDI的用例,自己也可以实现Autofac等其他DI,下面是MSDI的实现:- namespace Infrastructure
- {
- public sealed class MsDITypeRegistrar(IServiceCollection services) : ITypeRegistrar
- {
- private readonly IServiceCollection _services =
- services ?? throw new ArgumentNullException(nameof(services));
- public ITypeResolver Build()
- {
- return new TypeResolver(_services.BuildServiceProvider());
- }
- public void Register(Type service, Type implementation)
- {
- _services.AddSingleton(service, implementation);
- }
- public void RegisterInstance(Type service, object implementation)
- {
- _services.AddSingleton(service, implementation);
- }
- public void RegisterLazy(Type service, Func<object> factory)
- {
- _services.AddSingleton(service, (provider) => factory());
- }
- }
- internal sealed class TypeResolver(IServiceProvider provider) : ITypeResolver
- {
- public object? Resolve(Type? type)
- {
- if (provider is null || type is null)
- {
- return null;
- }
- return ActivatorUtilities.GetServiceOrCreateInstance(provider, type);
- }
- }
- }
复制代码 使用的话只需要实例化CommandApp时候传入MsDITypeRegistrar即可:- var services = new ServiceCollection();
- //添加服务...
- var app = new CommandApp(new MsDITypeRegistrar(services));
- app.Configure(config =>
- {
- //...
- });
- return app.Run(args);
复制代码 除了上面的方式,我们其实还可以使用ICommandInterceptor切面的方式来完成注入的操作:
下面我们定义一个AutoDIAttribute特性,实现一个AutoDIInterceptor的拦截器,后者主要给标记了AutoDI的属性服务赋值- [AttributeUsage(AttributeTargets.Property, Inherited = true)]
- public class AutoDIAttribute : Attribute{ }
- /// <summary>
- /// 自动注入的拦截器
- /// </summary>
- internal class AutoDIInterceptor(IServiceProvider serviceProvider) : ICommandInterceptor
- {
- public void Intercept(CommandContext context, CommandSettings settings)
- {
- var type = settings.GetType();
- var properties = type.GetProperties();
- foreach (var property in properties)
- {
- var isAutoInject = property.GetCustomAttributes<AutoDIAttribute>(true).Any();
- if (isAutoInject)
- {
- var service = ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, property.PropertyType);
- property.SetValue(settings, service);
- }
- }
- }
- }
复制代码 接下来在CommandSettings中标记需要自动注入服务的属性,如下面的HelloService:- internal class AutoDICommand : AsyncCommand<AutoDICommand.AnotherInjectSettings>
- {
- public class AnotherInjectSettings : CommandSettings
- {
- /// <summary>
- /// 使用切面装载的服务
- /// </summary>
- [AutoDI]
- public HelloService HelloService { get; set; } = null!;
- [Description("user name")]
- [DefaultValue("vipwan"), CommandOption("-n|--name")]
- public string Name { get; set; } = null!;
- [Description("user age")]
- [DefaultValue(12), CommandOption("-a|--age")]
- public int Age { get; set; }
- }
- public override async Task<int> ExecuteAsync(CommandContext context, AnotherInjectSettings settings)
- {
- var message = await settings.HelloService.SayHello(settings.Name, settings.Age);
- AnsiConsole.MarkupLine($"[green]{message}[/]");
- return 0;
- }
- }
复制代码 然后在app.Configure中使用AutoDIInterceptor切面:- var services = new ServiceCollection();
- //添加服务
- services.AddSingleton<HelloService>();
- var sp = services.BuildServiceProvider();
- app.Configure(config =>
- {
- //设置自动注入的拦截器
- config.SetInterceptor(new AutoDIInterceptor(sp));
- config.AddCommand<AutoDICommand>("di");
- //...
- });
复制代码 然后测试运行程序:- dotnet run -- di -n "vipwan"
复制代码 大功告成:
以上就介绍了几种在Spectre.Console.Cli注入服务的方式,当然没有最优的只有最适合自己的,如果代码存在不足,或者你有更好的建议 欢迎留言交流!
来源:https://www.cnblogs.com/vipwan/p/18321432
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|