diff --git a/Extensions/DIExtensions.cs b/Extensions/DIExtensions.cs index b5c7530..528d105 100644 --- a/Extensions/DIExtensions.cs +++ b/Extensions/DIExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc; @@ -12,8 +13,10 @@ using xCommons.Configurations; using xCommons.Constants; using xCommons.Filters; -namespace xCommons.Extensions { - public static partial class DIExtensions { +namespace xCommons.Extensions +{ + public static partial class DIExtensions + { /// /// Inject Specific Registered Service from IServiceCollection @@ -21,10 +24,11 @@ namespace xCommons.Extensions { /// /// /// - public static T GetRegisteredService (this IServiceCollection source) { + public static T GetRegisteredService(this IServiceCollection source) + { // - var serviceProvider = source.BuildServiceProvider (); - return serviceProvider.GetService (); + var serviceProvider = source.BuildServiceProvider(); + return serviceProvider.GetService(); } /// @@ -32,10 +36,55 @@ namespace xCommons.Extensions { /// /// /// - public static void AddXAppConfiguration (this IServiceCollection services, IConfiguration configuration) { + public static void AddXAppConfiguration(this IServiceCollection services, IConfiguration configuration) + { // - var appConfiguration = configuration.GetXAppConfiguration (); - services.AddSingleton (appConfiguration); + var appConfiguration = configuration.GetXAppConfiguration(); + services.AddSingleton(appConfiguration); + } + + /// + /// Search Assemblies, Extract XML Comments and + /// Integrate them inside swagger gen documents ... + /// + /// + public static void IncludeAssembliesXMLComments(this SwaggerGenOptions source) + { + // + // Extract all Exists .xml files ... + var basePath = AppContext.BaseDirectory; + var xmlFiles = Directory.GetFiles(basePath, "*.xml", SearchOption.TopDirectoryOnly); + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + + // + // Loop through Detected XML Files ... + foreach (var xmlFile in xmlFiles) + { + // + try + { + // + // Retrieve file name for Assembly Checking ... + var assemblyName = Path.GetFileNameWithoutExtension(xmlFile); + + // + // Try to retrieve Assembly ... + var assembly = assemblies + .FirstOrDefault(a => a.GetName().Name == assemblyName); + if (!assembly.IsNullOrDefault() || + File.Exists(Path.Combine(basePath, $"{assemblyName}.dll")) + ) + { + // + // Includes Selected XML Comments ... + source.IncludeXmlComments(xmlFile); + } + } + catch (Exception ex) + { + Console.WriteLine($"Warning: Could not include XML comments from {xmlFile}. Error: {ex.Message}"); + } + } } /// @@ -46,51 +95,62 @@ namespace xCommons.Extensions { /// /// /// - public static void AddXSwaggerGenOptions ( + public static void AddXSwaggerGenOptions( this SwaggerGenOptions source, string xmlFilePath = null, bool addRequiredXPoweredFilter = true, bool addXTokenAuthorization = true, bool addDefaultValueFilter = true - ) { + ) + { // - if (source.IsNull ()) { - source = new SwaggerGenOptions (); + if (source.IsNull()) + { + source = new SwaggerGenOptions(); } // // Add Xml File Path ... - if (!xmlFilePath.IsNullOrEmpty ()) { - source.IncludeXmlComments (xmlFilePath); + if (!xmlFilePath.IsNullOrEmpty()) + { + source.IncludeXmlComments(xmlFilePath); } + // + // Include all XML Documents ... + source.IncludeAssembliesXMLComments(); + // // Handle RequireXPowered Filter ... - if (addRequiredXPoweredFilter) { - source.OperationFilter (); + if (addRequiredXPoweredFilter) + { + source.OperationFilter(); } // // Add Default Values Filter ... - if (addDefaultValueFilter) { - source.OperationFilter (); + if (addDefaultValueFilter) + { + source.OperationFilter(); } // // Handle XToken Authorizations ... - if (addXTokenAuthorization) { + if (addXTokenAuthorization) + { // #region Bearer AccessToken ... // - source.AddSecurityDefinition (nameof (XAuthorization.AccessToken), new OpenApiSecurityScheme { + source.AddSecurityDefinition(nameof(XAuthorization.AccessToken), new OpenApiSecurityScheme + { In = ParameterLocation.Header, - Description = "Bearer token", - Type = SecuritySchemeType.ApiKey, - Name = XAuthorization.Header + Description = "Bearer token", + Type = SecuritySchemeType.ApiKey, + Name = XAuthorization.Header }); // - source.AddSecurityRequirement (new OpenApiSecurityRequirement { + source.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { @@ -105,15 +165,16 @@ namespace xCommons.Extensions { // #region RefreshToken ... // - source.AddSecurityDefinition (nameof (XAuthorization.RefreshToken), new OpenApiSecurityScheme { + source.AddSecurityDefinition(nameof(XAuthorization.RefreshToken), new OpenApiSecurityScheme + { In = ParameterLocation.Header, - Description = "refresh token", - Type = SecuritySchemeType.ApiKey, - Name = nameof (XAuthorization.RefreshToken) + Description = "refresh token", + Type = SecuritySchemeType.ApiKey, + Name = nameof(XAuthorization.RefreshToken) }); // - source.AddSecurityRequirement (new OpenApiSecurityRequirement { + source.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { @@ -128,15 +189,16 @@ namespace xCommons.Extensions { // #region ExpiresAt ... // - source.AddSecurityDefinition (nameof (XAuthorization.ExpiresAt), new OpenApiSecurityScheme { + source.AddSecurityDefinition(nameof(XAuthorization.ExpiresAt), new OpenApiSecurityScheme + { In = ParameterLocation.Header, - Description = "expires at", - Type = SecuritySchemeType.ApiKey, - Name = nameof (XAuthorization.ExpiresAt) + Description = "expires at", + Type = SecuritySchemeType.ApiKey, + Name = nameof(XAuthorization.ExpiresAt) }); // - source.AddSecurityRequirement (new OpenApiSecurityRequirement { + source.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { @@ -160,7 +222,7 @@ namespace xCommons.Extensions { /// /// /// - public static void AddXSwagger ( + public static void AddXSwagger( this IServiceCollection source, IConfiguration configuration, SwaggerGenOptions settings = null, @@ -168,11 +230,13 @@ namespace xCommons.Extensions { bool addRequiredXPoweredFilter = true, bool addXTokenAuthorization = true, bool addDefaultValueFilter = true - ) { + ) + { // - var xSwaggerConfig = configuration.GetXSwaggerConfiguration (); - if (xSwaggerConfig.IsNull ()) { - xSwaggerConfig = new XSwaggerConfiguration (); + var xSwaggerConfig = configuration.GetXSwaggerConfiguration(); + if (xSwaggerConfig.IsNull()) + { + xSwaggerConfig = new XSwaggerConfiguration(); } // @@ -180,10 +244,11 @@ namespace xCommons.Extensions { // #region Prepare SwaggerGenOptions ... - if (settings.IsNull ()) { - settings = new SwaggerGenOptions (); + if (settings.IsNull()) + { + settings = new SwaggerGenOptions(); } - settings.AddXSwaggerGenOptions ( + settings.AddXSwaggerGenOptions( xmlFilePath: xmlFilePath, addDefaultValueFilter: addDefaultValueFilter, addXTokenAuthorization: addXTokenAuthorization, @@ -195,7 +260,8 @@ namespace xCommons.Extensions { #region Prepare Swagger Doc ... // // Api Document Section ... - var apiDoc = new OpenApiInfo { + var apiDoc = new OpenApiInfo + { Title = xSwaggerConfig.Title, Version = xSwaggerConfig.Version, Description = xSwaggerConfig.Description, @@ -203,23 +269,27 @@ namespace xCommons.Extensions { // // Api Document TermsOfUse URL ... - if (!xSwaggerConfig.TermsOfServiceUrl.IsNullOrEmpty ()) { - apiDoc.TermsOfService = new Uri (xSwaggerConfig.TermsOfServiceUrl); + if (!xSwaggerConfig.TermsOfServiceUrl.IsNullOrEmpty()) + { + apiDoc.TermsOfService = new Uri(xSwaggerConfig.TermsOfServiceUrl); } // // Contact Section ... - if (!xSwaggerConfig.Contact.IsNull ()) { + if (!xSwaggerConfig.Contact.IsNull()) + { // - var apiContact = new OpenApiContact { + var apiContact = new OpenApiContact + { Name = xSwaggerConfig.Contact.Name, Email = xSwaggerConfig.Contact.Email }; // // Contact URL ... - if (!xSwaggerConfig.Contact.Url.IsNullOrEmpty ()) { - apiContact.Url = new Uri (xSwaggerConfig.Contact.Url); + if (!xSwaggerConfig.Contact.Url.IsNullOrEmpty()) + { + apiContact.Url = new Uri(xSwaggerConfig.Contact.Url); } // @@ -228,16 +298,19 @@ namespace xCommons.Extensions { // // License Section ... - if (!xSwaggerConfig.License.IsNull ()) { + if (!xSwaggerConfig.License.IsNull()) + { // - var apiLicense = new OpenApiLicense { + var apiLicense = new OpenApiLicense + { Name = xSwaggerConfig.License.Name, }; // // License URL ... - if (!xSwaggerConfig.License.Url.IsNullOrEmpty ()) { - apiLicense.Url = new Uri (xSwaggerConfig.License.Url); + if (!xSwaggerConfig.License.Url.IsNullOrEmpty()) + { + apiLicense.Url = new Uri(xSwaggerConfig.License.Url); } // @@ -247,13 +320,14 @@ namespace xCommons.Extensions { // // Register Swagger ... - source.AddSwaggerGen ( - opt => { + source.AddSwaggerGen( + opt => + { // - opt.UpdateData (settings); + opt.UpdateData(settings); // - opt.SwaggerDoc ("v1", apiDoc); + opt.SwaggerDoc("v1", apiDoc); } ); @@ -266,18 +340,22 @@ namespace xCommons.Extensions { /// /// /// - public static void UseXSwagger ( + public static void UseXSwagger( this IApplicationBuilder source, SwaggerUIOptions options = null - ) { + ) + { // - source.UseSwagger (); + source.UseSwagger(); // - if (options.IsNull ()) { - source.UseSwaggerUI (); - } else { - source.UseSwaggerUI (options: options); + if (options.IsNull()) + { + source.UseSwaggerUI(); + } + else + { + source.UseSwaggerUI(options: options); } } @@ -286,24 +364,28 @@ namespace xCommons.Extensions { /// /// /// - public static void AddXCors ( + public static void AddXCors( this IServiceCollection source, IEnumerable allowedOrigins - ) { + ) + { // - if (!allowedOrigins.HasChild ()) { + if (!allowedOrigins.HasChild()) + { // - Console.WriteLine ($"XCommons: there is no provided allowedOrigins, start app without any specific cors, this may be unsecure ..."); + Console.WriteLine($"XCommons: there is no provided allowedOrigins, start app without any specific cors, this may be unsecure ..."); // - source.AddCors (options => { - options.AddPolicy (XPolicy.AllowedOrigins, - builder => { + source.AddCors(options => + { + options.AddPolicy(XPolicy.AllowedOrigins, + builder => + { builder - .AllowAnyOrigin () - .AllowAnyHeader () - .AllowAnyMethod () - .WithExposedHeaders ("*"); + .AllowAnyOrigin() + .AllowAnyHeader() + .AllowAnyMethod() + .WithExposedHeaders("*"); }); }); @@ -312,15 +394,17 @@ namespace xCommons.Extensions { } // - source.AddCors (options => { - options.AddPolicy (XPolicy.AllowedOrigins, - builder => { + source.AddCors(options => + { + options.AddPolicy(XPolicy.AllowedOrigins, + builder => + { builder - .WithOrigins (allowedOrigins.ToArray ()) - .AllowAnyHeader () - .AllowAnyMethod () - .AllowCredentials () - .WithExposedHeaders ("*"); + .WithOrigins(allowedOrigins.ToArray()) + .AllowAnyHeader() + .AllowAnyMethod() + .AllowCredentials() + .WithExposedHeaders("*"); }); }); } @@ -329,9 +413,10 @@ namespace xCommons.Extensions { /// Use X Registered Cross Origin Resource Sharings /// /// - public static void UseXCors (this IApplicationBuilder sources) { + public static void UseXCors(this IApplicationBuilder sources) + { // - sources.UseCors (XPolicy.AllowedOrigins); + sources.UseCors(XPolicy.AllowedOrigins); } /// @@ -355,7 +440,7 @@ namespace xCommons.Extensions { // // Report All Available Api Versions on Response ... opt.ReportApiVersions = true; - }); + }); } } } \ No newline at end of file diff --git a/xCommons.csproj b/xCommons.csproj index 084e58c..df16077 100644 --- a/xCommons.csproj +++ b/xCommons.csproj @@ -65,9 +65,9 @@ - true - true $(NoWarn);1591 + true + true \ No newline at end of file