-
-
Notifications
You must be signed in to change notification settings - Fork 43
Description
When using the custom command pattern, as described here: https://jasperfx.github.io/oakton/guide/bootstrapping.html#custom-command-creators
The functionality as described in the "Improved Run Command" described here: https://jasperfx.github.io/oakton/guide/host/run.html#improved-run-command
does not work. Instead of being able to see your commands or see their usage, you get an error.
For example if I execute this command:
dotnet run -- myconsoleapp
I get this error:
[red]Invalid usage[/]
Unhandled exception. System.Reflection.TargetException: Non-static method requires a target.
at System.Reflection.MethodBase.ValidateInvokeTarget(Object target)
at System.Reflection.RuntimeMethodInfo.InvokeOneParameter(Object obj, BindingFlags invokeAttr, Binder binder, Object parameter, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.PropertyInfo.SetValue(Object obj, Object value)
at Oakton.Parsing.TokenHandlerBase.setValue(Object target, Object value)
at Oakton.Argument.Handle(Object input, Queue1 tokens) at Oakton.Help.UsageGraph.<>c__DisplayClass20_0.<BuildInput>b__0(ITokenHandler h) at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable
1 source, Func2 predicate, Boolean& found) at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable
1 source, Func2 predicate) at Oakton.Help.UsageGraph.BuildInput(Queue
1 tokens, ICommandCreator creator)
at Oakton.CommandFactory.HelpRun(Queue1 queue) at Oakton.CommandFactory.HelpRun(String commandName) at Oakton.CommandFactory.buildRun(Queue
1 queue, String commandName)
at Oakton.CommandFactory.BuildRun(IEnumerable`1 args)
at Oakton.CommandExecutor.ExecuteAsync(String[] args)
at Oakton.CommandExecutor.Execute(String[] args)
at Program.
dotnet run -- myconsoleapp ?
In addition if you specify the wrong arguments trying to run your console app, you also get a hard error. This command:
dotnet run --myconsoleapp test123
Gives this error:
[red]Error parsing input[/]System.FormatException: The input string 'test123' was not in a correct format.
at void System.Number.ThrowOverflowOrFormatException(ParsingStatus status, ReadOnlySpan value, TypeCode type)
at int System.Int32.Parse(string s)
at object Oakton.Internal.Conversion.Conversions.<>c__DisplayClass5_0`1.b__0(string x)
at bool Oakton.Argument.Handle(object input, Queue tokens)
at bool Oakton.Help.UsageGraph.<>c__DisplayClass20_0.b__0(ITokenHandler h)
at TSource System.Linq.Enumerable.TryGetFirst(IEnumerable source, Func<TSource, bool> predicate, out bool found)
at TSource System.Linq.Enumerable.FirstOrDefault(IEnumerable source, Func<TSource, bool> predicate)
at object Oakton.Help.UsageGraph.BuildInput(Queue tokens, ICommandCreator creator)
at CommandRun Oakton.CommandFactory.buildRun(Queue queue, string commandName)
Unhandled exception. System.Reflection.TargetException: Non-static method requires a target.
at System.Reflection.MethodBase.ValidateInvokeTarget(Object target)
at System.Reflection.RuntimeMethodInfo.InvokeOneParameter(Object obj, BindingFlags invokeAttr, Binder binder, Object parameter, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.PropertyInfo.SetValue(Object obj, Object value)
at Oakton.Parsing.TokenHandlerBase.setValue(Object target, Object value)
at Oakton.Argument.Handle(Object input, Queue1 tokens) at Oakton.Help.UsageGraph.<>c__DisplayClass20_0.<BuildInput>b__0(ITokenHandler h) at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable
1 source, Func2 predicate, Boolean& found) at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable
1 source, Func2 predicate) at Oakton.Help.UsageGraph.BuildInput(Queue
1 tokens, ICommandCreator creator)
at Oakton.CommandFactory.HelpRun(Queue1 queue) at Oakton.CommandFactory.HelpRun(String commandName) at Oakton.CommandFactory.buildRun(Queue
1 queue, String commandName)
at Oakton.CommandFactory.BuildRun(IEnumerable`1 args)
at Oakton.CommandExecutor.ExecuteAsync(String[] args)
at Oakton.CommandExecutor.Execute(String[] args)
at Program.
As long as I specify the proper parameter, Oakton does work. It is just when I try to take advantage of the improved run command to see how the command/inputs are supposed to be structured or if I make a mistake on the input parameters, Oakton seems to crash hard.
I am using version 6.0.0 of Oakton and a .NET 7 console app. My program.cs looks like this:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Oakton;
using Oakton.Commands;
using System.Reflection;
using IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddTransient();
services.AddTransient();
})
//.ConfigureAppConfiguration((hostingContext, config) => { })
.Build();
var executor = CommandExecutor.For(commandFactory =>
{
commandFactory.RegisterCommands(typeof(Program).GetTypeInfo().Assembly);
}
, new DiCommandCreator(host.Services)
);
return executor.Execute(args);
Any my DiCommandCreator class looks like this:
public class DiCommandCreator : ICommandCreator
{
private readonly IServiceProvider serviceProvider;
public DiCommandCreator(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public IOaktonCommand CreateCommand(Type commandType)
{
return (IOaktonCommand)serviceProvider.GetService(commandType);
}
public object CreateModel(Type modelType)
{
return serviceProvider.GetService(modelType);
}
}
I dont think it is anything wrong per se with my command or input (which is just a simple class with one integer property) because if I switch over to not use dependency injection and just use the "RunOaktonCommandsSynchronously" approach, everything works.
return Host.CreateDefaultBuilder(args)
.RunOaktonCommandsSynchronously(args);
Seems like when using the custom command pattern, Oakton just does not work as expected? I need to use IOC in this project and hoping there may be some way to address these issues. Thank you.