Skip to content

Commit 838cd94

Browse files
committed
Merge branch 'master' of https://github.com/csmir/Commands.NET
2 parents c205a7c + 69a05f3 commit 838cd94

File tree

21 files changed

+244
-127
lines changed

21 files changed

+244
-127
lines changed

src/Commands.Hosting/Commands.Hosting.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<NoWarn>CA1822;IDE0130;IDE0290</NoWarn>
1111

1212
<AssemblyVersion>2.0</AssemblyVersion>
13-
<PackageVersion>2.0.0-alpha.26</PackageVersion> <!--\-alpha.1-->
13+
<PackageVersion>2.0.0-alpha.29</PackageVersion> <!--\-alpha.1-->
1414
<FileVersion>2.0.0.0</FileVersion>
1515

1616
<GenerateDocumentationFile>true</GenerateDocumentationFile>

src/Commands.Hosting/Commands.Hosting/Execution/CommandExecutionFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public CommandExecutionFactory(IComponentProvider execProvider, IServiceProvider
6767
services.GetService<IExecutionScope>()?.Dispose();
6868
};
6969

70-
Logger?.LogInformation("Consuming {ExecutionProvider}, with {HandlerCount} result handler{MoreOrOne}.", Provider.GetType().FullName, handlers.Length, handlers.Length > 1 ? "(s)" : "");
70+
Logger?.LogInformation("Consuming {ExecutionProvider}, with {HandlerCount} result handler{MoreOrOne}.", Provider.GetType().FullName, handlers.Length, handlers.Length != 1 ? "(s)" : "");
7171

7272
var commands = execProvider.Components.GetCommands().ToArray();
7373

src/Commands.Http/Commands.Http.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<NoWarn>CA1822;IDE0130;IDE0290</NoWarn>
1111

1212
<AssemblyVersion>2.0</AssemblyVersion>
13-
<PackageVersion>2.0.0-alpha.26</PackageVersion> <!--\-alpha.1-->
13+
<PackageVersion>2.0.0-alpha.29</PackageVersion> <!--\-alpha.1-->
1414
<FileVersion>2.0.0.0</FileVersion>
1515

1616
<GenerateDocumentationFile>true</GenerateDocumentationFile>

