446 lines
15 KiB
C#
446 lines
15 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using xCommons.Filters;
|
|
using xCommons.Constants;
|
|
using xCommons.Configurations;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.OpenApi.Models;
|
|
using System.Collections.Generic;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Swashbuckle.AspNetCore.SwaggerUI;
|
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace xCommons.Extensions
|
|
{
|
|
public static partial class DIExtensions
|
|
{
|
|
|
|
/// <summary>
|
|
/// Inject Specific Registered Service from IServiceCollection
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <returns></returns>
|
|
public static T GetRegisteredService<T>(this IServiceCollection source)
|
|
{
|
|
//
|
|
var serviceProvider = source.BuildServiceProvider();
|
|
return serviceProvider.GetService<T>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Register App Configuration as a Service
|
|
/// </summary>
|
|
/// <param name="services"></param>
|
|
/// <param name="configuration"></param>
|
|
public static void AddXAppConfiguration(this IServiceCollection services, IConfiguration configuration)
|
|
{
|
|
//
|
|
var appConfiguration = configuration.GetXAppConfiguration();
|
|
services.AddSingleton<XAppConfiguration>(appConfiguration);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Search Assemblies, Extract XML Comments and
|
|
/// Integrate them inside swagger gen documents ...
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
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}");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add Required OperationFilters and Authorization Fields to Swagger Options
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="xmlFilePath"></param>
|
|
/// <param name="addRequiredXPoweredFilter"></param>
|
|
/// <param name="addXTokenAuthorization"></param>
|
|
/// <param name="addDefaultValueFilter"></param>
|
|
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();
|
|
}
|
|
|
|
//
|
|
// Add Xml File Path ...
|
|
if (!xmlFilePath.IsNullOrEmpty())
|
|
{
|
|
source.IncludeXmlComments(xmlFilePath);
|
|
}
|
|
|
|
//
|
|
// Include all XML Documents ...
|
|
source.IncludeAssembliesXMLComments();
|
|
|
|
//
|
|
// Handle RequireXPowered Filter ...
|
|
if (addRequiredXPoweredFilter)
|
|
{
|
|
source.OperationFilter<RequireXPoweredOperationFilter>();
|
|
}
|
|
|
|
//
|
|
// Add Default Values Filter ...
|
|
if (addDefaultValueFilter)
|
|
{
|
|
source.OperationFilter<SwaggerDefaultValuesOperationFilter>();
|
|
}
|
|
|
|
//
|
|
// Handle XToken Authorizations ...
|
|
if (addXTokenAuthorization)
|
|
{
|
|
//
|
|
#region Bearer AccessToken ...
|
|
//
|
|
source.AddSecurityDefinition(nameof(XAuthorization.AccessToken), new OpenApiSecurityScheme
|
|
{
|
|
In = ParameterLocation.Header,
|
|
Description = "Bearer token",
|
|
Type = SecuritySchemeType.ApiKey,
|
|
Name = XAuthorization.Header
|
|
});
|
|
|
|
//
|
|
source.AddSecurityRequirement(new OpenApiSecurityRequirement {
|
|
{
|
|
new OpenApiSecurityScheme {
|
|
Reference = new OpenApiReference {
|
|
Id = nameof (XAuthorization.AccessToken),
|
|
Type = ReferenceType.SecurityScheme
|
|
}
|
|
}, Array.Empty<string> ()
|
|
}
|
|
});
|
|
#endregion
|
|
|
|
//
|
|
#region RefreshToken ...
|
|
//
|
|
source.AddSecurityDefinition(nameof(XAuthorization.RefreshToken), new OpenApiSecurityScheme
|
|
{
|
|
In = ParameterLocation.Header,
|
|
Description = "refresh token",
|
|
Type = SecuritySchemeType.ApiKey,
|
|
Name = nameof(XAuthorization.RefreshToken)
|
|
});
|
|
|
|
//
|
|
source.AddSecurityRequirement(new OpenApiSecurityRequirement {
|
|
{
|
|
new OpenApiSecurityScheme {
|
|
Reference = new OpenApiReference {
|
|
Id = nameof (XAuthorization.RefreshToken),
|
|
Type = ReferenceType.SecurityScheme
|
|
}
|
|
}, Array.Empty<string> ()
|
|
}
|
|
});
|
|
#endregion
|
|
|
|
//
|
|
#region ExpiresAt ...
|
|
//
|
|
source.AddSecurityDefinition(nameof(XAuthorization.ExpiresAt), new OpenApiSecurityScheme
|
|
{
|
|
In = ParameterLocation.Header,
|
|
Description = "expires at",
|
|
Type = SecuritySchemeType.ApiKey,
|
|
Name = nameof(XAuthorization.ExpiresAt)
|
|
});
|
|
|
|
//
|
|
source.AddSecurityRequirement(new OpenApiSecurityRequirement {
|
|
{
|
|
new OpenApiSecurityScheme {
|
|
Reference = new OpenApiReference {
|
|
Id = nameof (XAuthorization.ExpiresAt),
|
|
Type = ReferenceType.SecurityScheme
|
|
}
|
|
}, Array.Empty<string> ()
|
|
}
|
|
});
|
|
#endregion
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Register Swagger
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="configuration"></param>
|
|
/// <param name="settings"></param>
|
|
/// <param name="xmlFilePath"></param>
|
|
/// <param name="addRequiredXPoweredFilter"></param>
|
|
/// <param name="addXTokenAuthorization"></param>
|
|
/// <param name="addDefaultValueFilter"></param>
|
|
public static void AddXSwagger(
|
|
this IServiceCollection source,
|
|
IConfiguration configuration,
|
|
SwaggerGenOptions settings = null,
|
|
string xmlFilePath = null,
|
|
bool addRequiredXPoweredFilter = true,
|
|
bool addXTokenAuthorization = true,
|
|
bool addDefaultValueFilter = true
|
|
)
|
|
{
|
|
//
|
|
var xSwaggerConfig = configuration.GetXSwaggerConfiguration();
|
|
if (xSwaggerConfig.IsNull())
|
|
{
|
|
xSwaggerConfig = new XSwaggerConfiguration();
|
|
}
|
|
|
|
//
|
|
source.AddSingleton(xSwaggerConfig);
|
|
|
|
//
|
|
#region Prepare SwaggerGenOptions ...
|
|
if (settings.IsNull())
|
|
{
|
|
settings = new SwaggerGenOptions();
|
|
}
|
|
settings.AddXSwaggerGenOptions(
|
|
xmlFilePath: xmlFilePath,
|
|
addDefaultValueFilter: addDefaultValueFilter,
|
|
addXTokenAuthorization: addXTokenAuthorization,
|
|
addRequiredXPoweredFilter: addRequiredXPoweredFilter
|
|
);
|
|
#endregion
|
|
|
|
//
|
|
#region Prepare Swagger Doc ...
|
|
//
|
|
// Api Document Section ...
|
|
var apiDoc = new OpenApiInfo
|
|
{
|
|
Title = xSwaggerConfig.Title,
|
|
Version = xSwaggerConfig.Version,
|
|
Description = xSwaggerConfig.Description,
|
|
};
|
|
|
|
//
|
|
// Api Document TermsOfUse URL ...
|
|
if (!xSwaggerConfig.TermsOfServiceUrl.IsNullOrEmpty())
|
|
{
|
|
apiDoc.TermsOfService = new Uri(xSwaggerConfig.TermsOfServiceUrl);
|
|
}
|
|
|
|
//
|
|
// Contact Section ...
|
|
if (!xSwaggerConfig.Contact.IsNull())
|
|
{
|
|
//
|
|
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);
|
|
}
|
|
|
|
//
|
|
apiDoc.Contact = apiContact;
|
|
}
|
|
|
|
//
|
|
// License Section ...
|
|
if (!xSwaggerConfig.License.IsNull())
|
|
{
|
|
//
|
|
var apiLicense = new OpenApiLicense
|
|
{
|
|
Name = xSwaggerConfig.License.Name,
|
|
};
|
|
|
|
//
|
|
// License URL ...
|
|
if (!xSwaggerConfig.License.Url.IsNullOrEmpty())
|
|
{
|
|
apiLicense.Url = new Uri(xSwaggerConfig.License.Url);
|
|
}
|
|
|
|
//
|
|
apiDoc.License = apiLicense;
|
|
}
|
|
#endregion
|
|
|
|
//
|
|
// Register Swagger ...
|
|
source.AddSwaggerGen(
|
|
opt =>
|
|
{
|
|
//
|
|
opt.UpdateData(settings);
|
|
|
|
//
|
|
opt.SwaggerDoc("v1", apiDoc);
|
|
}
|
|
);
|
|
|
|
//
|
|
// Register Swagger Operation Filters ...
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use Sagger
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="options"></param>
|
|
public static void UseXSwagger(
|
|
this IApplicationBuilder source,
|
|
SwaggerUIOptions options = null
|
|
)
|
|
{
|
|
//
|
|
source.UseSwagger();
|
|
|
|
//
|
|
if (options.IsNull())
|
|
{
|
|
source.UseSwaggerUI();
|
|
}
|
|
else
|
|
{
|
|
source.UseSwaggerUI(options: options);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add Cross Origin Resource Sharings
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="allowedOrigins"></param>
|
|
public static void AddXCors(
|
|
this IServiceCollection source,
|
|
IEnumerable<string> allowedOrigins
|
|
)
|
|
{
|
|
//
|
|
if (!allowedOrigins.HasChild())
|
|
{
|
|
//
|
|
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 =>
|
|
{
|
|
builder
|
|
.AllowAnyOrigin()
|
|
.AllowAnyHeader()
|
|
.AllowAnyMethod()
|
|
.WithExposedHeaders("*");
|
|
});
|
|
});
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
source.AddCors(options =>
|
|
{
|
|
options.AddPolicy(XPolicy.AllowedOrigins,
|
|
builder =>
|
|
{
|
|
builder
|
|
.WithOrigins(allowedOrigins.ToArray())
|
|
.AllowAnyHeader()
|
|
.AllowAnyMethod()
|
|
.AllowCredentials()
|
|
.WithExposedHeaders("*");
|
|
});
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use X Registered Cross Origin Resource Sharings
|
|
/// </summary>
|
|
/// <param name="sources"></param>
|
|
public static void UseXCors(this IApplicationBuilder sources)
|
|
{
|
|
//
|
|
sources.UseCors(XPolicy.AllowedOrigins);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Register Api V1 Versioning ...
|
|
/// </summary>
|
|
/// <param name="services"></param>
|
|
public static void AddXApiV1Versioning(this IServiceCollection services)
|
|
{
|
|
//
|
|
// Register Api Versioning ...
|
|
services.AddApiVersioning(opt =>
|
|
{
|
|
//
|
|
// Set Default Api Version ...
|
|
opt.DefaultApiVersion = new ApiVersion(1, 0);
|
|
|
|
//
|
|
// Set Routing to Default API Version, if Version unspecified ...
|
|
opt.AssumeDefaultVersionWhenUnspecified = true;
|
|
|
|
//
|
|
// Report All Available Api Versions on Response ...
|
|
opt.ReportApiVersions = true;
|
|
});
|
|
}
|
|
}
|
|
} |