-
I'm toying with how to integrate public static class Program
{
public static Task<int> Main(string[] args) =>
HostRunner.Run(Constants.AppName, args, args => CreateHostBuilder(args).Build().RunAsync());
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(args)
.ConfigureServices()
.UseSerilog(Constants.AppName);
} public static IHostBuilder ConfigureServices(this IHostBuilder hostBuilder) =>
hostBuilder.ConfigureServices((_, services) =>
{
services.AddHostedService<PulumiService>()
.AddSingleton<ICommandApp>(_ =>
{
var app = new CommandApp();
app.Configure(config =>
{
config.SetApplicationName(Constants.AppName);
config.AddCommand<PulumiPreviewCommand>("preview");
config.AddCommand<PulumiUpCommand>("up");
});
return app;
});
}); public sealed class PulumiService : BackgroundService
{
public PulumiService(ICommandApp appCommand, IHostApplicationLifetime appLifetime, ILogger<PulumiService> logger)
{
AppCommand = appCommand;
AppLifetime = appLifetime;
Logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await AppCommand.RunAsync(Environment.GetCommandLineArgs()[1..]);
AppLifetime.StopApplication();
}
private ICommandApp AppCommand { get; }
private IHostApplicationLifetime AppLifetime { get; }
private ILogger Logger { get; }
} The missing piece is being able to easily integrate with the generic host dependency injection, such that I can wire up the commands in Thoughts? (Besides thinking I am crazy 😁) |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 10 replies
-
@gitfool That's not crazy, I'm using the generic host with Spectre CLI too. In fact, it's already possible. The example Injection shows how to use In my application I have changed the implementation of public sealed class TypeRegistrar : ITypeRegistrar
{
private readonly IHostBuilder _builder;
public TypeRegistrar(IHostBuilder builder)
{
_builder = builder;
}
public ITypeResolver Build()
{
return new TypeResolver(_builder.Build());
}
public void Register(Type service, Type implementation)
{
_builder.ConfigureServices((_, services) => services.AddSingleton(service, implementation));
}
public void RegisterInstance(Type service, object implementation)
{
_builder.ConfigureServices((_, services) => services.AddSingleton(service, implementation));
}
public void RegisterLazy(Type service, Func<object> func)
{
if (func is null) throw new ArgumentNullException(nameof(func));
_builder.ConfigureServices((_, services) => services.AddSingleton(service, _ => func()));
}
} public sealed class TypeResolver : ITypeResolver, IDisposable
{
private readonly IHost _host;
public TypeResolver(IHost provider)
{
_host = provider ?? throw new ArgumentNullException(nameof(provider));
}
public object? Resolve(Type? type)
{
return type != null ? _host.Services.GetService(type) : null;
}
public void Dispose()
{
_host.Dispose();
}
} My public class Program
{
public static int Main(string[] args)
{
var host = CreateHostBuilder(args);
var registrar = new TypeRegistrar(host);
var app = new CommandApp<MyDefaultCommand>(registrar);
app.Configure(c => c.AddCommand<AnotherCommand>("other"));
app.Configure(c => c.AddCommand<ThirdCommand>("third"));
return app.Run(args);
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host
.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
// add service registrations here
services.AddSingleton<ISomeService, SomeService>();
});
} |
Beta Was this translation helpful? Give feedback.
-
In addition to what @thoemmi posted, I have a slightly different method over here that worked well for me - https://github.com/phil-scott-78/spectre-aspnet/blob/main/AspNetCoreApp/Infrastructure/SpectreHostingExtensions.cs I'm going a bit of a roundabout way of doing it because my tool is being used to debug and inspect the host, so I didn't want to add any of the console tooling into the host's container. Given enough time, I think we might add an official package to integrate easily so it's great seeing how others are approaching this problem and for what needs. |
Beta Was this translation helpful? Give feedback.
@gitfool That's not crazy, I'm using the generic host with Spectre CLI too. In fact, it's already possible. The example Injection shows how to use
IServiceCollection
: implement your ownITypeRegistrar
andITypeResolver
, and Spectre will register your commands in theIServiceCollection
automatically.In my application I have changed the implementation of
ITypeRegistrar
andITypeResolver
for better support of the generic host: