33// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
44// ------------------------------------------------------------
55
6+ using System ;
67using System . Collections . Generic ;
78using System . Linq ;
89using System . Text . Json . Nodes ;
@@ -32,22 +33,22 @@ protected EdmOperationOperationHandler(OpenApiDocument document) : base(document
3233 {
3334
3435 }
35- private OperationRestrictionsType _operationRestriction ;
36+ private OperationRestrictionsType ? _operationRestriction ;
3637
3738 /// <summary>
3839 /// Gets the navigation source.
3940 /// </summary>
40- protected IEdmNavigationSource NavigationSource { get ; private set ; }
41+ protected IEdmNavigationSource ? NavigationSource { get ; private set ; }
4142
4243 /// <summary>
4344 /// Gets the Edm operation.
4445 /// </summary>
45- protected IEdmOperation EdmOperation { get ; private set ; }
46+ protected IEdmOperation ? EdmOperation { get ; private set ; }
4647
4748 /// <summary>
4849 /// Gets the OData operation segment.
4950 /// </summary>
50- protected ODataOperationSegment OperationSegment { get ; private set ; }
51+ protected ODataOperationSegment ? OperationSegment { get ; private set ; }
5152
5253 /// <summary>
5354 /// Gets a value indicating whether the path has type cast segment or not.
@@ -60,31 +61,38 @@ protected override void Initialize(ODataContext context, ODataPath path)
6061 base . Initialize ( context , path ) ;
6162
6263 // It's bound operation, the first segment must be the navigaiton source.
63- ODataNavigationSourceSegment navigationSourceSegment = path . FirstSegment as ODataNavigationSourceSegment ;
64- NavigationSource = navigationSourceSegment . NavigationSource ;
64+ if ( path . FirstSegment is ODataNavigationSourceSegment navigationSourceSegment )
65+ NavigationSource = navigationSourceSegment . NavigationSource ;
6566
66- OperationSegment = path . LastSegment as ODataOperationSegment ;
67- EdmOperation = OperationSegment . Operation ;
67+ if ( path . LastSegment is ODataOperationSegment opSegment )
68+ {
69+ OperationSegment = opSegment ;
70+ EdmOperation = opSegment . Operation ;
71+ }
6872
6973 HasTypeCast = path . Segments . Any ( s => s is ODataTypeCastSegment ) ;
7074
71- _operationRestriction = Context . Model . GetRecord < OperationRestrictionsType > ( TargetPath , CapabilitiesConstants . OperationRestrictions ) ;
72- var operationRestrictions = Context . Model . GetRecord < OperationRestrictionsType > ( EdmOperation , CapabilitiesConstants . OperationRestrictions ) ;
73- _operationRestriction ? . MergePropertiesIfNull ( operationRestrictions ) ;
74- _operationRestriction ??= operationRestrictions ;
75+ if ( ! string . IsNullOrEmpty ( TargetPath ) )
76+ _operationRestriction = Context ? . Model . GetRecord < OperationRestrictionsType > ( TargetPath , CapabilitiesConstants . OperationRestrictions ) ;
77+ if ( Context is not null && EdmOperation is not null &&
78+ Context . Model . GetRecord < OperationRestrictionsType > ( EdmOperation , CapabilitiesConstants . OperationRestrictions ) is { } operationRestrictions )
79+ {
80+ _operationRestriction ? . MergePropertiesIfNull ( operationRestrictions ) ;
81+ _operationRestriction ??= operationRestrictions ;
82+ }
7583 }
7684
7785 /// <inheritdoc/>
7886 protected override void SetBasicInfo ( OpenApiOperation operation )
7987 {
8088 // Summary
81- operation . Summary = "Invoke " + ( EdmOperation . IsAction ( ) ? "action " : "function " ) + EdmOperation . Name ;
89+ operation . Summary = "Invoke " + ( EdmOperation ? . IsAction ( ) ?? false ? "action " : "function " ) + EdmOperation ? . Name ;
8290
8391 // Description
84- operation . Description = Context . Model . GetDescriptionAnnotation ( TargetPath ) ?? Context . Model . GetDescriptionAnnotation ( EdmOperation ) ;
92+ operation . Description = ( string . IsNullOrEmpty ( TargetPath ) ? null : Context ? . Model . GetDescriptionAnnotation ( TargetPath ) ) ?? Context ? . Model . GetDescriptionAnnotation ( EdmOperation ) ;
8593
8694 // OperationId
87- if ( Context . Settings . EnableOperationId )
95+ if ( Context is { Settings . EnableOperationId : true } && Path is not null )
8896 {
8997 // When the key segment is available,
9098 // its EntityType name will be used
@@ -97,7 +105,7 @@ protected override void SetBasicInfo(OpenApiOperation operation)
97105 {
98106 if ( segment is ODataKeySegment keySegment )
99107 {
100- if ( ! keySegment . IsAlternateKey )
108+ if ( ! keySegment . IsAlternateKey && segment is { EntityType : not null } )
101109 {
102110 identifiers . Add ( segment . EntityType . Name ) ;
103111 continue ;
@@ -113,7 +121,7 @@ protected override void SetBasicInfo(OpenApiOperation operation)
113121 identifiers . Add ( keySegment . Identifier ) ;
114122 }
115123 }
116- else if ( segment is ODataOperationSegment opSegment )
124+ else if ( segment is ODataOperationSegment { Identifier : not null } opSegment )
117125 {
118126 if ( opSegment . Operation is IEdmFunction function && Context . Model . IsOperationOverload ( function ) )
119127 {
@@ -123,9 +131,9 @@ protected override void SetBasicInfo(OpenApiOperation operation)
123131 : ( pathHash + opSegment . GetPathHash ( Context . Settings ) ) . GetHashSHA256 ( ) [ ..4 ] ;
124132 }
125133
126- identifiers . Add ( segment . Identifier ) ;
134+ identifiers . Add ( opSegment . Identifier ) ;
127135 }
128- else
136+ else if ( ! string . IsNullOrEmpty ( segment . Identifier ) )
129137 {
130138 identifiers . Add ( segment . Identifier ) ;
131139 }
@@ -154,11 +162,12 @@ protected override void SetTags(OpenApiOperation operation)
154162 {
155163 Name = tagName ,
156164 } ;
165+ tag . Extensions ??= new Dictionary < string , IOpenApiExtension > ( ) ;
157166 tag . Extensions . Add ( Constants . xMsTocType , new OpenApiAny ( "container" ) ) ;
158167 operation . Tags ??= new HashSet < OpenApiTagReference > ( ) ;
159168 operation . Tags . Add ( new OpenApiTagReference ( tag . Name , _document ) ) ;
160169
161- Context . AppendTag ( tag ) ;
170+ Context ? . AppendTag ( tag ) ;
162171
163172 base . SetTags ( operation ) ;
164173 }
@@ -169,12 +178,13 @@ protected override void SetTags(OpenApiOperation operation)
169178 /// <param name="tagName">The generated tag name.</param>
170179 /// <param name="skip">The number of segments to skip.</param>
171180 private void GenerateTagName ( out string tagName , int skip = 1 )
172- {
181+ {
182+ if ( Path is null ) throw new InvalidOperationException ( "Path is null." ) ;
173183 var targetSegment = Path . Segments . Reverse ( ) . Skip ( skip ) . FirstOrDefault ( ) ;
174184
175185 switch ( targetSegment )
176186 {
177- case ODataNavigationPropertySegment :
187+ case ODataNavigationPropertySegment when Context is not null :
178188 tagName = EdmModelHelper . GenerateNavigationPropertyPathTagName ( Path , Context ) ;
179189 break ;
180190 case ODataOperationImportSegment :
@@ -184,7 +194,7 @@ private void GenerateTagName(out string tagName, int skip = 1)
184194 GenerateTagName ( out tagName , skip ) ;
185195 break ;
186196 default :
187- tagName = NavigationSource . Name + "." + NavigationSource . EntityType . Name ;
197+ tagName = NavigationSource ? . Name + "." + NavigationSource ? . EntityType . Name ;
188198 if ( EdmOperation . IsAction ( ) )
189199 {
190200 tagName += ".Actions" ;
@@ -202,17 +212,17 @@ protected override void SetParameters(OpenApiOperation operation)
202212 {
203213 base . SetParameters ( operation ) ;
204214
205- if ( EdmOperation . IsFunction ( ) )
215+ if ( EdmOperation . IsFunction ( ) && EdmOperation is IEdmFunction function )
206216 {
207- IEdmFunction function = ( IEdmFunction ) EdmOperation ;
208217 AppendSystemQueryOptions ( function , operation ) ;
209218 }
210219 }
211220
212221 /// <inheritdoc/>
213222 protected override void SetResponses ( OpenApiOperation operation )
214223 {
215- operation . Responses = Context . CreateResponses ( EdmOperation , _document ) ;
224+ if ( EdmOperation is not null && Context is not null )
225+ operation . Responses = Context . CreateResponses ( EdmOperation , _document ) ;
216226 base . SetResponses ( operation ) ;
217227 }
218228
@@ -224,7 +234,7 @@ protected override void SetSecurity(OpenApiOperation operation)
224234 return ;
225235 }
226236
227- operation . Security = Context . CreateSecurityRequirements ( _operationRestriction . Permissions , _document ) . ToList ( ) ;
237+ operation . Security = Context ? . CreateSecurityRequirements ( _operationRestriction . Permissions , _document ) . ToList ( ) ;
228238 }
229239
230240 /// <inheritdoc/>
@@ -248,8 +258,9 @@ protected override void AppendCustomParameters(OpenApiOperation operation)
248258
249259 private void AppendSystemQueryOptions ( IEdmFunction function , OpenApiOperation operation )
250260 {
251- if ( function . ReturnType . IsCollection ( ) )
261+ if ( function . ReturnType . IsCollection ( ) && Context is not null )
252262 {
263+ operation . Parameters ??= [ ] ;
253264 // $top
254265 if ( Context . CreateTop ( function , _document ) is { } topParameter )
255266 {
@@ -306,10 +317,10 @@ private void AppendSystemQueryOptions(IEdmFunction function, OpenApiOperation op
306317 /// <inheritdoc/>
307318 protected override void SetCustomLinkRelType ( )
308319 {
309- if ( Context . Settings . CustomHttpMethodLinkRelMapping != null && EdmOperation != null )
320+ if ( Context is { Settings . CustomHttpMethodLinkRelMapping : not null } && EdmOperation != null )
310321 {
311322 LinkRelKey key = EdmOperation . IsAction ( ) ? LinkRelKey . Action : LinkRelKey . Function ;
312- Context . Settings . CustomHttpMethodLinkRelMapping . TryGetValue ( key , out string linkRelValue ) ;
323+ Context . Settings . CustomHttpMethodLinkRelMapping . TryGetValue ( key , out var linkRelValue ) ;
313324 CustomLinkRel = linkRelValue ;
314325 }
315326 }
@@ -321,9 +332,9 @@ protected override void SetExternalDocs(OpenApiOperation operation)
321332 {
322333 var externalDocs = ( string . IsNullOrEmpty ( TargetPath ) , string . IsNullOrEmpty ( CustomLinkRel ) ) switch
323334 {
324- ( _, true ) => null ,
325335 ( false , false ) => Context . Model . GetLinkRecord ( TargetPath ! , CustomLinkRel ! ) ,
326- ( true , false ) => Context . Model . GetLinkRecord ( EdmOperation , CustomLinkRel ! ) ,
336+ ( true , false ) when EdmOperation is not null => Context . Model . GetLinkRecord ( EdmOperation , CustomLinkRel ! ) ,
337+ ( _, _) => null ,
327338 } ;
328339
329340 if ( externalDocs != null )
@@ -340,9 +351,9 @@ protected override void SetExternalDocs(OpenApiOperation operation)
340351 // <inheritdoc/>
341352 protected override void SetExtensions ( OpenApiOperation operation )
342353 {
343- if ( Context is { Settings . EnablePagination : true } && EdmOperation . ReturnType ? . TypeKind ( ) == EdmTypeKind . Collection )
354+ if ( Context is { Settings . EnablePagination : true } && EdmOperation ? . ReturnType ? . TypeKind ( ) == EdmTypeKind . Collection )
344355 {
345- JsonObject extension = new JsonObject
356+ var extension = new JsonObject
346357 {
347358 { "nextLinkName" , "@odata.nextLink" } ,
348359 { "operationName" , Context . Settings . PageableOperationName }
0 commit comments