9
9
using Microsoft . Extensions . DependencyInjection . Extensions ;
10
10
using Microsoft . Extensions . Logging ;
11
11
using System . CommandLine . Builder ;
12
+ using System . CommandLine . Invocation ;
12
13
using System . CommandLine . IO ;
13
14
using System . Text . Encodings . Web ;
14
15
using System . Text . Json ;
@@ -34,8 +35,6 @@ public static class Helpers
34
35
Encoder = JavaScriptEncoder . UnsafeRelaxedJsonEscaping
35
36
} ;
36
37
37
- private static readonly HashSet < Option > SupportedOptions = new ( ) ;
38
-
39
38
private static IServiceCollection AddHttpHandlerMiddleware < THttpHandlerMiddleware > (
40
39
this IServiceCollection serviceCollection )
41
40
where THttpHandlerMiddleware : IHttpHandlerMiddleware
@@ -63,82 +62,110 @@ private static IServiceCollection AddResponseMiddleware<TResponseMiddleware>(
63
62
return serviceCollection ;
64
63
}
65
64
66
- public static void InitializeSupportOptions ( IServiceProvider serviceProvider )
65
+ private static Parser ConstructCommand ( this IServiceProvider serviceProvider , Func < InvocationContext , Task > ? handler = null )
67
66
{
68
- if ( SupportedOptions . Count == 0 )
69
- {
70
- foreach ( var option in
71
- serviceProvider
72
- . GetServices < IHttpHandlerMiddleware > ( ) . SelectMany ( x => x . SupportedOptions ( ) )
73
- . Union ( serviceProvider . GetServices < IRequestMiddleware > ( ) . SelectMany ( x => x . SupportedOptions ( ) )
74
- . Union ( serviceProvider . GetServices < IResponseMiddleware > ( ) . SelectMany ( x => x . SupportedOptions ( ) ) )
75
- . Union ( serviceProvider . GetRequiredService < IOutputFormatter > ( ) . SupportedOptions ( ) )
76
- . Union ( serviceProvider . GetRequiredService < IRequestExecutor > ( ) . SupportedOptions ( ) ) )
77
- . Union ( serviceProvider . GetRequiredService < ILoadTestExporterSelector > ( ) . SupportedOptions ( ) )
78
- . Union ( serviceProvider . GetServices < ILoadTestExporter > ( ) . SelectMany ( x => x . SupportedOptions ( ) ) )
79
- )
80
- {
81
- SupportedOptions . Add ( option ) ;
82
- }
83
- }
84
- var command = InitializeCommand ( ) ;
67
+ var command = InitializeCommandInternal ( serviceProvider , handler ) ;
85
68
var builder = new CommandLineBuilder ( command ) ;
86
- builder . UseDefaults ( ) ;
87
- _commandParser = builder . Build ( ) ;
69
+ // builder.UseDefaults();
70
+ builder
71
+ . UseHelp ( "--help" , "-?" , "/?" )
72
+ . UseEnvironmentVariableDirective ( )
73
+ . UseParseDirective ( )
74
+ . UseSuggestDirective ( )
75
+ . RegisterWithDotnetSuggest ( )
76
+ . UseTypoCorrections ( )
77
+ . UseParseErrorReporting ( )
78
+ . UseExceptionHandler ( )
79
+ . CancelOnProcessTermination ( )
80
+ . AddMiddleware ( async ( invocationContext , next ) =>
81
+ {
82
+ var context = serviceProvider . GetRequiredService < HttpContext > ( ) ;
83
+ context . InvocationContext = invocationContext ;
84
+
85
+ var requestModel = context . Request ;
86
+ requestModel . ParseResult = invocationContext . ParseResult ;
87
+
88
+ var method = requestModel . ParseResult . UnmatchedTokens
89
+ . FirstOrDefault ( x => HttpMethods . Contains ( x ) ) ;
90
+ if ( ! string . IsNullOrEmpty ( method ) )
91
+ {
92
+ requestModel . Method = new HttpMethod ( method ) ;
93
+ }
94
+ // Url
95
+ requestModel . Url = requestModel . ParseResult . UnmatchedTokens . FirstOrDefault ( x =>
96
+ ! x . StartsWith ( "-" , StringComparison . Ordinal )
97
+ && ! HttpMethods . Contains ( x ) )
98
+ ?? string . Empty ;
99
+ if ( string . IsNullOrEmpty ( requestModel . Url ) )
100
+ {
101
+ throw new InvalidOperationException ( "The request url can not be null" ) ;
102
+ }
103
+ requestModel . RequestItems = requestModel . ParseResult . UnmatchedTokens
104
+ . Except ( new [ ] { method , requestModel . Url } )
105
+ . WhereNotNull ( )
106
+ . Where ( x => ! x . StartsWith ( '-' ) )
107
+ . ToArray ( ) ;
108
+
109
+ await next ( invocationContext ) ;
110
+ } )
111
+ ;
112
+ return builder . Build ( ) ;
88
113
}
89
114
90
- private static Parser _commandParser = null ! ;
91
-
92
- private static Command InitializeCommand ( )
115
+ private static Command InitializeCommandInternal ( IServiceProvider serviceProvider , Func < InvocationContext , Task > ? handler = null )
93
116
{
94
117
var command = new RootCommand ( )
95
118
{
96
119
Name = "http" ,
97
120
} ;
98
- //var methodArgument = new Argument<HttpMethod>("method")
99
- //{
100
- // Description = "Request method",
101
- // Arity = ArgumentArity.ZeroOrOne,
102
- //};
103
- //methodArgument.SetDefaultValue(HttpMethod.Get.Method);
104
- //var allowedMethods = HttpMethods.ToArray();
105
- //methodArgument.AddSuggestions(allowedMethods);
106
-
107
- //command.AddArgument(methodArgument);
108
- //var urlArgument = new Argument<string>("url")
109
- //{
110
- // Description = "Request url",
111
- // Arity = ArgumentArity.ExactlyOne
112
- //};
113
- //command.AddArgument(urlArgument);
114
121
115
- foreach ( var option in SupportedOptions )
122
+ // var methodArgument = new Argument<HttpMethod>("method")
123
+ // {
124
+ // Description = "Request method",
125
+ // Arity = ArgumentArity.ZeroOrOne,
126
+ // };
127
+ // methodArgument.SetDefaultValue(HttpMethod.Get.Method);
128
+ // var allowedMethods = HttpMethods.ToArray();
129
+ // methodArgument.AddCompletions(allowedMethods);
130
+ // command.AddArgument(methodArgument);
131
+
132
+ // var urlArgument = new Argument<string>("url")
133
+ // {
134
+ // Description = "Request url",
135
+ // Arity = ArgumentArity.ExactlyOne
136
+ // };
137
+ // command.AddArgument(urlArgument);
138
+
139
+ // options
140
+ foreach ( var option in
141
+ serviceProvider
142
+ . GetServices < IHttpHandlerMiddleware > ( ) . SelectMany ( x => x . SupportedOptions ( ) )
143
+ . Union ( serviceProvider . GetServices < IRequestMiddleware > ( ) . SelectMany ( x => x . SupportedOptions ( ) )
144
+ . Union ( serviceProvider . GetServices < IResponseMiddleware > ( ) . SelectMany ( x => x . SupportedOptions ( ) ) )
145
+ . Union ( serviceProvider . GetRequiredService < IOutputFormatter > ( ) . SupportedOptions ( ) )
146
+ . Union ( serviceProvider . GetRequiredService < IRequestExecutor > ( ) . SupportedOptions ( ) ) )
147
+ . Union ( serviceProvider . GetRequiredService < ILoadTestExporterSelector > ( ) . SupportedOptions ( ) )
148
+ . Union ( serviceProvider . GetServices < ILoadTestExporter > ( ) . SelectMany ( x => x . SupportedOptions ( ) ) )
149
+ )
116
150
{
117
151
command . AddOption ( option ) ;
118
152
}
119
- command . SetHandler ( async invocationContext =>
120
- {
121
- try
122
- {
123
- var context = DependencyResolver . ResolveRequiredService < HttpContext > ( ) ;
124
- context . CancellationToken = invocationContext . GetCancellationToken ( ) ;
125
- await DependencyResolver . ResolveRequiredService < IRequestExecutor > ( )
126
- . ExecuteAsync ( context ) ;
127
- var output = await DependencyResolver . ResolveRequiredService < IOutputFormatter > ( )
128
- . GetOutput ( context ) ;
129
- invocationContext . Console . Out . WriteLine ( output . Trim ( ) ) ;
130
- }
131
- catch ( Exception e )
132
- {
133
- invocationContext . Console . Error . WriteLine ( $ "Unhandled exception: { e } ") ;
134
- }
135
- } ) ;
136
153
command . TreatUnmatchedTokensAsErrors = false ;
154
+
155
+ handler ??= async invocationContext =>
156
+ {
157
+ var context = serviceProvider . ResolveRequiredService < HttpContext > ( ) ;
158
+ await serviceProvider . ResolveRequiredService < IRequestExecutor > ( )
159
+ . ExecuteAsync ( context ) ;
160
+ var output = await serviceProvider . ResolveRequiredService < IOutputFormatter > ( )
161
+ . GetOutput ( context ) ;
162
+ invocationContext . Console . Out . WriteLine ( output . Trim ( ) ) ;
163
+ } ;
164
+ command . SetHandler ( handler ) ;
137
165
return command ;
138
166
}
139
167
140
- // ReSharper disable once InconsistentNaming
141
- public static IServiceCollection RegisterHTTPieServices ( this IServiceCollection serviceCollection )
168
+ public static IServiceCollection RegisterApplicationServices ( this IServiceCollection serviceCollection )
142
169
{
143
170
serviceCollection
144
171
. AddSingleton < IRequestExecutor , RequestExecutor > ( )
@@ -204,53 +231,15 @@ public static IServiceCollection RegisterHTTPieServices(this IServiceCollection
204
231
;
205
232
}
206
233
207
- public static void InitRequestModel ( HttpContext httpContext , string commandLine )
208
- => InitRequestModel ( httpContext , CommandLineStringSplitter . Instance . Split ( commandLine ) . ToArray ( ) ) ;
209
-
210
- public static void InitRequestModel ( HttpContext httpContext , string [ ] args )
211
- {
212
- // should output helps
213
- if ( args . Contains ( "-h" ) || args . Contains ( "-?" ) || args . Contains ( "--help" ) )
214
- {
215
- return ;
216
- }
217
- var requestModel = httpContext . Request ;
218
- requestModel . ParseResult = _commandParser . Parse ( args ) ;
219
-
220
- var method = requestModel . ParseResult . UnmatchedTokens . FirstOrDefault ( x => HttpMethods . Contains ( x ) ) ;
221
- if ( ! string . IsNullOrEmpty ( method ) )
222
- {
223
- requestModel . Method = new HttpMethod ( method ) ;
224
- }
225
- // Url
226
- requestModel . Url = requestModel . ParseResult . UnmatchedTokens . FirstOrDefault ( x =>
227
- ! x . StartsWith ( "-" , StringComparison . Ordinal )
228
- && ! HttpMethods . Contains ( x ) )
229
- ?? string . Empty ;
230
- if ( string . IsNullOrEmpty ( requestModel . Url ) )
231
- {
232
- throw new InvalidOperationException ( "The request url can not be null" ) ;
233
- }
234
- requestModel . Options = args
235
- . Where ( x => x . StartsWith ( '-' ) )
236
- . ToArray ( ) ;
237
- #nullable disable
238
- requestModel . RequestItems = requestModel . ParseResult . UnmatchedTokens
239
- . Except ( new [ ] { method , requestModel . Url } )
240
- . Where ( x => ! x . StartsWith ( '-' ) )
241
- . ToArray ( ) ;
242
- #nullable restore
243
- }
244
-
245
234
public static async Task < int > Handle ( this IServiceProvider services , string [ ] args )
246
235
{
247
- InitRequestModel ( services . GetRequiredService < HttpContext > ( ) , args ) ;
248
- return await _commandParser . InvokeAsync ( args ) ;
236
+ var commandParser = services . ConstructCommand ( ) ;
237
+ return await commandParser . InvokeAsync ( args ) ;
249
238
}
250
239
251
- public static async Task < int > Handle ( this IServiceProvider services , string commandLine )
240
+ public static async Task < int > Handle ( this IServiceProvider services , string commandLine , Func < InvocationContext , Task > ? handler = null )
252
241
{
253
- InitRequestModel ( services . GetRequiredService < HttpContext > ( ) , commandLine ) ;
254
- return await _commandParser . InvokeAsync ( commandLine ) ;
242
+ var commandParser = services . ConstructCommand ( handler ) ;
243
+ return await commandParser . InvokeAsync ( commandLine ) ;
255
244
}
256
245
}
0 commit comments