src/Commands.Http/Commands.Http/Execution/HttpCommandContext.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,14 @@ public virtual void Respond(IHttpResult result)
127127
}
128128
else
129129
{
130-
var jsonBytes = Response.ContentEncoding.GetBytes(JsonSerializer.Serialize(result.Content, result.Content.GetType(), _services.GetService<JsonSerializerOptions>()));
130+
string serializationResult;
131+
132+
if (result.Content is Tuple<Type, object> objectReferredByT)
133+
serializationResult = JsonSerializer.Serialize(objectReferredByT.Item2, objectReferredByT.Item1, _services.GetService<JsonSerializerOptions>());
134+
else
135+
serializationResult = JsonSerializer.Serialize(result.Content, result.Content.GetType(), _services.GetService<JsonSerializerOptions>());
136+
137+
var jsonBytes = Response.ContentEncoding.GetBytes(serializationResult);
131138

132139
Response.ContentLength64 = jsonBytes.Length;
133140

src/Commands.Http/Commands.Http/Execution/HttpCommandExecutionFactory.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class HttpCommandExecutionFactory(IComponentProvider executionProvider, I
2121
/// </remarks>
2222
/// <param name="cancellationToken">The token that when cancelled, will notify a linked token to stop the HTTP pipeline and cleanly escape the listening process.</param>
2323
/// <returns>An awaitable <see cref="Task"/> representing the result of the start operation.</returns>
24-
public Task StartAsync(CancellationToken cancellationToken)
24+
public Task StartAsync(CancellationToken cancellationToken = default)
2525
{
2626
try
2727
{
@@ -34,11 +34,8 @@ public Task StartAsync(CancellationToken cancellationToken)
3434
{
3535
Logger?.LogDebug("Configuring HTTP prefix: {Prefix}", prefix.Value);
3636

37-
if (string.IsNullOrWhiteSpace(prefix.Value))
38-
continue;
39-
40-
if (!httpListener.Prefixes.Contains(prefix.Value!))
41-
httpListener.Prefixes.Add(prefix.Value!);
37+
if (!string.IsNullOrWhiteSpace(prefix.Value) && !httpListener.Prefixes.Contains(prefix.Value))
38+
httpListener.Prefixes.Add(prefix.Value);
4239
}
4340
}
4441

@@ -65,7 +62,7 @@ public Task StartAsync(CancellationToken cancellationToken)
6562
/// </summary>
6663
/// <param name="cancellationToken">The token that when cancelled, will force the listening process to break regardless of its execution state.</param>
6764
/// <returns>An awaitable <see cref="Task"/> representing the result of the stop operation.</returns>
68-
public async Task StopAsync(CancellationToken cancellationToken)
65+
public async Task StopAsync(CancellationToken cancellationToken = default)
6966
{
7067
if (_runningTask is null)
7168
return;

src/Commands.Http/Commands.Http/Results/HttpResult.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ public override string ToString()
8787
/// <param name="content">The response to send.</param>
8888
/// <param name="statusCode">The status code of the response.</param>
8989
/// <returns>A new instance of <see cref="HttpResult"/> containing the values to be served to the caller invoking this operation.</returns>
90-
public static HttpResult Json(object content, HttpStatusCode statusCode = HttpStatusCode.OK)
90+
public static HttpResult Json<T>([DisallowNull] T content, HttpStatusCode statusCode = HttpStatusCode.OK)
9191
{
9292
Assert.NotNull(content, nameof(content));
9393

94-
return new(statusCode, content, "application/json");
94+
return new(statusCode, new Tuple<Type, object>(typeof(T), content), "application/json");
9595
}
9696

9797
/// <summary>

src/Commands.Samples/Commands.Samples.Http/Program.cs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
// This (currently) includes defining parsers and validation of component names.
3939
context.ConfigureOptions(options =>
4040
{
41-
41+
4242
});
4343
});
4444

@@ -88,23 +88,14 @@
8888
// This approach is more flexible and allows for more granular control over the services and components used in the application.
8989
// ... Or when you do not intend to implement the whole host, but just want to run the HTTP server on an isolated service collection.
9090
var services = new ServiceCollection()
91-
.AddHttpComponents(options =>
92-
{
93-
options.WithListener(listener =>
94-
{
95-
listener.Prefixes.Add("http://localhost:7000/");
96-
});
97-
})
91+
.AddSingleton<ComponentTree>([new CommandGroup<HttpModule>()])
92+
.AddHttpComponents(cfg => cfg.WithListener(listener => listener.Prefixes.Add("http://localhost:7000/")))
9893
.BuildServiceProvider();
9994

100-
// Retrieve the component provider from the service collection and add the HttpModule to it, rather than calling UseComponents on the host.
101-
services.GetRequiredService<IComponentProvider>()
102-
.Components.Add<HttpModule>();
103-
10495
// The factory under hosted context implements IHostedService, which means it will start and stop with the host.
10596
// This is not supported in this isolated context, so it is registered as a singleton service and can be started and stopped manually.
10697
await services.GetRequiredService<HttpCommandExecutionFactory>()
107-
.StartAsync(default);
98+
.StartAsync();
10899

109100
// Prevent the application from exiting immediately... or when in a larger application, continue running other tasks.
110101
await Task.Delay(Timeout.Infinite);

src/Commands.Tests/Commands.Tests.Benchmarks/Commands.Tests.Benchmarks.csproj

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
<TargetFramework>net8.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>enable</Nullable>
8-
<NoWarn>CA1822;IDE0130</NoWarn>
8+
<NoWarn>CA1822;IDE0130</NoWarn>
9+
<DefineConstants>$(DefineConstants);DISABLE_PROFILER_AGENT_CONFIG</DefineConstants>
910
</PropertyGroup>
1011

1112
<ItemGroup>
12-
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
13+
<PackageReference Include="BenchmarkDotNet" Version="0.15.6" />
14+
<PackageReference Include="Microsoft.VisualStudio.DiagnosticsHub.BenchmarkDotNetDiagnosers" Version="18.3.36726.2" />
1315
</ItemGroup>
16+
1417

1518
<ItemGroup>
1619
<ProjectReference Include="..\..\Commands\Commands.csproj" />

src/Commands.Tests/Commands.Tests.Benchmarks/Program.cs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,15 @@ public void FindCommands()
5050
public Task RunCommand()
5151
=> _provider.Execute(new BenchmarkContext("command"));
5252

53-
//[Benchmark]
54-
//public Task RunCommandNonBlocking()
55-
// => _provider.Execute(new BenchmarkContext("command"), new ExecutionOptions()
56-
// {
57-
// ExecuteAsynchronously = true,
58-
// });
59-
60-
//[Benchmark]
61-
//public ComponentTree CollectionCreate()
62-
// => [];
53+
[Benchmark]
54+
public ComponentTree CollectionCreate()
55+
=> [];
6356

64-
//[Benchmark]
65-
//public CommandGroup GroupCreate()
66-
// => new(["name"]);
57+
[Benchmark]
58+
public CommandGroup GroupCreate()
59+
=> new(["name"]);
6760

68-
//[Benchmark]
69-
//public Command CommandCreate()
70-
// => new(() => { }, ["name"]);
61+
[Benchmark]
62+
public Command CommandCreate()
63+
=> new(() => { }, ["name"]);
7164
}

src/Commands.Tests/Commands.Tests.Benchmarks/README.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,45 @@ Benchmarks are ran for every release to ensure the library is performing as expe
44

55
The following benchmarks are ran on the latest version of the library, using the latest version of the .NET SDK and BenchmarkDotNet.
66

7-
### Last Benchmark: 1/22/2025
8-
97
- **CreateArguments**: Parsing provided string input into processable arguments.
108
- **FindCommands**: Finding the command to execute based on the provided arguments.
119
- **RunCommand**: Parsing, Finding and running the command, start to finish.
12-
- **RunCommandNonBlocking**: Parsing, Finding and running the command asynchronously, start to finish.
1310
- **CollectionCreate**: Creating a collection for commands.
1411
- **GroupCreate**: Creating a group for commands.
1512
- **CommandCreate**: Creating a command.
1613

17-
# Intel® Core™ i7-1255U
14+
# Intel® Core™ i7-1255U
15+
16+
### Last Benchmark: 1/22/2025
1817

1918
| Method | Mean | Error | StdDev | Gen0 | Allocated |
2019
|---------------------- |-----------:|----------:|----------:|-------:|----------:|
2120
| CreateArguments | 50.497 ns | 0.9744 ns | 0.9570 ns | 0.0446 | 280 B |
2221
| FindCommands | 45.632 ns | 0.4376 ns | 0.3879 ns | 0.0140 | 88 B |
2322
| RunCommand | 199.856 ns | 2.5021 ns | 2.2180 ns | 0.0815 | 512 B |
24-
| RunCommandNonBlocking | 207.349 ns | 2.2603 ns | 1.8874 ns | 0.0892 | 560 B |
2523
| CollectionCreate | 4.372 ns | 0.0760 ns | 0.0635 ns | 0.0051 | 32 B |
2624
| GroupCreate | 11.112 ns | 0.0974 ns | 0.0864 ns | 0.0166 | 104 B |
2725
| CommandCreate | 137.402 ns | 1.4430 ns | 1.2050 ns | 0.0508 | 320 B |
2826

2927
> [!NOTE]
3028
> Allocation for running commands is a combination of the argument creation, and search process.
31-
> On itself, it allocates 144 / 192 bytes for actual execution.
29+
> On itself, it allocates 144 bytes for actual execution.
3230
33-
# Intel® Core™ Ultra 7 155H
31+
# Intel® Core™ Ultra 7 155H
3432

35-
> Not yet tested.
33+
### Last Benchmark: 11/27/2025
34+
35+
| Method | Mean | Error | StdDev | Gen0 | Allocated |
36+
|----------------- |-----------:|----------:|----------:|-------:|----------:|
37+
| CreateArguments | 42.739 ns | 0.7411 ns | 0.6933 ns | 0.0159 | 200 B |
38+
| FindCommands | 36.797 ns | 0.7566 ns | 1.0100 ns | 0.0025 | 32 B |
39+
| RunCommand | 172.082 ns | 3.0553 ns | 2.8579 ns | 0.0248 | 312 B |
40+
| CollectionCreate | 4.652 ns | 0.1170 ns | 0.1094 ns | 0.0025 | 32 B |
41+
| GroupCreate | 11.211 ns | 0.0869 ns | 0.0813 ns | 0.0083 | 104 B |
42+
| CommandCreate | 165.108 ns | 1.7455 ns | 1.6327 ns | 0.0370 | 464 B |
43+
44+
> [!NOTE]
45+
> Allocation for running commands is a combination of the argument creation, and search process.
46+
> On itself, it allocates 112 bytes for actual execution.
3647
37-
*This chart can be reproduced at any time by running this benchmark project.*
48+
*This chart can be reproduced at any time by running this benchmark project.*

0 commit comments

Comments
 (0)