在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:Cysharp/ConsoleAppFramework开源软件地址:https://github.com/Cysharp/ConsoleAppFramework开源编程语言:C# 99.9%开源软件介绍:ConsoleAppFrameworkConsoleAppFramework is an infrastructure of creating CLI(Command-line interface) tools, daemon, and multi batch application. You can create full feature of command line tool on only one-line. This simplicity is by C# 10.0 and .NET 6 new features, similar as ASP.NET Core 6.0 Minimal APIs. Most minimal API is one-line(with top-level-statements, global-usings). ConsoleApp.Run(args, (string name) => Console.WriteLine($"Hello {name}")); Of course, ConsoleAppFramework has extensibility. // Regsiter two commands(use short-name, argument)
// hello -m
// sum [x] [y]
var app = ConsoleApp.Create(args);
app.AddCommand("hello", ([Option("m", "Message to display.")] string message) => Console.WriteLine($"Hello {message}"));
app.AddCommand("sum", ([Option(0)] int x, [Option(1)] int y) => Console.WriteLine(x + y));
app.Run(); You can register public method as command. This provides a simple way to registering multiple commands. // AddCommands register as command.
// echo --msg --repeat(default = 3)
// sum [x] [y]
var app = ConsoleApp.Create(args);
app.AddCommands<Foo>();
app.Run();
public class Foo : ConsoleAppBase
{
public void Echo(string msg, int repeat = 3)
{
for (var i = 0; i < repeat; i++)
{
Console.WriteLine(msg);
}
}
public void Sum([Option(0)]int x, [Option(1)]int y)
{
Console.WriteLine((x + y).ToString());
}
} If you have many commands, you can define class separetely and use // Register `Foo` and `Bar` as SubCommands(You can also use AddSubCommands<T> to register manually).
// foo echo --msg
// foo sum [x] [y]
// bar hello2
var app = ConsoleApp.Create(args);
app.AddAllCommandType();
app.Run();
public class Foo : ConsoleAppBase
{
public void Echo(string msg)
{
Console.WriteLine(msg);
}
public void Sum([Option(0)]int x, [Option(1)]int y)
{
Console.WriteLine((x + y).ToString());
}
}
public class Bar : ConsoleAppBase
{
public void Hello2()
{
Console.WriteLine("H E L L O");
}
} ConsoleAppFramework is built on .NET Generic Host, you can use configuration, logging, DI, lifetime management by Microsoft.Extensions packages. ConsoleAppFramework do parameter binding from string args, routing many commands, dotnet style help builder, etc. Here is the full-sample of power of ConsoleAppFramework. // You can use full feature of Generic Host(same as ASP.NET Core).
var builder = ConsoleApp.CreateBuilder(args);
builder.ConfigureServices((ctx,services) =>
{
// Register EntityFramework database context
services.AddDbContext<MyDbContext>();
// Register appconfig.json to IOption<MyConfig>
services.Configure<MyConfig>(ctx.Configuration);
// Using Cysharp/ZLogger for logging to file
services.AddLogging(logging =>
{
logging.AddZLoggerFile("log.txt");
});
});
var app = builder.Build();
// setup many command, async, short-name/description option, subcommand, DI
app.AddCommand("calc-sum", (int x, int y) => Console.WriteLine(x + y));
app.AddCommand("sleep", async ([Option("t", "seconds of sleep time.")] int time) =>
{
await Task.Delay(TimeSpan.FromSeconds(time));
});
app.AddSubCommand("verb", "childverb", () => Console.WriteLine("called via 'verb childverb'"));
// You can insert all public methods as sub command => db select / db insert
// or AddCommand<T>() all public methods as command => select / insert
app.AddSubCommands<DatabaseApp>();
// some argument from DI.
app.AddRootCommand((ConsoleAppContext ctx, IOptions<MyConfig> config, string name) => { });
app.Run();
// ----
[Command("db")]
public class DatabaseApp : ConsoleAppBase, IAsyncDisposable
{
readonly ILogger<DatabaseApp> logger;
readonly MyDbContext dbContext;
readonly IOptions<MyConfig> config;
// you can get DI parameters.
public DatabaseApp(ILogger<DatabaseApp> logger,IOptions<MyConfig> config, MyDbContext dbContext)
{
this.logger = logger;
this.dbContext = dbContext;
this.config = config;
}
[Command("select")]
public async Task QueryAsync(int id)
{
// select * from...
}
// also allow defaultValue.
[Command("insert")]
public async Task InsertAsync(string value, int id = 0)
{
// insert into...
}
// support cleanup(IDisposable/IAsyncDisposable)
public async ValueTask DisposeAsync()
{
await dbContext.DisposeAsync();
}
}
public class MyConfig
{
public string FooValue { get; set; } = default!;
public string BarValue { get; set; } = default!;
} ConsoleAppFramework can create easily to many command application. Also enable to use GenericHost configuration is best way to share configuration/workflow when creating batch application for other .NET web app. If tool is for CI, git pull and run by dotnet's standard CommandLine api - System.CommandLine is low level, require many boilerplate codes. ConsoleAppFramework is like ASP.NET Core in CLI Applications, no needs boilerplate. However, with the power of Generic Host, it is simple and easy, but much more powerful. Table of Contents
Getting StartedNuGet: ConsoleAppFramework
If you are using .NET 6, automatically enabled implicit global ConsoleApp.Run(args, (string name) => Console.WriteLine($"Hello {name}")); You can execute command like The Option parser is no longer needed. You can also use the ConsoleApp.Run(args, ([Option("n", "name of send user.")] string name) => Console.WriteLine($"Hello {name}"));
Method parameter will be required parameter, optional parameter will be oprional parameter with default value. Also support boolean flag, if parameter is bool, in default it will be optional parameter and with // lambda expression does not support default value so require to use local function
static void Hello([Option("m")]string message, [Option("e")] bool end, [Option("r")] int repeat = 3)
{
for (int i = 0; i < repeat; i++)
{
Console.WriteLine(message);
}
if (end)
{
Console.WriteLine("END");
}
}
ConsoleApp.Run(args, Hello); Options:
-m, --message <String> (Required)
-e, --end (Optional)
-r, --repeat <Int32> (Default: 3)
You can use ConsoleApp.Run<MyCommands>(args);
// require to inherit ConsoleAppBase
public class MyCommands : ConsoleAppBase
{
// You can receive DI services in constructor.
// All public methods is registred.
// Using [RootCommand] attribute will be root-command
[RootCommand]
public void Hello(
[Option("n", "name of send user.")] string name,
[Option("r", "repeat count.")] int repeat = 3)
{
for (int i = 0; i < repeat; i++)
{
Console.WriteLine($"Hello My ConsoleApp from {name}");
}
}
// [Option(int)] describes that parameter is passed by index
[Command("escape")]
public void UrlEscape([Option(0)] string input)
{
Console.WriteLine(Uri.EscapeDataString(input));
}
// define async method returns Task
[Command("timer")]
public async Task Timer([Option(0)] uint waitSeconds)
{
Console.WriteLine(waitSeconds + " seconds");
while (waitSeconds != 0)
{
// ConsoleAppFramework does not stop immediately on terminate command(Ctrl+C)
// for allows gracefully shutdown(keeping safe cleanup)
// so you should pass Context.CancellationToken to async method.
// If not, abort timeout by HostOptions.ShutdownTimeout(default is 00:00:05).
await Task.Delay(TimeSpan.FromSeconds(1), Context.CancellationToken);
waitSeconds--;
Console.WriteLine(waitSeconds + " seconds");
}
}
} You can call like
This is recommended way to register multi commands. If you omit // Command is url-escape
// Option is --input-file
public void UrlEscape(string inputFile)
{
} This converting behaviour can configure by ConsoleApp / ConsoleAppBuilder
// Create is shorthand of CraeteBuilder(args).Build();
var app = ConsoleApp.Create(args);
// Builder returns IHost so you can configure application hosting option.
var app = ConsoleApp.CreateBuilder(args)
.ConfigureServices(services =>
{
})
.Build();
// Run is shorthand of Create(args).AddRootCommand(rootCommand).Run();
// If you want to create simple app, this API is most fast.
ConsoleApp.Run(args, /* lambda expression */);
// Run<T> is shorthand of Create(args).AddCommands<T>().Run();
// AddCommands<T> is recommend option to register many commands.
ConsoleApp.Run<MyCommands>(args); When calling var app = ConsoleApp.Create(args, options =>
{
options.ShowDefaultCommand = false;
options.NameConverter = x => x.ToLower();
}); Advanced API of // Setup services outside of ConsoleAppFramework.
var hostBuilder = Host.CreateDefaultBuilder()
.ConfigureServices();
var app = ConsoleApp.CreateFromHostBuilder(hostBuilder);
Delegate convention
app.AddCommand("no-argument", () => { });
app.AddCommand("any-arguments", (int x, string y, TimeSpan z) => { });
app.AddCommand("instance", new MyClass().Cmd);
app.AddCommand("async", async () => { });
app.AddCommand("attribute", ([Option("msg")]string message) => { });
static void Hello1() { }
app.AddCommand("local-static", Hello1);
void Hello2() { }
app.AddCommand("local-method", Hello2);
async Task Async() { }
app.AddCommand("async-method", Async);
void OptionalParameter(int x = 10, int y = 20) { }
app.AddCommand("optional", OptionalParameter);
public class MyClass
{
public void Cmd()
{
Console.WriteLine("OK");
}
} lambda expressions can not use optional parameter so if you want to need it, using local/static functions. Delegate(both lambda and method) allows to receive // option is --param1, --param2
app.AddCommand("di", (ConsoleAppContext ctx, ILogger logger, int param1, int param2) => { }); AddCommand
|
请发表评论