Skip to content

Commit 47d1194

Browse files
authored
feature: expand Microsoft.Extensions.Hosting support to allow work to be done prior to Run*Async() (#409)
1 parent bcf20ed commit 47d1194

File tree

4 files changed

+93
-0
lines changed

4 files changed

+93
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,5 @@ The library also includes other utilities for interaction with the console. Thes
129129
```
130130

131131
And more! See the [documentation](https://natemcmaster.github.io/CommandLineUtils/) for more API, such as `IConsole`, `IReporter`, and others.
132+
133+

src/Hosting.CommandLine/HostBuilderExtensions.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,49 @@ public static async Task<int> RunCommandLineApplicationAsync(
145145

146146
return state.ExitCode;
147147
}
148+
149+
/// <summary>
150+
/// Configures an instance of <typeparamref name="TApp" /> using <see cref="CommandLineApplication" /> to provide
151+
/// command line parsing on the given <paramref name="args" />.
152+
/// </summary>
153+
/// <typeparam name="TApp">The type of the command line application implementation</typeparam>
154+
/// <param name="hostBuilder">This instance</param>
155+
/// <param name="args">The command line arguments</param>
156+
/// <param name="configure">The delegate to configure the application</param>
157+
/// <returns><see cref="IHostBuilder"/></returns>
158+
public static IHostBuilder UseCommandLineApplication<TApp>(
159+
this IHostBuilder hostBuilder,
160+
string[] args,
161+
Action<CommandLineApplication<TApp>> configure = null)
162+
where TApp : class
163+
{
164+
configure ??= app => { };
165+
var state = new CommandLineState(args);
166+
hostBuilder.Properties[typeof(CommandLineState)] = state;
167+
hostBuilder.ConfigureServices(
168+
(context, services)
169+
=>
170+
{
171+
services
172+
.TryAddSingleton<StoreExceptionHandler>();
173+
services
174+
.TryAddSingleton<IUnhandledExceptionHandler>(provider => provider.GetRequiredService<StoreExceptionHandler>());
175+
services
176+
.AddSingleton<IHostLifetime, CommandLineLifetime>()
177+
.TryAddSingleton(PhysicalConsole.Singleton);
178+
services
179+
.AddSingleton(provider =>
180+
{
181+
state.SetConsole(provider.GetService<IConsole>());
182+
return state;
183+
})
184+
.AddSingleton<CommandLineContext>(state)
185+
.AddSingleton<ICommandLineService, CommandLineService<TApp>>();
186+
services
187+
.AddSingleton(configure);
188+
});
189+
190+
return hostBuilder;
191+
}
148192
}
149193
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) Nate McMaster.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace Microsoft.Extensions.Hosting
5+
{
6+
using System;
7+
using System.Runtime.ExceptionServices;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
using McMaster.Extensions.CommandLineUtils;
11+
using McMaster.Extensions.Hosting.CommandLine.Internal;
12+
using Microsoft.Extensions.DependencyInjection;
13+
14+
/// <summary>
15+
/// Extension methods for <see cref="IHost" /> support.
16+
/// </summary>
17+
public static class HostExtensions
18+
{
19+
/// <summary>
20+
/// Runs an instance of <typeparamref name="TApp" /> using the <see cref="CommandLineApplication" /> previously configured in
21+
/// <see cref="HostBuilderExtensions.UseCommandLineApplication{TApp}(IHostBuilder, string[], Action{CommandLineApplication{TApp}})"/>.
22+
/// </summary>
23+
/// <typeparam name="TApp">The type of the command line application implementation</typeparam>
24+
/// <param name="host">This instance</param>
25+
/// <param name="cancellationToken">A cancellation token</param>
26+
public static async Task<int> RunCommandLineApplicationAsync<TApp>(
27+
this IHost host,
28+
CancellationToken cancellationToken = default)
29+
where TApp : class
30+
{
31+
var exceptionHandler = host.Services.GetService<StoreExceptionHandler>();
32+
var state = host.Services.GetRequiredService<CommandLineState>();
33+
34+
await host.RunAsync(cancellationToken);
35+
36+
if (exceptionHandler?.StoredException != null)
37+
{
38+
ExceptionDispatchInfo.Capture(exceptionHandler.StoredException).Throw();
39+
}
40+
41+
return state.ExitCode;
42+
}
43+
}
44+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
#nullable enable
2+
static Microsoft.Extensions.Hosting.HostBuilderExtensions.UseCommandLineApplication<TApp>(this Microsoft.Extensions.Hosting.IHostBuilder! hostBuilder, string![]! args, System.Action<McMaster.Extensions.CommandLineUtils.CommandLineApplication<TApp!>!>! configure = null) -> Microsoft.Extensions.Hosting.IHostBuilder!
3+
Microsoft.Extensions.Hosting.HostExtensions
4+
static Microsoft.Extensions.Hosting.HostExtensions.RunCommandLineApplicationAsync<TApp>(this Microsoft.Extensions.Hosting.IHost! host, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<int>!

0 commit comments

Comments
 (0)