欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

.NET Spectre.Console.Cli注入服務的幾種姿勢

freeflydom
2024年10月8日 15:41 本文熱度 692

Spectre.Console.NET程序員可能都不陌生,寫控制臺程序美化還是不錯的,支持著色,表格,圖標等相當Nice,如果對這個庫不熟悉我強烈推薦你了解一下,Spectre.Console.Cli作為Spectre.Console的子集,對于寫一些CLI小工具還是相當方便

本文主要講講 Spectre.Console.Cli的服務注入, TA是 Spectre.Console 庫的一部分,用于創建命令行界面(CLI)應用程序。TA提供了一個強大且易于使用的API來定義命令、參數和選項,同時支持 Spectre.Console 的豐富輸出格式化功能。

一個官方極簡的CLI例子,定義一個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"

大功告成:

轉自https://www.cnblogs.com/vipwan/p/18321432


該文章在 2024/10/8 15:41:54 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved