@@ -32,7 +32,6 @@ namespace Azure.Generator.Management.Providers
3232 internal class ResourceClientProvider : TypeProvider
3333 {
3434 private IReadOnlyCollection < InputServiceMethod > _resourceServiceMethods ;
35- private readonly IReadOnlyList < string > _contextualParameters ;
3635
3736 private FieldProvider _dataField ;
3837 private FieldProvider _resourcetypeField ;
@@ -56,11 +55,11 @@ public ResourceClientProvider(InputClient inputClient)
5655 ResourceData = ManagementClientGenerator . Instance . TypeFactory . CreateModel ( resourceModel ) ! ;
5756 _clientProvider = ManagementClientGenerator . Instance . TypeFactory . CreateClient ( inputClient ) ! ;
5857
59- _contextualParameters = GetContextualParameters ( requestPath ) ;
58+ ContextualParameters = GetContextualParameters ( requestPath ) ;
6059
61- _dataField = new FieldProvider ( FieldModifiers . Private , ResourceData . Type , "_data" , this ) ;
62- _clientDiagonosticsField = new FieldProvider ( FieldModifiers . Private , typeof ( ClientDiagnostics ) , $ "_{ SpecName . ToLower ( ) } ClientDiagnostics", this ) ;
63- _restClientField = new FieldProvider ( FieldModifiers . Private , _clientProvider . Type , $ "_{ SpecName . ToLower ( ) } RestClient", this ) ;
60+ _dataField = new FieldProvider ( FieldModifiers . Private | FieldModifiers . ReadOnly , ResourceData . Type , "_data" , this ) ;
61+ _clientDiagonosticsField = new FieldProvider ( FieldModifiers . Private | FieldModifiers . ReadOnly , typeof ( ClientDiagnostics ) , $ "_{ SpecName . ToLower ( ) } ClientDiagnostics", this ) ;
62+ _restClientField = new FieldProvider ( FieldModifiers . Private | FieldModifiers . ReadOnly , _clientProvider . Type , $ "_{ SpecName . ToLower ( ) } RestClient", this ) ;
6463 }
6564
6665 private IReadOnlyList < string > GetContextualParameters ( string contextualRequestPath )
@@ -77,6 +76,8 @@ private IReadOnlyList<string> GetContextualParameters(string contextualRequestPa
7776 return contextualParameters ;
7877 }
7978
79+ protected IReadOnlyList < string > ContextualParameters { get ; }
80+
8081 protected override string BuildName ( ) => $ "{ SpecName } Resource";
8182
8283 private OperationSourceProvider ? _source ;
@@ -89,7 +90,7 @@ private IReadOnlyList<string> GetContextualParameters(string contextualRequestPa
8990
9091 protected override string BuildRelativeFilePath ( ) => Path . Combine ( "src" , "Generated" , $ "{ Name } .cs") ;
9192
92- protected override FieldProvider [ ] BuildFields ( ) => [ _dataField , _clientDiagonosticsField , _restClientField , _resourcetypeField ] ;
93+ protected override FieldProvider [ ] BuildFields ( ) => [ _clientDiagonosticsField , _restClientField , _dataField , _resourcetypeField ] ;
9394
9495 protected override PropertyProvider [ ] BuildProperties ( )
9596 {
@@ -199,6 +200,8 @@ protected MethodProvider BuildValidateResourceIdMethod()
199200
200201 protected virtual ValueExpression ExpectedResourceTypeForValidation => _resourcetypeField ;
201202
203+ protected virtual CSharpType ResourceClientCharpType => this . Type ;
204+
202205 protected override CSharpType [ ] BuildImplements ( ) => [ typeof ( ArmResource ) ] ;
203206
204207 protected override MethodProvider [ ] BuildMethods ( )
@@ -224,14 +227,14 @@ protected override MethodProvider[] BuildMethods()
224227 return [ BuildValidateResourceIdMethod ( ) , .. operationMethods ] ;
225228 }
226229
227- private MethodProvider BuildOperationMethod ( InputServiceMethod method , MethodProvider convenienceMethod , bool isAsync , bool isUpdateOnly = false )
230+ // TODO: the BuildOperationMethod related code is kind of messy now need to be refactored in a following up PR
231+ protected MethodProvider BuildOperationMethod ( InputServiceMethod method , MethodProvider convenienceMethod , bool isAsync , bool isUpdateOnly = false )
228232 {
229- var operation = method . Operation ;
230233 var signature = new MethodSignature (
231234 isUpdateOnly ? ( isAsync ? "UpdateAsync" : "Update" ) : convenienceMethod . Signature . Name ,
232235 isUpdateOnly ? $ "Update a { SpecName } " : convenienceMethod . Signature . Description ,
233236 convenienceMethod . Signature . Modifiers ,
234- GetOperationMethodReturnType ( isAsync , method is InputLongRunningServiceMethod || method is InputLongRunningPagingServiceMethod , operation . Responses , out var isGeneric ) ,
237+ GetOperationMethodReturnType ( method , isAsync , out var isGeneric ) ,
235238 convenienceMethod . Signature . ReturnDescription ,
236239 GetOperationMethodParameters ( convenienceMethod , method is InputLongRunningServiceMethod ) ,
237240 convenienceMethod . Signature . Attributes ,
@@ -240,58 +243,85 @@ private MethodProvider BuildOperationMethod(InputServiceMethod method, MethodPro
240243 convenienceMethod . Signature . ExplicitInterface ,
241244 convenienceMethod . Signature . NonDocumentComment ) ;
242245
246+ return BuildOperationMethodCore ( method , convenienceMethod , signature , isAsync , isGeneric ) ;
247+ }
248+
249+ protected MethodProvider BuildOperationMethodCore ( InputServiceMethod method , MethodProvider convenienceMethod , MethodSignature signature , bool isAsync , bool isGeneric )
250+ {
243251 var bodyStatements = new MethodBodyStatement [ ]
244252 {
245- UsingDeclare ( "scope" , typeof ( DiagnosticScope ) , _clientDiagonosticsField . Invoke ( nameof ( ClientDiagnostics . CreateScope ) , [ Literal ( $ "{ Type . Namespace } .{ operation . Name } ") ] ) , out var scopeVariable ) ,
253+ UsingDeclare ( "scope" , typeof ( DiagnosticScope ) , _clientDiagonosticsField . Invoke ( nameof ( ClientDiagnostics . CreateScope ) , [ Literal ( $ "{ Name } .{ signature . Name } ") ] ) , out var scopeVariable ) ,
246254 scopeVariable . Invoke ( nameof ( DiagnosticScope . Start ) ) . Terminate ( ) ,
247255 new TryCatchFinallyStatement
248- ( BuildOperationMethodTryStatement ( convenienceMethod , isAsync , method , isGeneric ) , Catch ( Declare < Exception > ( "e" , out var exceptionVarialble ) , [ scopeVariable . Invoke ( nameof ( DiagnosticScope . Failed ) , exceptionVarialble ) . Terminate ( ) , Throw ( ) ] ) )
256+ ( BuildOperationMethodTryStatement ( method , convenienceMethod , signature , isAsync , isGeneric ) ,
257+ Catch ( Declare < Exception > ( "e" , out var exceptionVarialble ) ,
258+ [ scopeVariable . Invoke ( nameof ( DiagnosticScope . Failed ) , exceptionVarialble ) . Terminate ( ) , Throw ( ) ] ) )
249259 } ;
250260
251261 return new MethodProvider ( signature , bodyStatements , this ) ;
252262 }
253263
264+ protected virtual bool SkipMethodParameter ( ParameterProvider parameter )
265+ {
266+ return ContextualParameters . Contains ( parameter . Name ) ;
267+ }
268+
254269 protected IReadOnlyList < ParameterProvider > GetOperationMethodParameters ( MethodProvider convenienceMethod , bool isLongRunning )
255270 {
256271 var result = new List < ParameterProvider > ( ) ;
257272 if ( isLongRunning )
258273 {
259274 result . Add ( KnownAzureParameters . WaitUntil ) ;
260275 }
276+
261277 foreach ( var parameter in convenienceMethod . Signature . Parameters )
262278 {
263- if ( ! _contextualParameters . Contains ( parameter . Name ) )
279+ if ( ! SkipMethodParameter ( parameter ) )
264280 {
265281 result . Add ( parameter ) ;
266282 }
267283 }
284+
268285 return result ;
269286 }
270287
271- protected CSharpType GetOperationMethodReturnType ( bool isAsync , bool isLongRunningOperation , IReadOnlyList < InputOperationResponse > operationResponses , out bool isGeneric )
288+ protected bool IsLongRunningOperation ( InputServiceMethod method )
289+ {
290+ return method is InputLongRunningServiceMethod || method is InputLongRunningPagingServiceMethod ;
291+ }
292+
293+ protected bool IsReturnTypeGeneric ( InputServiceMethod method )
294+ {
295+ var operationResponses = method . Operation . Responses ;
296+ var response = operationResponses . FirstOrDefault ( r => ! r . IsErrorResponse ) ;
297+ var responseBodyType = response ? . BodyType is null ? null : ManagementClientGenerator . Instance . TypeFactory . CreateCSharpType ( response . BodyType ) ;
298+ return IsLongRunningOperation ( method ) && responseBodyType is not null ;
299+ }
300+
301+ protected CSharpType GetOperationMethodReturnType ( InputServiceMethod method , bool isAsync , out bool isGeneric )
272302 {
273- isGeneric = false ;
303+ bool isLongRunningOperation = IsLongRunningOperation ( method ) ;
304+ isGeneric = IsReturnTypeGeneric ( method ) ;
305+
274306 if ( isLongRunningOperation )
275307 {
276- var response = operationResponses . FirstOrDefault ( r => ! r . IsErrorResponse ) ;
277- var responseBodyType = response ? . BodyType is null ? null : ManagementClientGenerator . Instance . TypeFactory . CreateCSharpType ( response . BodyType ) ;
278- if ( responseBodyType is null )
308+ if ( ! isGeneric )
279309 {
280310 return isAsync ? new CSharpType ( typeof ( Task < > ) , typeof ( ArmOperation ) ) : typeof ( ArmOperation ) ;
281311 }
282312 else
283313 {
284- isGeneric = true ;
285- return isAsync ? new CSharpType ( typeof ( Task < > ) , new CSharpType ( typeof ( ArmOperation < > ) , Type ) ) : new CSharpType ( typeof ( ArmOperation < > ) , Type ) ;
314+ return isAsync ? new CSharpType ( typeof ( Task < > ) , new CSharpType ( typeof ( ArmOperation < > ) , ResourceClientCharpType ) ) : new CSharpType ( typeof ( ArmOperation < > ) , ResourceClientCharpType ) ;
286315 }
287316 }
288- return isAsync ? new CSharpType ( typeof ( Task < > ) , new CSharpType ( typeof ( Response < > ) , Type ) ) : new CSharpType ( typeof ( Response < > ) , Type ) ;
317+ return isAsync ? new CSharpType ( typeof ( Task < > ) , new CSharpType ( typeof ( Response < > ) , ResourceClientCharpType ) ) : new CSharpType ( typeof ( Response < > ) , ResourceClientCharpType ) ;
289318 }
290319
291- private TryStatement BuildOperationMethodTryStatement ( MethodProvider convenienceMethod , bool isAsync , InputServiceMethod method , bool isGeneric )
320+ private TryStatement BuildOperationMethodTryStatement ( InputServiceMethod method , MethodProvider convenienceMethod , MethodSignature signature , bool isAsync , bool isGeneric )
292321 {
293322 var operation = method . Operation ;
294323 var cancellationToken = convenienceMethod . Signature . Parameters . Single ( p => p . Type . Equals ( typeof ( CancellationToken ) ) ) ;
324+
295325 var tryStatement = new TryStatement ( ) ;
296326 var contextDeclaration = Declare ( "context" , typeof ( RequestContext ) , New . Instance ( typeof ( RequestContext ) , new Dictionary < ValueExpression , ValueExpression > { { Identifier ( nameof ( RequestContext . CancellationToken ) ) , cancellationToken } } ) , out var contextVariable ) ;
297327 tryStatement . Add ( contextDeclaration ) ;
@@ -325,7 +355,7 @@ private TryStatement BuildOperationMethodTryStatement(MethodProvider convenience
325355 finalStateVia = ( OperationFinalStateVia ) lroPagingMethod . LongRunningServiceMetadata . FinalStateVia ;
326356 }
327357
328- var armOperationType = ! isGeneric ? ManagementClientGenerator . Instance . OutputLibrary . ArmOperation . Type : ManagementClientGenerator . Instance . OutputLibrary . GenericArmOperation . Type . MakeGenericType ( [ Type ] ) ;
358+ var armOperationType = ! isGeneric ? ManagementClientGenerator . Instance . OutputLibrary . ArmOperation . Type : ManagementClientGenerator . Instance . OutputLibrary . GenericArmOperation . Type . MakeGenericType ( [ ResourceClientCharpType ] ) ;
329359 ValueExpression [ ] armOperationArguments = [ _clientDiagonosticsField , This . Property ( "Pipeline" ) , messageVariable . Property ( "Request" ) , isGeneric ? responseVariable . Invoke ( "GetRawResponse" ) : responseVariable , Static ( typeof ( OperationFinalStateVia ) ) . Property ( finalStateVia . ToString ( ) ) ] ;
330360 var operationDeclaration = Declare ( "operation" , armOperationType , New . Instance ( armOperationType , isGeneric ? [ New . Instance ( Source . Type , This . Property ( "Client" ) ) , .. armOperationArguments ] : armOperationArguments ) , out var operationVariable ) ;
331361
@@ -340,15 +370,27 @@ private TryStatement BuildOperationMethodTryStatement(MethodProvider convenience
340370 }
341371 else
342372 {
343- tryStatement . Add ( new IfStatement ( responseVariable . Property ( "Value" ) . Equal ( Null ) )
344- {
345- ( ( KeywordExpression ) ThrowExpression ( New . Instance ( typeof ( RequestFailedException ) , responseVariable . Invoke ( "GetRawResponse" ) ) ) ) . Terminate ( )
346- } ) ;
347- tryStatement . Add ( Return ( Static ( typeof ( Response ) ) . Invoke ( nameof ( Response . FromValue ) , New . Instance ( Type , This . Property ( "Client" ) , responseVariable . Property ( "Value" ) ) , responseVariable . Invoke ( "GetRawResponse" ) ) ) ) ;
373+ tryStatement . Add ( BuildReturnStatements ( responseVariable , signature ) ) ;
348374 }
375+
349376 return tryStatement ;
350377 }
351378
379+ protected virtual MethodBodyStatement BuildReturnStatements ( ValueExpression responseVariable , MethodSignature signature )
380+ {
381+ List < MethodBodyStatement > statements =
382+ [
383+ new IfStatement ( responseVariable . Property ( "Value" ) . Equal ( Null ) )
384+ {
385+ ( ( KeywordExpression ) ThrowExpression ( New . Instance ( typeof ( RequestFailedException ) , responseVariable . Invoke ( "GetRawResponse" ) ) ) ) . Terminate ( )
386+ } ,
387+ ] ;
388+ var returnValueExpression = New . Instance ( ResourceClientCharpType , This . Property ( "Client" ) , responseVariable . Property ( "Value" ) ) ;
389+ statements . Add ( Return ( Static ( typeof ( Response ) ) . Invoke ( nameof ( Response . FromValue ) , returnValueExpression , responseVariable . Invoke ( "GetRawResponse" ) ) ) ) ;
390+
391+ return statements ;
392+ }
393+
352394 private static CSharpType GetResponseType ( MethodProvider convenienceMethod , bool isAsync ) => isAsync ? convenienceMethod . Signature . ReturnType ? . Arguments [ 0 ] ! : convenienceMethod . Signature . ReturnType ! ;
353395
354396 private ValueExpression [ ] PopulateArguments ( IReadOnlyList < ParameterProvider > parameters , MethodProvider convenienceMethod , VariableExpression contextVariable )
@@ -365,7 +407,7 @@ private ValueExpression[] PopulateArguments(IReadOnlyList<ParameterProvider> par
365407 arguments . Add ( This . Property ( nameof ( ArmResource . Id ) ) . Property ( nameof ( ResourceIdentifier . ResourceGroupName ) ) ) ;
366408 }
367409 // TODO: handle parents
368- else if ( parameter . Name . Equals ( _contextualParameters . Last ( ) , StringComparison . InvariantCultureIgnoreCase ) )
410+ else if ( parameter . Name . Equals ( ContextualParameters . Last ( ) , StringComparison . InvariantCultureIgnoreCase ) )
369411 {
370412 arguments . Add ( This . Property ( nameof ( ArmResource . Id ) ) . Property ( nameof ( ResourceIdentifier . Name ) ) ) ;
371413 }
0 commit comments