diff --git a/src/Configuration/CompositeChangeToken.cs b/src/Configuration/CompositeChangeToken.cs index 039570a7..5e05406f 100644 --- a/src/Configuration/CompositeChangeToken.cs +++ b/src/Configuration/CompositeChangeToken.cs @@ -3,14 +3,14 @@ namespace Microsoft.Extensions.DependencyInjection; public class CompositeChangeToken(params IChangeToken[] changeTokens) : IChangeToken { - private readonly IChangeToken[] _changeTokens = changeTokens; - - public bool ActiveChangeCallbacks => Exists(_changeTokens, t => t.ActiveChangeCallbacks); - - public bool HasChanged => Exists(_changeTokens, t => t.HasChanged); - - public IDisposable RegisterChangeCallback(Action callback, object? state) => - new CompositeDisposable( - _changeTokens.Select(t => t.RegisterChangeCallback(callback, state)) - ); + private readonly IChangeToken[] _changeTokens = changeTokens; + +public bool ActiveChangeCallbacks => Exists(_changeTokens, t => t.ActiveChangeCallbacks); + +public bool HasChanged => Exists(_changeTokens, t => t.HasChanged); + +public IDisposable RegisterChangeCallback(Action callback, object? state) => + new CompositeDisposable( + _changeTokens.Select(t => t.RegisterChangeCallback(callback, state)) + ); } diff --git a/src/Configuration/JsonFileConfigurationExtensions.cs b/src/Configuration/JsonFileConfigurationExtensions.cs index e7f3f457..1ce175f3 100644 --- a/src/Configuration/JsonFileConfigurationExtensions.cs +++ b/src/Configuration/JsonFileConfigurationExtensions.cs @@ -104,8 +104,8 @@ bool recursive .EnumerateFiles( "*.json", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly - ) - // .Where(IsForThisEnvironment) + ) + // .Where(IsForThisEnvironment) .OrderBy(jsonFile => jsonFile.Name); internal static string RemoveEnvironmentIfIsForThisEnvironment(this string jsonFileName) => diff --git a/src/Http/Mime/ApplicationMediaTypeNames.cs b/src/Http/Mime/ApplicationMediaTypeNames.cs index a13d00b3..0fac6481 100644 --- a/src/Http/Mime/ApplicationMediaTypeNames.cs +++ b/src/Http/Mime/ApplicationMediaTypeNames.cs @@ -80,8 +80,8 @@ public static class ApplicationMediaTypeNames public const string OpenApiV2Yaml = $"{OpenApiYaml}; version=2.x"; /// ; version=3.x - public const string OpenApiV3Json = $"{OpenApiJson}; version=3.x"; - - /// ; version=3.x + public const string OpenApiV3Json = $"{OpenApiJson}; version=3.x"; + + /// ; version=3.x public const string OpenApiV3Yaml = $"{OpenApiYaml}; version=3.x"; } diff --git a/src/Http/Mime/TempMediaType.cs b/src/Http/Mime/TempMediaType.cs index fcfc0352..874edb01 100644 --- a/src/Http/Mime/TempMediaType.cs +++ b/src/Http/Mime/TempMediaType.cs @@ -21,68 +21,68 @@ namespace Dgmjr.Mime; public readonly record struct TempMediaType(string Name) : IMediaType { - public string DisplayName { get; } = Name; - private static readonly MD5 MD5 = MD5.Create(); - public string[] Synonyms { get; init; } = Empty(); - Uri IHaveAUri.Uri => new(UriString); - object IIdentifiable.Id => Id; - public int Id => 0; - public int Value => Id; - public string UriString => "urn:publicid:temp:media-type:" + DisplayName.ToKebabCase(); - public string GuidString => MD5.ComputeHash(UriString.ToUTF8Bytes()).ToHexString(); - public guid Guid => new(GuidString); - public string Description => Name; - public string GroupName => Name; - public string ShortName => Name; - public string Name => DisplayName; - public int Order => 0; - public string Prompt => ""; - - uri IMediaType.Uri => UriString; - uri IHaveAuri.Uri => UriString; - - object IHaveAValue.Value => Value; - - int IHaveAValue.Value => Id; - - MediaTypes IHaveAValue.Value => MediaTypes.Any; - - TypeCode IConvertible.GetTypeCode() => TypeCode.Object; - - bool IConvertible.ToBoolean(IFormatProvider? provider) => true; - - byte IConvertible.ToByte(IFormatProvider? provider) => Convert.ToByte(Value); - - char IConvertible.ToChar(IFormatProvider? provider) => Convert.ToChar(Value); - - datetime IConvertible.ToDateTime(IFormatProvider? provider) => Convert.ToDateTime(Value); - - decimal IConvertible.ToDecimal(IFormatProvider? provider) => Convert.ToDecimal(Value); - - double IConvertible.ToDouble(IFormatProvider? provider) => Convert.ToDouble(Value); - - short IConvertible.ToInt16(IFormatProvider? provider) => Convert.ToInt16(Value); - - int IConvertible.ToInt32(IFormatProvider? provider) => Convert.ToInt32(Value); - - long IConvertible.ToInt64(IFormatProvider? provider) => Convert.ToInt64(Value); - - sbyte IConvertible.ToSByte(IFormatProvider? provider) => Convert.ToSByte(Value); - - float IConvertible.ToSingle(IFormatProvider? provider) => Convert.ToSingle(Value); - - string IConvertible.ToString(IFormatProvider? provider) => Convert.ToString(Value); - - object IConvertible.ToType(type conversionType, IFormatProvider? provider) => - Convert.ChangeType(Value, conversionType); - - ushort IConvertible.ToUInt16(IFormatProvider? provider) => Convert.ToUInt16(Value); - - uint IConvertible.ToUInt32(IFormatProvider? provider) => Convert.ToUInt32(Value); - - ulong IConvertible.ToUInt64(IFormatProvider? provider) => Convert.ToUInt64(Value); - - bool IEquatable.Equals(int other) => Id == other; - - bool IEquatable.Equals(IMediaType other) => this.Matches(other); + public string DisplayName { get; } = Name; +private static readonly MD5 MD5 = MD5.Create(); +public string[] Synonyms { get; init; } = Empty(); +Uri IHaveAUri.Uri => new(UriString); +object IIdentifiable.Id => Id; +public int Id => 0; +public int Value => Id; +public string UriString => "urn:publicid:temp:media-type:" + DisplayName.ToKebabCase(); +public string GuidString => MD5.ComputeHash(UriString.ToUTF8Bytes()).ToHexString(); +public guid Guid => new(GuidString); +public string Description => Name; +public string GroupName => Name; +public string ShortName => Name; +public string Name => DisplayName; +public int Order => 0; +public string Prompt => ""; + +uri IMediaType.Uri => UriString; +uri IHaveAuri.Uri => UriString; + +object IHaveAValue.Value => Value; + +int IHaveAValue.Value => Id; + +MediaTypes IHaveAValue.Value => MediaTypes.Any; + +TypeCode IConvertible.GetTypeCode() => TypeCode.Object; + +bool IConvertible.ToBoolean(IFormatProvider? provider) => true; + +byte IConvertible.ToByte(IFormatProvider? provider) => Convert.ToByte(Value); + +char IConvertible.ToChar(IFormatProvider? provider) => Convert.ToChar(Value); + +datetime IConvertible.ToDateTime(IFormatProvider? provider) => Convert.ToDateTime(Value); + +decimal IConvertible.ToDecimal(IFormatProvider? provider) => Convert.ToDecimal(Value); + +double IConvertible.ToDouble(IFormatProvider? provider) => Convert.ToDouble(Value); + +short IConvertible.ToInt16(IFormatProvider? provider) => Convert.ToInt16(Value); + +int IConvertible.ToInt32(IFormatProvider? provider) => Convert.ToInt32(Value); + +long IConvertible.ToInt64(IFormatProvider? provider) => Convert.ToInt64(Value); + +sbyte IConvertible.ToSByte(IFormatProvider? provider) => Convert.ToSByte(Value); + +float IConvertible.ToSingle(IFormatProvider? provider) => Convert.ToSingle(Value); + +string IConvertible.ToString(IFormatProvider? provider) => Convert.ToString(Value); + +object IConvertible.ToType(type conversionType, IFormatProvider? provider) => + Convert.ChangeType(Value, conversionType); + +ushort IConvertible.ToUInt16(IFormatProvider? provider) => Convert.ToUInt16(Value); + +uint IConvertible.ToUInt32(IFormatProvider? provider) => Convert.ToUInt32(Value); + +ulong IConvertible.ToUInt64(IFormatProvider? provider) => Convert.ToUInt64(Value); + +bool IEquatable.Equals(int other) => Id == other; + +bool IEquatable.Equals(IMediaType other) => this.Matches(other); } diff --git a/src/Http/ResponseCodes/ResponseCode.cs b/src/Http/ResponseCodes/ResponseCode.cs index 5f8480e0..aef9cb85 100644 --- a/src/Http/ResponseCodes/ResponseCode.cs +++ b/src/Http/ResponseCodes/ResponseCode.cs @@ -51,8 +51,8 @@ public enum StatusCode : ushort /// 200 /// [Display( - Name = "OK", - // Description = "The request has succeeded. The meaning of the success depends on the HTTP method:" + Name = "OK", + // Description = "The request has succeeded. The meaning of the success depends on the HTTP method:" Description = "Yay! You didn't fuck up!" )] [Uri($"{UriBase}200")] @@ -63,8 +63,8 @@ public enum StatusCode : ushort /// 201 /// [Display( - Name = "Created", - // Description = "The request has succeeded and a new resource has been created as a result. This is typically the response sent after a PUT request." + Name = "Created", + // Description = "The request has succeeded and a new resource has been created as a result. This is typically the response sent after a PUT request." Description = "I created the thing for you." )] [Uri($"{UriBase}201")] @@ -75,8 +75,8 @@ public enum StatusCode : ushort /// 202 /// [Display( - Name = "Accepted", - // Description = "The request has been received but not yet acted upon. It is non-committal, meaning that there is no way in HTTP to later send an asynchronous response indicating the outcome of processing the request. It is intended for cases where another process or server handles the request, or for batch processing." + Name = "Accepted", + // Description = "The request has been received but not yet acted upon. It is non-committal, meaning that there is no way in HTTP to later send an asynchronous response indicating the outcome of processing the request. It is intended for cases where another process or server handles the request, or for batch processing." Description = "I got it and you can go do other stuff while I work on it for you." )] [Uri($"{UriBase}202")] diff --git a/src/Http/Services/AddHttpServicesExtensions.cs b/src/Http/Services/AddHttpServicesExtensions.cs index 01d6cecc..2869e94b 100644 --- a/src/Http/Services/AddHttpServicesExtensions.cs +++ b/src/Http/Services/AddHttpServicesExtensions.cs @@ -125,7 +125,7 @@ public static IHostApplicationBuilder AddHttpServices( ); } - if(options.IIS != null) + if (options.IIS != null) { builder.Services.Configure( options => @@ -133,7 +133,7 @@ public static IHostApplicationBuilder AddHttpServices( ); } - if(options.Kestrel != null) + if (options.Kestrel != null) { builder.Services.Configure( options => @@ -141,7 +141,7 @@ public static IHostApplicationBuilder AddHttpServices( ); } - if(options.ExceptionHandling != null) + if (options.ExceptionHandling != null) { builder.Services.Configure( options => diff --git a/src/Http/Services/CorsOptions.cs b/src/Http/Services/CorsOptions.cs index 23d3733d..0731c908 100644 --- a/src/Http/Services/CorsOptions.cs +++ b/src/Http/Services/CorsOptions.cs @@ -6,7 +6,7 @@ namespace Dgmjr.AspNetCore.Http.Services; string, Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicy >; -using ICorsPolicyCollection = ICollection>; +using ICorsPolicyCollection = ICollection>; using ICorsPolicyEnumerable = IEnumerable>; public class CorsOptions diff --git a/src/Http/Services/CorsOptionsConfigurator.cs b/src/Http/Services/CorsOptionsConfigurator.cs index d787cba8..d6b97ee0 100644 --- a/src/Http/Services/CorsOptionsConfigurator.cs +++ b/src/Http/Services/CorsOptionsConfigurator.cs @@ -7,12 +7,12 @@ namespace Dgmjr.AspNetCore.Http.Services; public class CorsOptionsConfigurator(IConfiguration configuration) : IConfigureOptions { - public const string CorsOptionsSection = $"{Http}:{Cors}"; - - private readonly IConfiguration _configuration = configuration; - - public void Configure(CorsOptions options) - { - var corsPolicyDictionary = _configuration.GetSection(CorsOptionsSection).Get>(); - } + public const string CorsOptionsSection = $"{Http}:{Cors}"; + +private readonly IConfiguration _configuration = configuration; + +public void Configure(CorsOptions options) +{ + var corsPolicyDictionary = _configuration.GetSection(CorsOptionsSection).Get>(); +} } diff --git a/src/Http/Services/UseHttpServicesExtensions.cs b/src/Http/Services/UseHttpServicesExtensions.cs index 00bec872..54fc20cf 100644 --- a/src/Http/Services/UseHttpServicesExtensions.cs +++ b/src/Http/Services/UseHttpServicesExtensions.cs @@ -11,7 +11,7 @@ public static IApplicationBuilder UseHttpServices(this IApplicationBuilder app) { var options = app.ApplicationServices.GetRequiredService>().Value; - if(options.UseRequestDecompression) + if (options.UseRequestDecompression) { app.UseRequestDecompression(); } @@ -21,37 +21,37 @@ public static IApplicationBuilder UseHttpServices(this IApplicationBuilder app) app.UseResponseCompression(); } - if(options.UseFileServer) + if (options.UseFileServer) { app.UseFileServer(options.FileServer); - if(options.FileServer.EnableDefaultFiles) + if (options.FileServer.EnableDefaultFiles) { app.UseDefaultFiles(options.FileServer.DefaultFilesOptions); } - if(options.FileServer.EnableDirectoryBrowsing) + if (options.FileServer.EnableDirectoryBrowsing) { app.UseDirectoryBrowser(options.FileServer.DirectoryBrowserOptions); } - if(options.FileServer.StaticFileOptions != null || options.UseStaticFiles) + if (options.FileServer.StaticFileOptions != null || options.UseStaticFiles) { app.UseStaticFiles(options.FileServer.StaticFileOptions); } } - if(options.UseResponseCaching) + if (options.UseResponseCaching) { app.UseResponseCaching(); } - if(options.UseForwardedHeaders) + if (options.UseForwardedHeaders) { app.UseForwardedHeaders(options.ForwardedHeaders); } - if(options.UseCors) + if (options.UseCors) { app.UseCors(); // _ = app.UseCors(corsOptions => corsOptions @@ -63,27 +63,27 @@ public static IApplicationBuilder UseHttpServices(this IApplicationBuilder app) // ); } - if(options.UseCookiePolicy) + if (options.UseCookiePolicy) { app.UseCookiePolicy(options.CookiePolicy); } - if(options.UseSession) + if (options.UseSession) { app.UseSession(options.Session); } - if(options.UseHsts) + if (options.UseHsts) { app.UseHsts(); } - if(options.UseHttpsRedirection) + if (options.UseHttpsRedirection) { app.UseHttpsRedirection(); } - if(options.UseExceptionHandler) + if (options.UseExceptionHandler) { app.UseExceptionHandler(options.ExceptionHandling); } diff --git a/src/MicrosoftGraph/ApplicationService.cs b/src/MicrosoftGraph/ApplicationService.cs index 656d4430..f216a6cc 100644 --- a/src/MicrosoftGraph/ApplicationService.cs +++ b/src/MicrosoftGraph/ApplicationService.cs @@ -3,28 +3,28 @@ namespace Dgmjr.MicrosoftGraph; public class ApplicationService(GraphServiceClient graph, ILogger logger, IConfiguration configuration) : ILog { - public ILogger Logger => logger; - private readonly IConfiguration _configuration = configuration; - private MicrosoftB2CGraphOptions GraphOptions => _configuration.GetSection(Constants.AzureAdB2C).Get(); - private MicrosoftIdentityOptions IdentityOptions => _configuration.GetSection(Constants.AzureAdB2C).Get(); - protected virtual GraphServiceClient Graph => graph; - public guid ExtensionsAppClientId => GraphOptions.AzureAdB2CExtensionsApplicationId; - - /// Retrieves the client ID from "AzureAdB2C:ClientIf" - public string ClientId => - IdentityOptions?.ClientId ?? - throw new InvalidOperationException("ClientId is required"); - - public async Task GetApplication() - => await Graph.Applications[ClientId].Request().GetAsync(); - - public async Task GetExtensionsApplication() - => await Graph.Applications[GraphOptions.AzureAdB2CExtensionsApplicationId.ToString()].Request().GetAsync(); - - public async Task GetExtensionPropertiesAsync(CancellationToken cancellationToken = default) - { - - var extensionProperties = await Graph.Applications[ExtensionsAppClientId.ToString()].ExtensionProperties.Request().GetAsync(); - return extensionProperties.AsEnumerable().ToArray(); - } + public ILogger Logger => logger; +private readonly IConfiguration _configuration = configuration; +private MicrosoftB2CGraphOptions GraphOptions => _configuration.GetSection(Constants.AzureAdB2C).Get(); +private MicrosoftIdentityOptions IdentityOptions => _configuration.GetSection(Constants.AzureAdB2C).Get(); +protected virtual GraphServiceClient Graph => graph; +public guid ExtensionsAppClientId => GraphOptions.AzureAdB2CExtensionsApplicationId; + +/// Retrieves the client ID from "AzureAdB2C:ClientIf" +public string ClientId => + IdentityOptions?.ClientId ?? + throw new InvalidOperationException("ClientId is required"); + +public async Task GetApplication() + => await Graph.Applications[ClientId].Request().GetAsync(); + +public async Task GetExtensionsApplication() + => await Graph.Applications[GraphOptions.AzureAdB2CExtensionsApplicationId.ToString()].Request().GetAsync(); + +public async Task GetExtensionPropertiesAsync(CancellationToken cancellationToken = default) +{ + + var extensionProperties = await Graph.Applications[ExtensionsAppClientId.ToString()].ExtensionProperties.Request().GetAsync(); + return extensionProperties.AsEnumerable().ToArray(); +} } diff --git a/src/MicrosoftGraph/PassphraseGenerator.cs b/src/MicrosoftGraph/PassphraseGenerator.cs index 3447157a..25c5c3c5 100644 --- a/src/MicrosoftGraph/PassphraseGenerator.cs +++ b/src/MicrosoftGraph/PassphraseGenerator.cs @@ -39,76 +39,76 @@ public class PassphraseGeneratorOptions public class PassphraseGenerator(IOptions options) : IPassphraseGenerator { - private static readonly RandomNumberGenerator Random = RandomNumberGenerator.Create(); - private readonly PassphraseGeneratorOptions _options = - options?.Value ?? throw new ArgumentNullException(nameof(options)); - private string[] WordList => _options.WordList; - private char[] SpecialCharacters => _options.SpecialCharacters; - private int WordCount => _options.WordCount; - private int EmojiCount => _options.EmojiCount; - private int SpecialCharacterCount => _options.SpecialCharacterCount; - private int LowercaseCharacterCount => _options.LowercaseCharacterCount; - private int UppercaseCharacterCount => _options.UppercaseCharacterCount; - private int CharacterCount => _options.CharacterCount; - private char[] Emoji => _options.Emoji; - - public string Generate() - { - var wordsToGo = WordCount; - var emojiToGo = EmojiCount; - var specialCharactersToGo = SpecialCharacterCount; - var lowercaseCharactersToGo = LowercaseCharacterCount; - var uppercaseCharactersToGo = UppercaseCharacterCount; - var charactersToGo = CharacterCount; - - var passphrase = new StringBuilder(); - - while ( - wordsToGo > 0 - || emojiToGo > 0 - || specialCharactersToGo > 0 - || lowercaseCharactersToGo > 0 - || uppercaseCharactersToGo > 0 - || charactersToGo > 0 - ) - { - var word = GetRandomWord(); - passphrase.Append(word); - wordsToGo--; - charactersToGo -= word.Length; - lowercaseCharactersToGo -= word.Count(char.IsLower); - uppercaseCharactersToGo -= word.Count(char.IsUpper); - - if (emojiToGo > 0) - { - var emoji = PickRandomElement(Emoji); - passphrase.Append(emoji); - emojiToGo--; - charactersToGo--; - } - - if (lowercaseCharactersToGo > 0) - { - var emoji = PickRandomElement(Emoji); - passphrase.Append(emoji); - emojiToGo--; - charactersToGo--; - } - - if (specialCharactersToGo > 0) - { - var specialCharacter = PickRandomElement(SpecialCharacters); - passphrase.Append(specialCharacter); - specialCharactersToGo--; - charactersToGo--; - } - } - - return passphrase.ToString(); - } - - private string GetRandomWord() => PickRandomElement(WordList); - - private static T PickRandomElement(T[] elements) => - elements.Skip(Random.NextInt32(elements.Length - 1)).First(); + private static readonly RandomNumberGenerator Random = RandomNumberGenerator.Create(); +private readonly PassphraseGeneratorOptions _options = + options?.Value ?? throw new ArgumentNullException(nameof(options)); +private string[] WordList => _options.WordList; +private char[] SpecialCharacters => _options.SpecialCharacters; +private int WordCount => _options.WordCount; +private int EmojiCount => _options.EmojiCount; +private int SpecialCharacterCount => _options.SpecialCharacterCount; +private int LowercaseCharacterCount => _options.LowercaseCharacterCount; +private int UppercaseCharacterCount => _options.UppercaseCharacterCount; +private int CharacterCount => _options.CharacterCount; +private char[] Emoji => _options.Emoji; + +public string Generate() +{ + var wordsToGo = WordCount; + var emojiToGo = EmojiCount; + var specialCharactersToGo = SpecialCharacterCount; + var lowercaseCharactersToGo = LowercaseCharacterCount; + var uppercaseCharactersToGo = UppercaseCharacterCount; + var charactersToGo = CharacterCount; + + var passphrase = new StringBuilder(); + + while ( + wordsToGo > 0 + || emojiToGo > 0 + || specialCharactersToGo > 0 + || lowercaseCharactersToGo > 0 + || uppercaseCharactersToGo > 0 + || charactersToGo > 0 + ) + { + var word = GetRandomWord(); + passphrase.Append(word); + wordsToGo--; + charactersToGo -= word.Length; + lowercaseCharactersToGo -= word.Count(char.IsLower); + uppercaseCharactersToGo -= word.Count(char.IsUpper); + + if (emojiToGo > 0) + { + var emoji = PickRandomElement(Emoji); + passphrase.Append(emoji); + emojiToGo--; + charactersToGo--; + } + + if (lowercaseCharactersToGo > 0) + { + var emoji = PickRandomElement(Emoji); + passphrase.Append(emoji); + emojiToGo--; + charactersToGo--; + } + + if (specialCharactersToGo > 0) + { + var specialCharacter = PickRandomElement(SpecialCharacters); + passphrase.Append(specialCharacter); + specialCharactersToGo--; + charactersToGo--; + } + } + + return passphrase.ToString(); +} + +private string GetRandomWord() => PickRandomElement(WordList); + +private static T PickRandomElement(T[] elements) => + elements.Skip(Random.NextInt32(elements.Length - 1)).First(); } diff --git a/src/Mvc/IHostApplicationBuilderMvcExtensions.cs b/src/Mvc/IHostApplicationBuilderMvcExtensions.cs index f39baaaf..226d9777 100644 --- a/src/Mvc/IHostApplicationBuilderMvcExtensions.cs +++ b/src/Mvc/IHostApplicationBuilderMvcExtensions.cs @@ -21,7 +21,7 @@ public static IHostApplicationBuilder AddMvc(this IHostApplicationBuilder builde builder.Services.Configure(mvcOptionsSection); var mvcOptions = mvcOptionsSection.Get(); - if(mvcOptions is not null) + if (mvcOptions is not null) { #if NET5_0_OR_GREATER if(mvcOptions.EnableEndpointRouting) @@ -44,22 +44,22 @@ public static IHostApplicationBuilder AddMvc(this IHostApplicationBuilder builde } #endif - if(mvcOptions.AddControllersAsServices) + if (mvcOptions.AddControllersAsServices) { mvcBuilder.AddControllersAsServices(); } - if(mvcOptions.AddXmlSerializerFormatters) + if (mvcOptions.AddXmlSerializerFormatters) { mvcBuilder.AddXmlSerializerFormatters(); } - if(mvcOptions.AddXmlDataContractSerializerFormatters) + if (mvcOptions.AddXmlDataContractSerializerFormatters) { mvcBuilder.AddXmlDataContractSerializerFormatters(); } - if(mvcOptions.AddMvcConventions) + if (mvcOptions.AddMvcConventions) { // mvcBuilder.AddMvcOptions(options => builder.Configuration.Bind(configurationSectionKey, options)); } diff --git a/src/Mvc/OKAttributes.cs b/src/Mvc/OKAttributes.cs index 80487ae5..f962357e 100644 --- a/src/Mvc/OKAttributes.cs +++ b/src/Mvc/OKAttributes.cs @@ -34,7 +34,8 @@ public class ProducesOKResponseAttribute( Application.MessagePack.DisplayName, Application.Bson.DisplayName, Text.Plain.DisplayName - ) { } + ) +{ } /// Notes that the method can produce a 200 OK response /// The type of the model to be returned. @@ -55,7 +56,8 @@ public sealed class ProducesNoContentResponseAttribute( Application.MessagePack.DisplayName, Application.Bson.DisplayName, TextMediaTypeNames.Plain - ) { } + ) +{ } public class ProducesCreatedResponseAttribute( type modelType, @@ -70,7 +72,8 @@ public class ProducesCreatedResponseAttribute( Application.MessagePack.DisplayName, Application.Bson.DisplayName, Text.Plain.DisplayName - ) { } + ) +{ } public class ProducesCreatedResponseAttribute( string description = "The shit you were try'n'a create was created successfully." @@ -89,7 +92,8 @@ public class ProducesPartialContentResponseAttribute( Application.MessagePack.DisplayName, Application.Bson.DisplayName, TextMediaTypeNames.Plain - ) { } + ) +{ } public sealed class ProducesPartialContentResponseAttribute( string description = "Here's some of the shit you requested." @@ -110,9 +114,9 @@ public sealed class CreateOperationAttribute( public sealed class UpdateOperationAttribute( string? operationId, - string? summary = "Update an existing resource from a complete model object", - string? description = "Update an existing resource from a complete model object", - string[]? tags = null + string ? summary = "Update an existing resource from a complete model object", + string ? description = "Update an existing resource from a complete model object", + string[] ? tags = null ) : DgmjrOperationAttribute( operationId, @@ -123,9 +127,9 @@ public sealed class UpdateOperationAttribute( public sealed class DeleteOperationAttribute( string? operationId, - string? summary = "Delete an existing resource", - string? description = "Delete an existing resource", - string[]? tags = null + string ? summary = "Delete an existing resource", + string ? description = "Delete an existing resource", + string[] ? tags = null ) : DgmjrOperationAttribute( operationId, @@ -136,9 +140,9 @@ public sealed class DeleteOperationAttribute( public sealed class PatchOperationAttribute( string? operationId, - string? summary = "Update an existing resource from a partial model object", - string? description = "Update an existing resource from a partial model object", - string[]? tags = null + string ? summary = "Update an existing resource from a partial model object", + string ? description = "Update an existing resource from a partial model object", + string[] ? tags = null ) : DgmjrOperationAttribute( operationId, diff --git a/src/Mvc/ProducesErrorAttributes/Produces400ErrorAttribute.cs b/src/Mvc/ProducesErrorAttributes/Produces400ErrorAttribute.cs index 33427666..74d88ce7 100644 --- a/src/Mvc/ProducesErrorAttributes/Produces400ErrorAttribute.cs +++ b/src/Mvc/ProducesErrorAttributes/Produces400ErrorAttribute.cs @@ -25,5 +25,6 @@ public Produces400ErrorAttribute() "You done fucked up!", typeof(BadRequestProblemDetails), ApplicationMediaTypeNames.ProblemJson - ) { } + ) + { } } diff --git a/src/Mvc/ProducesErrorAttributes/Produces401ErrorAttribute.cs b/src/Mvc/ProducesErrorAttributes/Produces401ErrorAttribute.cs index e66a09a9..b19d3a00 100644 --- a/src/Mvc/ProducesErrorAttributes/Produces401ErrorAttribute.cs +++ b/src/Mvc/ProducesErrorAttributes/Produces401ErrorAttribute.cs @@ -25,5 +25,6 @@ public Produces401ErrorAttribute() "You're not allowed to fucking do that!", typeof(UnauthorizedProblemDetails), ApplicationMediaTypeNames.ProblemJson - ) { } + ) + { } } diff --git a/src/Mvc/ProducesErrorAttributes/Produces403ErrorAttribute.cs b/src/Mvc/ProducesErrorAttributes/Produces403ErrorAttribute.cs index 568b0a0a..2f970984 100644 --- a/src/Mvc/ProducesErrorAttributes/Produces403ErrorAttribute.cs +++ b/src/Mvc/ProducesErrorAttributes/Produces403ErrorAttribute.cs @@ -25,5 +25,6 @@ public Produces403ErrorAttribute() "You're not allowed to fucking do that!", typeof(ForbiddenProblemDetails), ApplicationMediaTypeNames.ProblemJson - ) { } + ) + { } } diff --git a/src/Mvc/ProducesErrorAttributes/Produces404ErrorAttribute.cs b/src/Mvc/ProducesErrorAttributes/Produces404ErrorAttribute.cs index ecfb62f0..d36c24b3 100644 --- a/src/Mvc/ProducesErrorAttributes/Produces404ErrorAttribute.cs +++ b/src/Mvc/ProducesErrorAttributes/Produces404ErrorAttribute.cs @@ -25,5 +25,6 @@ public Produces404ErrorAttribute() "The shit you're looking for doesn't fucking exist!", typeof(NotFoundProblemDetails), ApplicationMediaTypeNames.ProblemJson - ) { } + ) + { } } diff --git a/src/Mvc/ProducesErrorAttributes/Produces418ErrorAttribute.cs b/src/Mvc/ProducesErrorAttributes/Produces418ErrorAttribute.cs index 0fdf6b67..e9580db1 100644 --- a/src/Mvc/ProducesErrorAttributes/Produces418ErrorAttribute.cs +++ b/src/Mvc/ProducesErrorAttributes/Produces418ErrorAttribute.cs @@ -25,5 +25,6 @@ public Produces418ErrorAttribute() "I'm a fucking teapot, short and stout. Here's my handle; here's my spout. If you've reached this error code, you must shout, \"I'm a fuckin' idiot so kick me out!\"", typeof(ImATeapotProblemDetailsExample), ApplicationMediaTypeNames.ProblemJson - ) { } + ) + { } } diff --git a/src/Mvc/ProducesErrorAttributes/Produces500ErrorAttribute.cs b/src/Mvc/ProducesErrorAttributes/Produces500ErrorAttribute.cs index a91cc24a..65e8a73d 100644 --- a/src/Mvc/ProducesErrorAttributes/Produces500ErrorAttribute.cs +++ b/src/Mvc/ProducesErrorAttributes/Produces500ErrorAttribute.cs @@ -25,5 +25,6 @@ public Produces500ErrorAttribute() "Shit hit the fucking fan!", typeof(InternalServerErrorProblemDetails), ApplicationMediaTypeNames.ProblemJson - ) { } + ) + { } } diff --git a/src/Swagger/SwaggerExtensions/AddSwaggerGenExtension.ThisAssemblyProject.cs b/src/Swagger/SwaggerExtensions/AddSwaggerGenExtension.ThisAssemblyProject.cs index 78344712..22967125 100644 --- a/src/Swagger/SwaggerExtensions/AddSwaggerGenExtension.ThisAssemblyProject.cs +++ b/src/Swagger/SwaggerExtensions/AddSwaggerGenExtension.ThisAssemblyProject.cs @@ -18,96 +18,96 @@ namespace Microsoft.Extensions.DependencyInjection; internal record struct TThisAssemblyStaticProxy(type ThisAssemblyStaticProxy) { - public const string ThisAssembly = nameof(ThisAssembly); - - public static TThisAssemblyStaticProxy From(Assembly asm) => - new TThisAssemblyStaticProxy(Find(asm.GetTypes(), t => t.Name is nameof(ThisAssembly))); - - public type? Project => - Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Project)); - public type? Info => - Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Info)); - public type? Git => Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Git)); - public type? Metadata => - Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Metadata)); - public type? Strings => - Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Strings)); - public Assembly Assembly => ThisAssemblyStaticProxy.Assembly; - - public string? AssemblyVersion => - Project?.GetRuntimeField(nameof(AssemblyVersion))?.GetValue(null) as string - ?? Info?.GetRuntimeField(nameof(AssemblyVersion))?.GetValue(null) as string - ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Version; - public string? Authors => Project?.GetRuntimeField(nameof(Authors))?.GetValue(null) as string; - public string? Company => - Project?.GetRuntimeField(nameof(Company))?.GetValue(null) as string - ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Company; - public string? ContactEmail => - Project?.GetRuntimeField(nameof(ContactEmail))?.GetValue(null) as string; - public string? Copyright => - Project?.GetRuntimeField(nameof(Copyright))?.GetValue(null) as string - ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Copyright; - public string? Description => - Assembly.GetCustomAttributes()?.FirstOrDefault()?.Description - ?? this.ThisAssemblyStaticProxy - ?.GetRuntimeField(nameof(Description)) - ?.GetValue(null) - ?.ToString() - ?? Project?.GetRuntimeField(nameof(Description))?.GetValue(null) as string; - public string? FileVersion => - Project?.GetRuntimeField(nameof(FileVersion))?.GetValue(null) as string - ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Version; - public string? InformationalVersion => - Project?.GetRuntimeField(nameof(InformationalVersion))?.GetValue(null) as string; - public string? LicenseExpression => - PackageLicenseExpression - ?? Project?.GetRuntimeField(nameof(LicenseExpression))?.GetValue(null)?.ToString() - ?? Project?.GetRuntimeField(nameof(LicenseExpression))?.GetValue(null)?.ToString() - ?? "None"; - public string? Owners => Project?.GetRuntimeField(nameof(Owners))?.GetValue(null) as string; - public string? PackageLicenseExpression => - Project?.GetRuntimeField(nameof(PackageLicenseExpression))?.GetValue(null) as string; - public string? PackageTags => - Project?.GetRuntimeField(nameof(PackageTags))?.GetValue(null) as string; - public string? PackageVersion => - Project?.GetRuntimeField(nameof(PackageVersion))?.GetValue(null) as string; - public string? Product => Project?.GetRuntimeField(nameof(Product))?.GetValue(null) as string; - public string? SwaggerTheme => - Project?.GetRuntimeField(nameof(SwaggerTheme))?.GetValue(null) as string; - public string? Title => - Project?.GetRuntimeField(nameof(Title))?.GetValue(null) as string - ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Title; - public string? Version => Project?.GetRuntimeField(nameof(Version))?.GetValue(null) as string; - public uri? LicenseUrl => $"https://opensource.org/licenses/{LicenseExpression}"; - public uri? PackageProjectUrl => - IsNullOrWhiteSpace(PackageProjectUrlString) - ? "https://example.com/contact" - : PackageProjectUrlString; - - public uri? RepositoryUrl => - IsNullOrWhiteSpace(RepositoryUrlString) ? "about:blank" : RepositoryUrlString; - public uri? TermsOfServiceUrl => - IsNullOrWhiteSpace(TermsOfServiceUrlString) - ? "https://example.com/terms" - : TermsOfServiceUrlString; - - public string? RepositoryUrlString => - Project?.GetRuntimeField(nameof(RepositoryUrl))?.GetValue(null) as string; - public string? PackageProjectUrlString => - Project?.GetRuntimeField(nameof(PackageProjectUrl))?.GetValue(null) as string; - public string? TermsOfServiceUrlString => - Project?.GetRuntimeField(nameof(TermsOfServiceUrl))?.GetValue(null) as string; - public string? ApiVersion => - "v" - + ( - IsNullOrEmpty(PackageVersion) - ? IsNullOrEmpty(FileVersion) - ? IsNullOrEmpty(Version) - ? IsNullOrEmpty(AssemblyVersion) - ? "0.0.1-Preview" - : AssemblyVersion - : Version - : FileVersion - : PackageVersion - ); + public const string ThisAssembly = nameof(ThisAssembly); + +public static TThisAssemblyStaticProxy From(Assembly asm) => + new TThisAssemblyStaticProxy(Find(asm.GetTypes(), t => t.Name is nameof(ThisAssembly))); + +public type? Project => + Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Project)); +public type? Info => + Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Info)); +public type? Git => Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Git)); +public type? Metadata => + Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Metadata)); +public type? Strings => + Find(ThisAssemblyStaticProxy.GetNestedTypes(), t => t.Name == nameof(Strings)); +public Assembly Assembly => ThisAssemblyStaticProxy.Assembly; + +public string? AssemblyVersion => + Project?.GetRuntimeField(nameof(AssemblyVersion))?.GetValue(null) as string + ?? Info?.GetRuntimeField(nameof(AssemblyVersion))?.GetValue(null) as string + ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Version; +public string? Authors => Project?.GetRuntimeField(nameof(Authors))?.GetValue(null) as string; +public string? Company => + Project?.GetRuntimeField(nameof(Company))?.GetValue(null) as string + ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Company; +public string? ContactEmail => + Project?.GetRuntimeField(nameof(ContactEmail))?.GetValue(null) as string; +public string? Copyright => + Project?.GetRuntimeField(nameof(Copyright))?.GetValue(null) as string + ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Copyright; +public string? Description => + Assembly.GetCustomAttributes()?.FirstOrDefault()?.Description + ?? this.ThisAssemblyStaticProxy + ?.GetRuntimeField(nameof(Description)) + ?.GetValue(null) + ?.ToString() + ?? Project?.GetRuntimeField(nameof(Description))?.GetValue(null) as string; +public string? FileVersion => + Project?.GetRuntimeField(nameof(FileVersion))?.GetValue(null) as string + ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Version; +public string? InformationalVersion => + Project?.GetRuntimeField(nameof(InformationalVersion))?.GetValue(null) as string; +public string? LicenseExpression => + PackageLicenseExpression + ?? Project?.GetRuntimeField(nameof(LicenseExpression))?.GetValue(null)?.ToString() + ?? Project?.GetRuntimeField(nameof(LicenseExpression))?.GetValue(null)?.ToString() + ?? "None"; +public string? Owners => Project?.GetRuntimeField(nameof(Owners))?.GetValue(null) as string; +public string? PackageLicenseExpression => + Project?.GetRuntimeField(nameof(PackageLicenseExpression))?.GetValue(null) as string; +public string? PackageTags => + Project?.GetRuntimeField(nameof(PackageTags))?.GetValue(null) as string; +public string? PackageVersion => + Project?.GetRuntimeField(nameof(PackageVersion))?.GetValue(null) as string; +public string? Product => Project?.GetRuntimeField(nameof(Product))?.GetValue(null) as string; +public string? SwaggerTheme => + Project?.GetRuntimeField(nameof(SwaggerTheme))?.GetValue(null) as string; +public string? Title => + Project?.GetRuntimeField(nameof(Title))?.GetValue(null) as string + ?? Assembly.GetCustomAttributes()?.FirstOrDefault()?.Title; +public string? Version => Project?.GetRuntimeField(nameof(Version))?.GetValue(null) as string; +public uri? LicenseUrl => $"https://opensource.org/licenses/{LicenseExpression}"; +public uri? PackageProjectUrl => + IsNullOrWhiteSpace(PackageProjectUrlString) + ? "https://example.com/contact" + : PackageProjectUrlString; + +public uri? RepositoryUrl => + IsNullOrWhiteSpace(RepositoryUrlString) ? "about:blank" : RepositoryUrlString; +public uri? TermsOfServiceUrl => + IsNullOrWhiteSpace(TermsOfServiceUrlString) + ? "https://example.com/terms" + : TermsOfServiceUrlString; + +public string? RepositoryUrlString => + Project?.GetRuntimeField(nameof(RepositoryUrl))?.GetValue(null) as string; +public string? PackageProjectUrlString => + Project?.GetRuntimeField(nameof(PackageProjectUrl))?.GetValue(null) as string; +public string? TermsOfServiceUrlString => + Project?.GetRuntimeField(nameof(TermsOfServiceUrl))?.GetValue(null) as string; +public string? ApiVersion => + "v" + + ( + IsNullOrEmpty(PackageVersion) + ? IsNullOrEmpty(FileVersion) + ? IsNullOrEmpty(Version) + ? IsNullOrEmpty(AssemblyVersion) + ? "0.0.1-Preview" + : AssemblyVersion + : Version + : FileVersion + : PackageVersion + ); } diff --git a/src/Swagger/swaggerui/Controllers/SwaggerUIController.cs b/src/Swagger/swaggerui/Controllers/SwaggerUIController.cs index 98c2cf1b..cf5d9128 100644 --- a/src/Swagger/swaggerui/Controllers/SwaggerUIController.cs +++ b/src/Swagger/swaggerui/Controllers/SwaggerUIController.cs @@ -15,162 +15,162 @@ namespace Dgmjr.AspNetCore.Swagger.UI; [Route("/swagger-ui/{documentName}")] public partial class SwaggerUIController(ILogger logger, HttpClient httpClient, IDistributedCache cache, IOptionsMonitor options, IOptionsMonitor swaggerOptions, IOptionsMonitor swaggerGenOptions) : ControllerBase, ILog { - private const string Swagger_UI = "Swagger UI"; - private string SwaggerUIIndex_Html => $"swaggerui.{Options.SwaggerUI}.index.html"; - private string SwaggerUIInit_js => $"swaggerui.{Options.SwaggerUI}.swagger-ui-init.js"; - private string SwaggerUI => $"swaggerui.{Options.SwaggerUI}"; - private string BaseUrl => Options.ReverseProxyEndpoint; - public ILogger Logger => logger; - private SwaggerUIOptions Options => options.CurrentValue; - private SwaggerOptions SwaggerOptions => swaggerOptions.CurrentValue; - private SwaggerGenOptions SwaggerGenOptions => swaggerGenOptions.CurrentValue; - - private ConfigObject ConfigObject => Options.ConfigObject; - private OAuthConfigObject OAuthConfigObject => Options.OAuthConfigObject; - private InterceptorFunctions Interceptors => Options.Interceptors; - private string ConfigObjectJson => Serialize(ConfigObject); - private string OAuthConfigObjectJson => Serialize(OAuthConfigObject); - private string InterceptorsJson => Serialize(Interceptors); - - private readonly IDistributedCache _cache = cache; - private readonly HttpClient _httpClient = httpClient; - - [HttpGet("{**swaggerUiFileName}")] - [SwaggerOperation(Summary = "Swagger UI Documents", Description = "Retrieves Swagger UI Documents", Tags = [ Swagger_UI ], OperationId = "SwaggerUIDocuments")] - [Produces(Text.Html.DisplayName, Application.Json.DisplayName, Application.JavaScript.DisplayName, Application.Xml.DisplayName, Application.Zip.DisplayName, Application.Pdf.DisplayName, Application.Rtf.DisplayName)] - public async Task GetSwaggerUIFileAsync(string swaggerUiFileName) - { - if(Options.UseReverseProxy) - { - var cacheKey = $"{SwaggerUI}-{swaggerUiFileName}"; - var document = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; - var extension = Path.GetExtension(swaggerUiFileName); - if (document is not null) - { - Logger.LogCacheHit(cacheKey); - return File(document, MimeTypes.GetMimeType(extension)); - } - Logger.LogCacheMiss(cacheKey); - Logger.LogTrace($"Swagger UI file request URI: {BaseUrl}{swaggerUiFileName}"); - var content = await _httpClient.GetByteArrayAsync($"{BaseUrl}{swaggerUiFileName}"); - await _cache.SetAsync(cacheKey, content); - return File(content, MimeTypes.GetMimeType(extension)); - } - else - { - var document = await GetType().Assembly.GetManifestResourceStream(SwaggerUIIndex_Html).ReadAllBytesAsync(); - var extension = Path.GetExtension(swaggerUiFileName); - return File(document, MimeTypes.GetMimeType(extension), fileDownloadName: swaggerUiFileName); - } - } - - [HttpGet("index.html")] - [SwaggerOperation(Summary = "Swagger UI index.html", Description = "Retrieves Swagger UI index.html", Tags = [ Swagger_UI ], OperationId = "SwaggerUIIndexHtml")] - [Produces(Text.Html.DisplayName)] - public async Task GetSwaggerUIIndexAsync() - { - if(Options.UseReverseProxy && Options.SwaggerUI is not UI.SwaggerUI.Bootstrap) - { - return await GetSwaggerUIFileAsync("index.html"); - } - - var cacheKey = SwaggerUIIndex_Html; - var document = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; - if (document is not null) - { - Logger.LogCacheHit(cacheKey); - return File(document, Text.Html.DisplayName); - } - Logger.LogCacheMiss(cacheKey); - var content = await GetType().Assembly.GetManifestResourceStream(SwaggerUIIndex_Html).ReadAllBytesAsync(); - await _cache.SetAsync(cacheKey, content); - return File(content, Text.Html.DisplayName); - } - - [HttpGet("assets/swagger-ui.js")] - [SwaggerOperation(Summary = "Swagger UI swagger-ui.js", Description = "Retrieves Swagger UI swagger-ui.js", Tags = [ Swagger_UI ], OperationId = "SwaggerUISwaggerUIJs")] - [Produces(Application.JavaScript.DisplayName)] - public async Task GetSwaggerUIJsAsync() - { - if(Options.UseReverseProxy && Options.SwaggerUI is not UI.SwaggerUI.Bootstrap) - { - return await GetSwaggerUIFileAsync("swagger-ui.js"); - } - - var cacheKey = $"{SwaggerUI}-swagger-ui.js"; - var contentBytes = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; - if (contentBytes is not null) - { - Logger.LogCacheHit(cacheKey); - } - else - { - Logger.LogCacheMiss(cacheKey); - } - var stringContent = contentBytes.ToUTF8String(); - - stringContent = stringContent.Replace("definitions", "schemas"); - contentBytes = stringContent.ToUTF8Bytes(); - - await _cache.SetAsync(cacheKey, contentBytes); - return File(contentBytes, Text.Html.DisplayName); - } - - [HttpGet("swagger-ui-init.js")] - [SwaggerOperation(Summary = "Swagger UI Init", Description = "Swagger UI Init", Tags = [ Swagger_UI ], OperationId = "SwaggerUIInit")] - [Produces(Application.JavaScript.DisplayName)] - public async Task GetSwaggerUIIInitJsAsync() - { - var cacheKey = $"{SwaggerUI}-swagger-ui-init.js"; - var document = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; - if (document is not null) - { - Logger.LogCacheHit(cacheKey); - return File(document, Text.Html.DisplayName); - } - Logger.LogCacheMiss(cacheKey); - var content = await GetType().Assembly.ReadAssemblyResourceAllTextAsync(SwaggerUIInit_js); - content = content.Replace("${ConfigObject}", ConfigObjectJson); - content = content.Replace("${OAuthConfigObject}", OAuthConfigObjectJson); - content = content.Replace("${Interceptors}", InterceptorsJson); - var contentBytes = content.ToUTF8Bytes(); - await _cache.SetAsync(cacheKey, contentBytes); - return File(contentBytes, Text.Html.DisplayName); - } - - [HttpGet("swagger.json")] - public async Task GetSwaggerJsonAsync([FromRoute] string documentName) - { - var cacheKey = $"{SwaggerUI}-{documentName}"; - var documentBytes = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; - if (documentBytes is not null) - { - Logger.LogCacheHit(cacheKey); - } - else - { - Logger.LogCacheMiss(cacheKey); - var baseServerUri = GetBaseServerUri(); - var requestUri = $"{baseServerUri}/{SwaggerOptions.RouteTemplate.Replace("{documentName}", documentName)}"; - Logger.LogTrace($"Swagger document request URI: {requestUri}"); - documentBytes = await _httpClient.GetByteArrayAsync(requestUri); - await _cache.SetAsync(cacheKey, documentBytes); - } - return File(documentBytes, ApplicationMediaTypeNames.OpenApiJson); - } - - private string GetBaseServerUri() - { - var request = HttpContext.Request; - var scheme = request.Scheme; - var host = request.Host; - // var pathBase = request.PathBase; - var port = request.Host.Port; - var baseUri = $"{scheme}://{host}"; - Logger.LogTrace($"scheme: {scheme}"); - Logger.LogTrace($"host: {host}"); - Logger.LogTrace($"port: {port}"); - Logger.LogTrace($"baseUri: {baseUri}"); - return baseUri; - } + private const string Swagger_UI = "Swagger UI"; +private string SwaggerUIIndex_Html => $"swaggerui.{Options.SwaggerUI}.index.html"; +private string SwaggerUIInit_js => $"swaggerui.{Options.SwaggerUI}.swagger-ui-init.js"; +private string SwaggerUI => $"swaggerui.{Options.SwaggerUI}"; +private string BaseUrl => Options.ReverseProxyEndpoint; +public ILogger Logger => logger; +private SwaggerUIOptions Options => options.CurrentValue; +private SwaggerOptions SwaggerOptions => swaggerOptions.CurrentValue; +private SwaggerGenOptions SwaggerGenOptions => swaggerGenOptions.CurrentValue; + +private ConfigObject ConfigObject => Options.ConfigObject; +private OAuthConfigObject OAuthConfigObject => Options.OAuthConfigObject; +private InterceptorFunctions Interceptors => Options.Interceptors; +private string ConfigObjectJson => Serialize(ConfigObject); +private string OAuthConfigObjectJson => Serialize(OAuthConfigObject); +private string InterceptorsJson => Serialize(Interceptors); + +private readonly IDistributedCache _cache = cache; +private readonly HttpClient _httpClient = httpClient; + +[HttpGet("{**swaggerUiFileName}")] +[SwaggerOperation(Summary = "Swagger UI Documents", Description = "Retrieves Swagger UI Documents", Tags = [Swagger_UI], OperationId = "SwaggerUIDocuments")] +[Produces(Text.Html.DisplayName, Application.Json.DisplayName, Application.JavaScript.DisplayName, Application.Xml.DisplayName, Application.Zip.DisplayName, Application.Pdf.DisplayName, Application.Rtf.DisplayName)] +public async Task GetSwaggerUIFileAsync(string swaggerUiFileName) +{ + if (Options.UseReverseProxy) + { + var cacheKey = $"{SwaggerUI}-{swaggerUiFileName}"; + var document = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; + var extension = Path.GetExtension(swaggerUiFileName); + if (document is not null) + { + Logger.LogCacheHit(cacheKey); + return File(document, MimeTypes.GetMimeType(extension)); + } + Logger.LogCacheMiss(cacheKey); + Logger.LogTrace($"Swagger UI file request URI: {BaseUrl}{swaggerUiFileName}"); + var content = await _httpClient.GetByteArrayAsync($"{BaseUrl}{swaggerUiFileName}"); + await _cache.SetAsync(cacheKey, content); + return File(content, MimeTypes.GetMimeType(extension)); + } + else + { + var document = await GetType().Assembly.GetManifestResourceStream(SwaggerUIIndex_Html).ReadAllBytesAsync(); + var extension = Path.GetExtension(swaggerUiFileName); + return File(document, MimeTypes.GetMimeType(extension), fileDownloadName: swaggerUiFileName); + } +} + +[HttpGet("index.html")] +[SwaggerOperation(Summary = "Swagger UI index.html", Description = "Retrieves Swagger UI index.html", Tags = [Swagger_UI], OperationId = "SwaggerUIIndexHtml")] +[Produces(Text.Html.DisplayName)] +public async Task GetSwaggerUIIndexAsync() +{ + if (Options.UseReverseProxy && Options.SwaggerUI is not UI.SwaggerUI.Bootstrap) + { + return await GetSwaggerUIFileAsync("index.html"); + } + + var cacheKey = SwaggerUIIndex_Html; + var document = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; + if (document is not null) + { + Logger.LogCacheHit(cacheKey); + return File(document, Text.Html.DisplayName); + } + Logger.LogCacheMiss(cacheKey); + var content = await GetType().Assembly.GetManifestResourceStream(SwaggerUIIndex_Html).ReadAllBytesAsync(); + await _cache.SetAsync(cacheKey, content); + return File(content, Text.Html.DisplayName); +} + +[HttpGet("assets/swagger-ui.js")] +[SwaggerOperation(Summary = "Swagger UI swagger-ui.js", Description = "Retrieves Swagger UI swagger-ui.js", Tags = [Swagger_UI], OperationId = "SwaggerUISwaggerUIJs")] +[Produces(Application.JavaScript.DisplayName)] +public async Task GetSwaggerUIJsAsync() +{ + if (Options.UseReverseProxy && Options.SwaggerUI is not UI.SwaggerUI.Bootstrap) + { + return await GetSwaggerUIFileAsync("swagger-ui.js"); + } + + var cacheKey = $"{SwaggerUI}-swagger-ui.js"; + var contentBytes = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; + if (contentBytes is not null) + { + Logger.LogCacheHit(cacheKey); + } + else + { + Logger.LogCacheMiss(cacheKey); + } + var stringContent = contentBytes.ToUTF8String(); + + stringContent = stringContent.Replace("definitions", "schemas"); + contentBytes = stringContent.ToUTF8Bytes(); + + await _cache.SetAsync(cacheKey, contentBytes); + return File(contentBytes, Text.Html.DisplayName); +} + +[HttpGet("swagger-ui-init.js")] +[SwaggerOperation(Summary = "Swagger UI Init", Description = "Swagger UI Init", Tags = [Swagger_UI], OperationId = "SwaggerUIInit")] +[Produces(Application.JavaScript.DisplayName)] +public async Task GetSwaggerUIIInitJsAsync() +{ + var cacheKey = $"{SwaggerUI}-swagger-ui-init.js"; + var document = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; + if (document is not null) + { + Logger.LogCacheHit(cacheKey); + return File(document, Text.Html.DisplayName); + } + Logger.LogCacheMiss(cacheKey); + var content = await GetType().Assembly.ReadAssemblyResourceAllTextAsync(SwaggerUIInit_js); + content = content.Replace("${ConfigObject}", ConfigObjectJson); + content = content.Replace("${OAuthConfigObject}", OAuthConfigObjectJson); + content = content.Replace("${Interceptors}", InterceptorsJson); + var contentBytes = content.ToUTF8Bytes(); + await _cache.SetAsync(cacheKey, contentBytes); + return File(contentBytes, Text.Html.DisplayName); +} + +[HttpGet("swagger.json")] +public async Task GetSwaggerJsonAsync([FromRoute] string documentName) +{ + var cacheKey = $"{SwaggerUI}-{documentName}"; + var documentBytes = Options.UseCache ? await _cache.GetAsync(cacheKey) : null; + if (documentBytes is not null) + { + Logger.LogCacheHit(cacheKey); + } + else + { + Logger.LogCacheMiss(cacheKey); + var baseServerUri = GetBaseServerUri(); + var requestUri = $"{baseServerUri}/{SwaggerOptions.RouteTemplate.Replace("{documentName}", documentName)}"; + Logger.LogTrace($"Swagger document request URI: {requestUri}"); + documentBytes = await _httpClient.GetByteArrayAsync(requestUri); + await _cache.SetAsync(cacheKey, documentBytes); + } + return File(documentBytes, ApplicationMediaTypeNames.OpenApiJson); +} + +private string GetBaseServerUri() +{ + var request = HttpContext.Request; + var scheme = request.Scheme; + var host = request.Host; + // var pathBase = request.PathBase; + var port = request.Host.Port; + var baseUri = $"{scheme}://{host}"; + Logger.LogTrace($"scheme: {scheme}"); + Logger.LogTrace($"host: {host}"); + Logger.LogTrace($"port: {port}"); + Logger.LogTrace($"baseUri: {baseUri}"); + return baseUri; +} }