1- // Copyright (c) Microsoft Corporation. All rights reserved.
1+ // Copyright (c) Microsoft Corporation. All rights reserved.
22// Licensed under the MIT license.
33
44using System ;
@@ -129,7 +129,7 @@ public static async Task<T> LoadAsync<T>(string url, OpenApiSpecVersion version,
129129 /// <param name="cancellationToken">Propagates notification that operations should be cancelled.</param>
130130 /// <param name="format">The Open API format</param>
131131 /// <returns></returns>
132- public static async Task < ReadResult > LoadAsync ( Stream input , string format , OpenApiReaderSettings settings = null , CancellationToken cancellationToken = default )
132+ public static async Task < ReadResult > LoadAsync ( Stream input , string format = null , OpenApiReaderSettings settings = null , CancellationToken cancellationToken = default )
133133 {
134134 Utils . CheckArgumentNull ( format , nameof ( format ) ) ;
135135 settings ??= new OpenApiReaderSettings ( ) ;
@@ -173,6 +173,27 @@ public static ReadResult Parse(string input,
173173 return InternalLoad ( stream , format , settings ) ;
174174 }
175175
176+ /// <summary>
177+ /// Reads the input string and parses it into an Open API document.
178+ /// </summary>
179+ /// <param name="input">The input string.</param>
180+ /// <param name="version"></param>
181+ /// <param name="diagnostic">The diagnostic entity containing information from the reading process.</param>
182+ /// <param name="format">The Open API format</param>
183+ /// <param name="settings">The OpenApi reader settings.</param>
184+ /// <returns>An OpenAPI document instance.</returns>
185+ public static T Parse < T > ( string input ,
186+ OpenApiSpecVersion version ,
187+ out OpenApiDiagnostic diagnostic ,
188+ string format = null ,
189+ OpenApiReaderSettings settings = null ) where T : IOpenApiElement
190+ {
191+ format ??= OpenApiConstants . Json ;
192+ settings ??= new OpenApiReaderSettings ( ) ;
193+ var stream = new MemoryStream ( Encoding . UTF8 . GetBytes ( input ) ) ;
194+ return Load < T > ( stream , version , format , out diagnostic , settings ) ;
195+ }
196+
176197 private static async Task < ReadResult > InternalLoadAsync ( Stream input , string format , OpenApiReaderSettings settings = null , CancellationToken cancellationToken = default )
177198 {
178199 Utils . CheckArgumentNull ( format , nameof ( format ) ) ;
@@ -190,7 +211,6 @@ private static async Task<ReadResult> InternalLoadAsync(Stream input, string for
190211 }
191212 }
192213
193-
194214 return readResult ;
195215 }
196216
@@ -220,168 +240,49 @@ private static ReadResult InternalLoad(MemoryStream input, string format, OpenAp
220240 return readResult ;
221241 }
222242
223-
224- /// <summary>
225- /// Reads the input string and parses it into an Open API document.
226- /// </summary>
227- /// <param name="input">The input string.</param>
228- /// <param name="version"></param>
229- /// <param name="diagnostic">The diagnostic entity containing information from the reading process.</param>
230- /// <param name="format">The Open API format</param>
231- /// <param name="settings">The OpenApi reader settings.</param>
232- /// <returns>An OpenAPI document instance.</returns>
233- public static T Parse < T > ( string input ,
234- OpenApiSpecVersion version ,
235- out OpenApiDiagnostic diagnostic ,
236- string format = null ,
237- OpenApiReaderSettings settings = null ) where T : IOpenApiElement
238- {
239- format ??= OpenApiConstants . Json ;
240- settings ??= new OpenApiReaderSettings ( ) ;
241- var stream = new MemoryStream ( Encoding . UTF8 . GetBytes ( input ) ) ;
242- return Load < T > ( stream , version , format , out diagnostic , settings ) ;
243- }
244-
245- /// <summary>
246- /// Reads the stream input and parses the fragment of an OpenAPI description into an Open API Element.
247- /// </summary>
248- /// <typeparam name="T"></typeparam>
249- /// <param name="url">The path to the OpenAPI file</param>
250- /// <param name="version">Version of the OpenAPI specification that the fragment conforms to.</param>
251- /// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing.</param>
252- /// <param name="settings">The OpenApiReader settings.</param>
253- /// <returns>Instance of newly created IOpenApiElement.</returns>
254- /// <returns>The OpenAPI element.</returns>
255- public static T Load < T > ( string url , OpenApiSpecVersion version , out OpenApiDiagnostic diagnostic , OpenApiReaderSettings settings = null ) where T : IOpenApiElement
256- {
257- var format = GetFormat ( url ) ;
258- settings ??= new OpenApiReaderSettings ( ) ;
259-
260- #pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
261- var stream = GetStreamAsync ( url ) . GetAwaiter ( ) . GetResult ( ) ;
262- #pragma warning restore VSTHRD002 // Avoid problematic synchronous waits
263-
264- return Load < T > ( stream as MemoryStream , version , format , out diagnostic , settings ) ;
265- }
266-
267-
268- /// <summary>
269- /// Reads the stream input and ensures it is buffered before passing it to the Load method.
270- /// </summary>
271- /// <typeparam name="T"></typeparam>
272- /// <param name="input"></param>
273- /// <param name="version"></param>
274- /// <param name="format"></param>
275- /// <param name="diagnostic"></param>
276- /// <param name="settings"></param>
277- /// <returns></returns>
278- public static T Load < T > ( Stream input , OpenApiSpecVersion version , string format , out OpenApiDiagnostic diagnostic , OpenApiReaderSettings settings = null ) where T : IOpenApiElement
279- {
280- if ( input is MemoryStream memoryStream )
281- {
282- return Load < T > ( memoryStream , version , format , out diagnostic , settings ) ;
283- } else {
284- memoryStream = new MemoryStream ( ) ;
285- input . CopyTo ( memoryStream ) ;
286- memoryStream . Position = 0 ;
287- return Load < T > ( memoryStream , version , format , out diagnostic , settings ) ;
288- }
289- }
290-
291-
292- /// <summary>
293- /// Reads the stream input and parses the fragment of an OpenAPI description into an Open API Element.
294- /// </summary>
295- /// <typeparam name="T"></typeparam>
296- /// <param name="input">Stream containing OpenAPI description to parse.</param>
297- /// <param name="version">Version of the OpenAPI specification that the fragment conforms to.</param>
298- /// <param name="format"></param>
299- /// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing.</param>
300- /// <param name="settings">The OpenApiReader settings.</param>
301- /// <returns>Instance of newly created IOpenApiElement.</returns>
302- /// <returns>The OpenAPI element.</returns>
303- public static T Load < T > ( MemoryStream input , OpenApiSpecVersion version , string format , out OpenApiDiagnostic diagnostic , OpenApiReaderSettings settings = null ) where T : IOpenApiElement
304- {
305- format ??= OpenApiConstants . Json ;
306- return OpenApiReaderRegistry . GetReader ( format ) . ReadFragment < T > ( input , version , out diagnostic , settings ) ;
307- }
308-
309- private static string GetContentType ( string url )
243+ private static async Task < ( Stream , string ) > RetrieveStreamAndFormatAsync ( string url )
310244 {
311245 if ( ! string . IsNullOrEmpty ( url ) )
312246 {
313- #pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
314- var response = _httpClient . GetAsync ( url ) . GetAwaiter ( ) . GetResult ( ) ;
315- #pragma warning restore VSTHRD002 // Avoid problematic synchronous waits
316-
317- var mediaType = response . Content . Headers . ContentType . MediaType ;
318- return mediaType . Split ( ";" . ToCharArray ( ) , StringSplitOptions . RemoveEmptyEntries ) . First ( ) ;
319- }
320-
321- return null ;
322- }
247+ Stream stream ;
248+ string format ;
323249
324- /// <summary>
325- /// Infers the OpenAPI format from the input URL.
326- /// </summary>
327- /// <param name="url">The input URL.</param>
328- /// <returns>The OpenAPI format.</returns>
329- public static string GetFormat ( string url )
330- {
331- if ( ! string . IsNullOrEmpty ( url ) )
332- {
333- if ( url . StartsWith ( "http" , StringComparison . OrdinalIgnoreCase ) || url . StartsWith ( "https" , StringComparison . OrdinalIgnoreCase ) )
250+ if ( url . StartsWith ( "http" , StringComparison . OrdinalIgnoreCase )
251+ || url . StartsWith ( "https" , StringComparison . OrdinalIgnoreCase ) )
334252 {
335- // URL examples ---> https://example.com/path/to/file.json, https://example.com/path/to/file.yaml
336- var path = new Uri ( url ) ;
337- var urlSuffix = path . Segments [ path . Segments . Length - 1 ] . Split ( '.' ) . LastOrDefault ( ) ;
338-
339- return ! string . IsNullOrEmpty ( urlSuffix ) ? urlSuffix : GetContentType ( url ) . Split ( '/' ) . LastOrDefault ( ) ;
253+ var response = await _httpClient . GetAsync ( url ) ;
254+ var mediaType = response . Content . Headers . ContentType . MediaType ;
255+ var contentType = mediaType . Split ( ";" . ToCharArray ( ) , StringSplitOptions . RemoveEmptyEntries ) [ 0 ] ;
256+ format = contentType . Split ( '/' ) . LastOrDefault ( ) ;
257+ stream = await response . Content . ReadAsStreamAsync ( ) ;
258+ return ( stream , format ) ;
340259 }
341260 else
342261 {
343- return Path . GetExtension ( url ) . Split ( '.' ) . LastOrDefault ( ) ;
262+ format = Path . GetExtension ( url ) . Split ( '.' ) . LastOrDefault ( ) ;
263+
264+ try
265+ {
266+ var fileInput = new FileInfo ( url ) ;
267+ stream = fileInput . OpenRead ( ) ;
268+ }
269+ catch ( Exception ex ) when (
270+ ex is
271+ FileNotFoundException or
272+ PathTooLongException or
273+ DirectoryNotFoundException or
274+ IOException or
275+ UnauthorizedAccessException or
276+ SecurityException or
277+ NotSupportedException )
278+ {
279+ throw new InvalidOperationException ( $ "Could not open the file at { url } ", ex ) ;
280+ }
281+
282+ return ( stream , format ) ;
344283 }
345284 }
346- return null ;
347- }
348-
349- private static async Task < Stream > GetStreamAsync ( string url )
350- {
351- Stream stream ;
352- if ( url . StartsWith ( "http" , StringComparison . OrdinalIgnoreCase ) || url . StartsWith ( "https" , StringComparison . OrdinalIgnoreCase ) )
353- {
354- try
355- {
356- stream = await _httpClient . GetStreamAsync ( new Uri ( url ) ) ;
357- }
358- catch ( HttpRequestException ex )
359- {
360- throw new InvalidOperationException ( $ "Could not download the file at { url } ", ex ) ;
361- }
362- }
363- else
364- {
365- try
366- {
367- var fileInput = new FileInfo ( url ) ;
368- stream = fileInput . OpenRead ( ) ;
369- }
370- catch ( Exception ex ) when (
371- ex is
372- FileNotFoundException or
373- PathTooLongException or
374- DirectoryNotFoundException or
375- IOException or
376- UnauthorizedAccessException or
377- SecurityException or
378- NotSupportedException )
379- {
380- throw new InvalidOperationException ( $ "Could not open the file at { url } ", ex ) ;
381- }
382- }
383-
384- return stream ;
285+ return ( null , null ) ;
385286 }
386287 }
387288}
0 commit comments