You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
> The latest Visual Studio changed the execution timing of Source Generators to either during save or at compile time. If you encounter unexpected behavior, try compiling once or change the option to "Automatic" under TextEditor -> C# -> Advanced -> Source Generators.
172
+
171
173
You can execute command like `sampletool --name "foo"`.
172
174
173
175
* The return value can be `void`, `int`, `Task`, or `Task<int>`
@@ -257,7 +259,7 @@ To add aliases to parameters, list the aliases separated by `|` before the comma
257
259
258
260
Unfortunately, due to current C# specifications, lambda expressions and [local functions do not support document comments](https://github.com/dotnet/csharplang/issues/2110), so a class is required.
259
261
260
-
In addition to `-h|--help`, there is another special built-in option: `--version`. In default, it displays the `AssemblyInformationalVersion` or `AssemblyVersion`. You can configure version string by `ConsoleApp.Version`, for example `ConsoleApp.Version = "2001.9.3f14-preview2";`.
262
+
In addition to `-h|--help`, there is another special built-in option: `--version`. In default, it displays the `AssemblyInformationalVersion`without source revision or `AssemblyVersion`. You can configure version string by `ConsoleApp.Version`, for example `ConsoleApp.Version = "2001.9.3f14-preview2";`.
261
263
262
264
Command
263
265
---
@@ -355,6 +357,43 @@ app.Add<MyCommands>("foo");
355
357
app.Run(args);
356
358
```
357
359
360
+
### Register from attribute
361
+
362
+
Instead of using `Add<T>`, you can automatically add commands by applying the `[RegisterCommands]` attribute to a class.
363
+
364
+
```csharp
365
+
[RegisterCommands]
366
+
publicclassFoo
367
+
{
368
+
publicvoidBaz(intx)
369
+
{
370
+
Console.Write(x);
371
+
}
372
+
}
373
+
374
+
[RegisterCommands("bar")]
375
+
publicclassBar
376
+
{
377
+
publicvoidBaz(intx)
378
+
{
379
+
Console.Write(x);
380
+
}
381
+
}
382
+
```
383
+
384
+
These are automatically added when using `ConsoleApp.Create()`.
385
+
386
+
```csharp
387
+
varapp=ConsoleApp.Create();
388
+
389
+
// Commands:
390
+
// baz
391
+
// bar baz
392
+
app.Run(args);
393
+
```
394
+
395
+
You can also combine this with `Add` or `Add<T>` to add more commands.
396
+
358
397
### Performance of Commands
359
398
360
399
In `ConsoleAppFramework`, the number and types of registered commands are statically determined at compile time. For example, let's register the following four commands:
The C# compiler performs complex generation for string constant switches, making them extremely fast, and it would be difficult to achieve faster routing than this.
456
495
496
+
Disable Naming Conversion
497
+
---
498
+
Command names and option names are automatically converted to kebab-case by default. While this follows standard command-line tool naming conventions, you might find this conversion inconvenient when creating batch files for internal applications. Therefore, it's possible to disable this conversion at the assembly level.
You can disable automatic conversion by using `[assembly: ConsoleAppFrameworkGeneratorOptions(DisableNamingConversion = true)]`. In this case, the command would be `ExecuteCommand --fooBarBaz`.
519
+
457
520
Parse and Value Binding
458
521
---
459
522
The method parameter names and types determine how to parse and bind values from the command-line arguments. When using lambda expressions, optional values and `params` arrays supported from C# 12 are also supported.
The execution processing of `ConsoleAppFramework` fully supports `DI`. When you want to use a logger, read a configuration, or share processing with an ASP.NET project, using `Microsoft.Extensions.DependencyInjection` or other DI libraries can make processing convenient.
826
889
827
-
Lambda expressions passed to Run, class constructors, methods, and filter constructors can inject services obtained from `IServiceProvider`. Let's look at a minimal example. Setting any `System.IServiceProvider` to `ConsoleApp.ServiceProvider` enables DI throughout the system.
890
+
If you are referencing `Microsoft.Extensions.DependencyInjection`, you can call the `ConfigureServices` method from `ConsoleApp.ConsoleAppBuilder` (ConsoleAppFramework adds methods based on your project's reference status).
When passing to a lambda expression or method, the `[FromServices]` attribute is used to distinguish it from command parameters. When passing a class, Constructor Injection can be used, resulting in a simpler appearance.
844
905
845
-
Let's try injecting a logger and enabling output to a file. The libraries used are Microsoft.Extensions.Logging and [Cysharp/ZLogger](https://github.com/Cysharp/ZLogger/) (a high-performance logger built on top of MS.E.Logging).
846
-
906
+
Let's try injecting a logger and enabling output to a file. The libraries used are Microsoft.Extensions.Logging and [Cysharp/ZLogger](https://github.com/Cysharp/ZLogger/) (a high-performance logger built on top of MS.E.Logging). If you are referencing `Microsoft.Extensions.Logging`, you can call `ConfigureLogging` from `ConsoleAppBuilder`.
847
907
848
908
```csharp
849
909
// Package Import: ZLogger
850
-
varservices=newServiceCollection();
851
-
services.AddLogging(x=>
852
-
{
853
-
x.ClearProviders();
854
-
x.SetMinimumLevel(LogLevel.Trace);
855
-
x.AddZLoggerConsole();
856
-
x.AddZLoggerFile("log.txt");
857
-
});
858
-
859
-
usingvarserviceProvider=services.BuildServiceProvider(); // using for logger flush(important!)
860
-
ConsoleApp.ServiceProvider=serviceProvider;
910
+
varapp=ConsoleApp.Create()
911
+
.ConfigureLogging(x=>
912
+
{
913
+
x.ClearProviders();
914
+
x.SetMinimumLevel(LogLevel.Trace);
915
+
x.AddZLoggerConsole();
916
+
x.AddZLoggerFile("log.txt");
917
+
});
861
918
862
-
varapp=ConsoleApp.Create();
863
919
app.Add<MyCommand>();
864
920
app.Run(args);
865
921
866
922
// inject logger to constructor
867
923
publicclassMyCommand(ILogger<MyCommand> logger)
868
924
{
869
-
[Command("")]
870
925
publicvoidEcho(stringmsg)
871
926
{
872
927
logger.ZLogInformation($"Message is {msg}");
873
928
}
874
929
}
875
930
```
876
931
877
-
`ConsoleApp` has replaceable default logging methods `ConsoleApp.Log` and `ConsoleApp.LogError` used for Help display and exception handling. If using `ILogger<T>`, it's better to replace these as well.
932
+
For building an `IServiceProvider`, `ConfigureServices/ConfigureLogging` uses `Microsoft.Extensions.DependencyInjection.ServiceCollection`. If you want to set a custom ServiceProvider or a ServiceProvider built from Host, or if you want to execute DI with `ConsoleApp.Run`, set it to `ConsoleApp.ServiceProvider`.
878
933
879
934
```csharp
880
-
usingvarserviceProvider=services.BuildServiceProvider(); // using for cleanup(important)
`ConsoleApp` has replaceable default logging methods `ConsoleApp.Log` and `ConsoleApp.LogError` used for Help display and exception handling. If using `ILogger<T>`, it's better to replace these as well.
@@ -936,25 +1016,23 @@ public class PositionOptions
936
1016
}
937
1017
```
938
1018
939
-
If you have other applications such as ASP.NET in the entire project and want to use common DI and configuration set up using `Microsoft.Extensions.Hosting`, you can share them by setting the `IServiceProvider` of `IHost` after building.
1019
+
When `Microsoft.Extensions.Configuration.Abstractions` is imported, `ConfigureEmptyConfiguration` becomes available to call. Additionally, when `Microsoft.Extensions.Configuration.Json` is imported, `ConfigureDefaultConfiguration` becomes available to call. In DefaultConfiguration, `SetBasePath(System.IO.Directory.GetCurrentDirectory())` and `AddJsonFile("appsettings.json", optional: true)` are executed before calling `Action<IConfigurationBuilder> configure`.
Furthermore, overloads of `Action<IConfiguration, IServiceCollection> configure` and `Action<IConfiguration, ILoggingBuilder> configure` are added to `ConfigureServices` and `ConfigureLogging`, allowing you to retrieve the Configuration when executing the delegate.
944
1022
945
-
usingvarhost=builder.Build(); // use using for host lifetime
ConsoleAppFramework has its own lifetime management (see the [CancellationToken(Gracefully Shutdown) and Timeout](#cancellationtokengracefully-shutdown-and-timeout) section), so Host's Start/Stop is not necessary. However, be sure to use the Host itself.
953
-
954
1033
As it is, the DI scope is not set, but by using a global filter, you can add a scope for each command execution. `ConsoleAppFilter` can also inject services via constructor injection, so let's get the `IServiceProvider`.
However, since the construction of the filters is performed before execution, automatic injection using scopes is only effective for the command body itself.
972
1060
1061
+
If you have other applications such as ASP.NET in the entire project and want to use common DI and configuration set up using `Microsoft.Extensions.Hosting`, you can call `ToConsoleAppBuilder` from `IHostBuilder` or `HostApplicationBuilder`.
1062
+
1063
+
```csharp
1064
+
// Package Import: Microsoft.Extensions.Hosting
1065
+
varapp=Host.CreateApplicationBuilder()
1066
+
.ToConsoleAppBuilder();
1067
+
```
1068
+
1069
+
In this case, it builds the HostBuilder, creates a Scope for the ServiceProvider, and disposes of all of them after execution.
1070
+
1071
+
ConsoleAppFramework has its own lifetime management (see the [CancellationToken(Gracefully Shutdown) and Timeout](#cancellationtokengracefully-shutdown-and-timeout) section), so Host's Start/Stop is not necessary.
1072
+
973
1073
Colorize
974
1074
---
975
1075
The framework doesn't support colorization directly; however, utilities like [Cysharp/Kokuban](https://github.com/Cysharp/Kokuban) make console colorization easy.
0 commit comments