温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何使用.Net Core编写命令行工具

发布时间:2021-06-11 15:19:09 来源:亿速云 阅读:317 作者:小新 栏目:开发技术

这篇文章将为大家详细讲解有关如何使用.Net Core编写命令行工具,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

命令行工具(CLI)

  命令行工具(CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。

  通常认为,命令行工具(CLI)没有图形用户界面(GUI)那么方便用户操作。因为,命令行工具的软件通常需要用户记忆操作的命令,但是,由于其本身的特点,命令行工具要较图形用户界面节约计算机系统的资源。在熟记命令的前提下,使用命令行工具往往要较使用图形用户界面的操作速度要快。所以,图形用户界面的操作系统中,都保留着可选的命令行工具。

  另外,命令行工具(CLI)应该是一个开箱即用的工具,不需要安装任何依赖。

  一些熟悉的CLI工具如下:

  1. dotnet cli

  2. vue cli

  3.angular cli

  4. aws cli

  5.azure cli

指令设计

  本文将使用.Net Core(版本3.1.102)编写一个CLI工具,实现配置管理以及条目(item)管理(调用WebApi实现),详情如下:

  如何使用.Net Core编写命令行工具

框架说明

  编写CLI使用的主要框架是CommandLineUtils,它主要有以下优势:

  1. 良好的语法设计

  2. 支持依赖注入

  3. 支持generic host

WebApi

  提供api让cli调用,实现条目(item)的增删改查:

[Route("api/items")] [ApiController] public class ItemsController : ControllerBase {   private readonly IMemoryCache _cache;   private readonly string _key = "items";   public ItemsController(IMemoryCache memoryCache)   {     _cache = memoryCache;   }   [HttpGet]   public IActionResult List()   {     var items = _cache.Get<List<Item>>(_key);     return Ok(items);   }   [HttpGet("{id}")]   public IActionResult Get(string id)   {     var item = _cache.Get<List<Item>>(_key).FirstOrDefault(n => n.Id == id);     return Ok(item);   }   [HttpPost]   public IActionResult Create(ItemForm form)   {     var items = _cache.Get<List<Item>>(_key) ?? new List<Item>();     var item = new Item     {       Id = Guid.NewGuid().ToString("N"),       Name = form.Name,       Age = form.Age     };     items.Add(item);     _cache.Set(_key, items);          return Ok(item);   }   [HttpDelete("{id}")]   public IActionResult Delete(string id)   {     var items = _cache.Get<List<Item>>(_key);     var item = items?.SingleOrDefault(n => n.Id == id);     if (item == null)     {       return NotFound();     }     items.Remove(item);     _cache.Set(_key, items);     return Ok();   } }

CLI

  1. Program - 函数入口

[HelpOption(Inherited = true)] //显示指令帮助,并且让子指令也继承此设置 [Command(Description = "A tool to communicate with web api"), //指令描述  Subcommand(typeof(ConfigCommand), typeof(ItemCommand))] //子指令 class Program {   public static int Main(string[] args)   {     //配置依赖注入     var serviceCollection = new ServiceCollection();     serviceCollection.AddSingleton(PhysicalConsole.Singleton);     serviceCollection.AddSingleton<IConfigService, ConfigService>();     serviceCollection.AddHttpClient<IItemClient, ItemClient>();     var services = serviceCollection.BuildServiceProvider();     var app = new CommandLineApplication<Program>();     app.Conventions       .UseDefaultConventions()       .UseConstructorInjection(services);     var console = (IConsole)services.GetService(typeof(IConsole));     try     {       return app.Execute(args);     }     catch (UnrecognizedCommandParsingException ex) //处理未定义指令     {       console.WriteLine(ex.Message);       return -1;     }   }   //指令逻辑   private int OnExecute(CommandLineApplication app, IConsole console)   {     console.WriteLine("Please specify a command.");     app.ShowHelp();     return 1;   } }

  2. ConfigCommand和ItemCommand - 实现的功能比较简单,主要是指令描述以及指定对应的子指令

[Command("config", Description = "Manage config"),  Subcommand(typeof(GetCommand), typeof(SetCommand))] public class ConfigCommand {   private int OnExecute(CommandLineApplication app, IConsole console)   {     console.Error.WriteLine("Please submit a sub command.");     app.ShowHelp();     return 1;   } } [Command("item", Description = "Manage item"),  Subcommand(typeof(CreateCommand), typeof(GetCommand), typeof(ListCommand), typeof(DeleteCommand))] public class ItemCommand {   private int OnExecute(CommandLineApplication app, IConsole console)   {     console.Error.WriteLine("Please submit a sub command.");     app.ShowHelp();     return 1;   } }

  3.ConfigService - 配置管理的具体实现,主要是文件读写

public interface IConfigService {   void Set();   Config Get(); } public class ConfigService: IConfigService {   private readonly IConsole _console;   private readonly string _directoryName;   private readonly string _fileName;   public ConfigService(IConsole console)   {     _console = console;     _directoryName = ".api-cli";     _fileName = "config.json";   }   public void Set()   {     var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), _directoryName);     if (!Directory.Exists(directory))     {       Directory.CreateDirectory(directory);     }     var config = new Config     {       //弹出交互框,让用户输入,设置默认值为http://localhost:5000/       Endpoint = Prompt.GetString("Specify the endpoint:", "http://localhost:5000/")     };     if (!config.Endpoint.EndsWith("/"))     {       config.Endpoint += "/";     }     var filePath = Path.Combine(directory, _fileName);     using (var outputFile = new StreamWriter(filePath, false, Encoding.UTF8))     {       outputFile.WriteLine(JsonConvert.SerializeObject(config, Formatting.Indented));     }     _console.WriteLine($"Config saved in {filePath}.");   }   public Config Get()   {     var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), _directoryName, _fileName);     if (File.Exists(filePath))     {       var content = File.ReadAllText(filePath);       try       {         var config = JsonConvert.DeserializeObject<Config>(content);         return config;       }       catch       {         _console.WriteLine("The config is invalid, please use 'config set' command to reset one.");       }     }     else     {       _console.WriteLine("Config is not existed, please use 'config set' command to set one.");     }     return null;   } }

  4.ItemClient - 调用Web Api的具体实现,使用HttpClientFactory的方式

public interface IItemClient {   Task<string> Create(ItemForm form);   Task<string> Get(string id);   Task<string> List();   Task<string> Delete(string id); } public class ItemClient : IItemClient {   public HttpClient Client { get; }   public ItemClient(HttpClient client, IConfigService configService)   {     var config = configService.Get();     if (config == null)     {       return;     }     client.BaseAddress = new Uri(config.Endpoint);     Client = client;   }   public async Task<string> Create(ItemForm form)   {     var content = new StringContent(JsonConvert.SerializeObject(form), Encoding.UTF8, "application/json");     var result = await Client.PostAsync("/api/items", content);     if (result.IsSuccessStatusCode)     {       var stream = await result.Content.ReadAsStreamAsync();       var item = Deserialize<Item>(stream);       return $"Item created, info:{item}";     }     return "Error occur, please again later.";   }   public async Task<string> Get(string id)   {     var result = await Client.GetAsync($"/api/items/{id}");     if (result.IsSuccessStatusCode)     {       var stream = await result.Content.ReadAsStreamAsync();       var item = Deserialize<Item>(stream);       var response = new StringBuilder();       response.AppendLine($"{"Id".PadRight(40, ' ')}{"Name".PadRight(20, ' ')}Age");       response.AppendLine($"{item.Id.PadRight(40, ' ')}{item.Name.PadRight(20, ' ')}{item.Age}");       return response.ToString();     }     return "Error occur, please again later.";   }   public async Task<string> List()   {     var result = await Client.GetAsync($"/api/items");     if (result.IsSuccessStatusCode)     {       var stream = await result.Content.ReadAsStreamAsync();       var items = Deserialize<List<Item>>(stream);       var response = new StringBuilder();       response.AppendLine($"{"Id".PadRight(40, ' ')}{"Name".PadRight(20, ' ')}Age");       if (items != null && items.Count > 0)       {         foreach (var item in items)         {           response.AppendLine($"{item.Id.PadRight(40, ' ')}{item.Name.PadRight(20, ' ')}{item.Age}");         }       }              return response.ToString();     }     return "Error occur, please again later.";   }   public async Task<string> Delete(string id)   {     var result = await Client.DeleteAsync($"/api/items/{id}");     if (result.IsSuccessStatusCode)     {       return $"Item {id} deleted.";     }     if (result.StatusCode == HttpStatusCode.NotFound)     {       return $"Item {id} not found.";     }     return "Error occur, please again later.";   }   private static T Deserialize<T>(Stream stream)   {     using var reader = new JsonTextReader(new StreamReader(stream));     var serializer = new JsonSerializer();     return (T)serializer.Deserialize(reader, typeof(T));   } }

如何发布

  在项目文件中设置发布程序的名称(AssemblyName):

 <PropertyGroup>    <OutputType>Exe</OutputType>    <TargetFramework>netcoreapp3.1</TargetFramework>    <AssemblyName>api-cli</AssemblyName>   </PropertyGroup>

  进入控制台程序目录:

cd src/NetCoreCLI

  发布Linux使用版本:

 dotnet publish -c Release -r linux-x64 /p:PublishSingleFile=true

  发布Windows使用版本:

dotnet publish -c Release -r win-x64 /p:PublishSingleFile=true

  发布MAC使用版本:

 dotnet publish -c Release -r osx-x64 /p:PublishSingleFile=true

使用示例

  这里使用Linux作为示例环境。

  1. 以docker的方式启动web api

如何使用.Net Core编写命令行工具

  2. 虚拟机上没有安装.net core的环境

如何使用.Net Core编写命令行工具

  3. 把编译好的CLI工具拷贝到虚拟机上,授权并移动到PATH中(如果不移动,可以通过./api-cli的方式调用)

sudo chmod +x api-cli #授权 sudo mv ./api-cli /usr/local/bin/api-cli #移动到PATH

  4. 设置配置文件:api-cli config set

如何使用.Net Core编写命令行工具

  5. 查看配置文件:api-cli config get

如何使用.Net Core编写命令行工具

  6. 创建条目:api-cli item create

如何使用.Net Core编写命令行工具

  7. 条目列表:api-cli item list

如何使用.Net Core编写命令行工具

  8. 获取条目:api-cli item get

如何使用.Net Core编写命令行工具

  9. 删除条目:api-cli item delete

如何使用.Net Core编写命令行工具

  10. 指令帮助:api-cli -h, api-cli config -h, api-cli item -h

如何使用.Net Core编写命令行工具

如何使用.Net Core编写命令行工具

如何使用.Net Core编写命令行工具

  11. 错误指令:api-cli xxx

如何使用.Net Core编写命令行工具

关于“如何使用.Net Core编写命令行工具”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI