perf: 优化动态api启动
This commit is contained in:
@@ -9,84 +9,89 @@ using Microsoft.OpenApi.Any;
|
|||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using Volo.Abp.AspNetCore.Mvc;
|
using Volo.Abp.AspNetCore.Mvc;
|
||||||
|
using Volo.Abp.DependencyInjection;
|
||||||
|
using Volo.Abp.Options;
|
||||||
|
|
||||||
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
public static class SwaggerAddExtensions
|
public static class SwaggerAddExtensions
|
||||||
{
|
{
|
||||||
public static IServiceCollection AddYiSwaggerGen<Program>(this IServiceCollection services, Action<SwaggerGenOptions>? action=null)
|
public static IServiceCollection AddYiSwaggerGen<Program>(this IServiceCollection services,
|
||||||
|
Action<SwaggerGenOptions>? action = null)
|
||||||
{
|
{
|
||||||
|
var mvcOptions = services.GetPreConfigureActions<AbpAspNetCoreMvcOptions>().Configure();
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
|
||||||
var mvcOptions = serviceProvider.GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>();
|
var mvcSettings =
|
||||||
|
mvcOptions.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
|
||||||
var mvcSettings = mvcOptions.Value.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
|
|
||||||
|
|
||||||
|
|
||||||
services.AddAbpSwaggerGen(
|
services.AddAbpSwaggerGen(
|
||||||
options =>
|
options =>
|
||||||
{
|
|
||||||
if (action is not null)
|
|
||||||
{
|
{
|
||||||
action.Invoke(options);
|
if (action is not null)
|
||||||
}
|
|
||||||
|
|
||||||
// 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
|
|
||||||
foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
|
|
||||||
{
|
|
||||||
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
|
|
||||||
{
|
{
|
||||||
options.SwaggerDoc(setting.RemoteServiceName, new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
|
action.Invoke(options);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 根据分组名称过滤 API 文档
|
// 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
|
||||||
options.DocInclusionPredicate((docName, apiDesc) =>
|
foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
|
||||||
{
|
|
||||||
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
|
|
||||||
{
|
{
|
||||||
var settingOrNull = mvcSettings.Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly).FirstOrDefault();
|
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
|
||||||
if (settingOrNull is not null)
|
|
||||||
{
|
{
|
||||||
return docName == settingOrNull.RemoteServiceName;
|
options.SwaggerDoc(setting.RemoteServiceName,
|
||||||
|
new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
options.CustomSchemaIds(type => type.FullName);
|
// 根据分组名称过滤 API 文档
|
||||||
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
|
options.DocInclusionPredicate((docName, apiDesc) =>
|
||||||
if (basePath is not null)
|
|
||||||
{
|
|
||||||
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
|
|
||||||
{
|
{
|
||||||
options.IncludeXmlComments(item, true);
|
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
|
||||||
|
{
|
||||||
|
var settingOrNull = mvcSettings
|
||||||
|
.Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly)
|
||||||
|
.FirstOrDefault();
|
||||||
|
if (settingOrNull is not null)
|
||||||
|
{
|
||||||
|
return docName == settingOrNull.RemoteServiceName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
options.CustomSchemaIds(type => type.FullName);
|
||||||
|
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
|
||||||
|
if (basePath is not null)
|
||||||
|
{
|
||||||
|
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
|
||||||
|
{
|
||||||
|
options.IncludeXmlComments(item, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
|
||||||
|
{
|
||||||
|
Description = "直接输入Token即可",
|
||||||
|
Name = "Authorization",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Type = SecuritySchemeType.Http,
|
||||||
|
Scheme = "bearer"
|
||||||
|
});
|
||||||
|
var scheme = new OpenApiSecurityScheme()
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
|
||||||
|
};
|
||||||
|
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||||
|
{
|
||||||
|
[scheme] = new string[0]
|
||||||
|
});
|
||||||
|
|
||||||
|
options.OperationFilter<AddRequiredHeaderParameter>();
|
||||||
|
options.SchemaFilter<EnumSchemaFilter>();
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
|
|
||||||
{
|
|
||||||
Description = "直接输入Token即可",
|
|
||||||
Name = "Authorization",
|
|
||||||
In = ParameterLocation.Header,
|
|
||||||
Type = SecuritySchemeType.Http,
|
|
||||||
Scheme = "bearer"
|
|
||||||
});
|
|
||||||
var scheme = new OpenApiSecurityScheme()
|
|
||||||
{
|
|
||||||
Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
|
|
||||||
};
|
|
||||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
|
||||||
{
|
|
||||||
[scheme] = new string[0]
|
|
||||||
});
|
|
||||||
|
|
||||||
options.OperationFilter<AddRequiredHeaderParameter>();
|
|
||||||
options.SchemaFilter<EnumSchemaFilter>();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
@@ -103,7 +108,6 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="model"></param>
|
/// <param name="model"></param>
|
||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
|
|
||||||
public void Apply(OpenApiSchema model, SchemaFilterContext context)
|
public void Apply(OpenApiSchema model, SchemaFilterContext context)
|
||||||
{
|
{
|
||||||
if (context.Type.IsEnum)
|
if (context.Type.IsEnum)
|
||||||
@@ -112,7 +116,7 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
model.Type = "string";
|
model.Type = "string";
|
||||||
model.Format = null;
|
model.Format = null;
|
||||||
|
|
||||||
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
Enum.GetNames(context.Type)
|
Enum.GetNames(context.Type)
|
||||||
.ToList()
|
.ToList()
|
||||||
@@ -121,9 +125,10 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
Enum e = (Enum)Enum.Parse(context.Type, name);
|
Enum e = (Enum)Enum.Parse(context.Type, name);
|
||||||
var descrptionOrNull = GetEnumDescription(e);
|
var descrptionOrNull = GetEnumDescription(e);
|
||||||
model.Enum.Add(new OpenApiString(name));
|
model.Enum.Add(new OpenApiString(name));
|
||||||
stringBuilder.Append($"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
|
stringBuilder.Append(
|
||||||
|
$"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
|
||||||
});
|
});
|
||||||
model.Description= stringBuilder.ToString();
|
model.Description = stringBuilder.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,13 +138,13 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||||
return attributes.Length > 0 ? attributes[0].Description : null;
|
return attributes.Length > 0 ? attributes[0].Description : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class AddRequiredHeaderParameter : IOperationFilter
|
public class AddRequiredHeaderParameter : IOperationFilter
|
||||||
{
|
{
|
||||||
public static string HeaderKey { get; set; } = "__tenant";
|
public static string HeaderKey { get; set; } = "__tenant";
|
||||||
|
|
||||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||||
{
|
{
|
||||||
if (operation.Parameters == null)
|
if (operation.Parameters == null)
|
||||||
@@ -150,8 +155,8 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
|||||||
In = ParameterLocation.Header,
|
In = ParameterLocation.Header,
|
||||||
Required = false,
|
Required = false,
|
||||||
AllowEmptyValue = true,
|
AllowEmptyValue = true,
|
||||||
Description="租户id或者租户名称(可空为默认租户)"
|
Description = "租户id或者租户名称(可空为默认租户)"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,13 +355,13 @@ namespace Yi.Framework.Rbac.Application.Services
|
|||||||
{
|
{
|
||||||
//将后端菜单转换成前端路由,组件级别需要过滤
|
//将后端菜单转换成前端路由,组件级别需要过滤
|
||||||
output =
|
output =
|
||||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus).Vue3RuoYiRouterBuild();
|
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus.Where(x=>x.MenuSource==MenuSourceEnum.Ruoyi).ToList()).Vue3RuoYiRouterBuild();
|
||||||
}
|
}
|
||||||
else if (routerType == "pure")
|
else if (routerType == "pure")
|
||||||
{
|
{
|
||||||
//将后端菜单转换成前端路由,组件级别需要过滤
|
//将后端菜单转换成前端路由,组件级别需要过滤
|
||||||
output =
|
output =
|
||||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus).Vue3PureRouterBuild();
|
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus.Where(x=>x.MenuSource==MenuSourceEnum.Pure).ToList()).Vue3PureRouterBuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ namespace Yi.Framework.Rbac.Domain.Shared.Dtos
|
|||||||
public HashSet<RoleDto> Roles { get; set; } = new();
|
public HashSet<RoleDto> Roles { get; set; } = new();
|
||||||
public HashSet<MenuDto> Menus { get; set; } = new();
|
public HashSet<MenuDto> Menus { get; set; } = new();
|
||||||
|
|
||||||
public List<string> RoleCodes { get; set; } = new();
|
public HashSet<string> RoleCodes { get; set; } = new();
|
||||||
public List<string> PermissionCodes { get; set; } = new();
|
public HashSet<string> PermissionCodes { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserDto
|
public class UserDto
|
||||||
|
|||||||
@@ -217,8 +217,8 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dto.PermissionCodes?.ForEach(per => AddToClaim(claims, TokenTypeConst.Permission, per));
|
dto.PermissionCodes?.ToList()?.ForEach(per => AddToClaim(claims, TokenTypeConst.Permission, per));
|
||||||
dto.RoleCodes?.ForEach(role => AddToClaim(claims, AbpClaimTypes.Role, role));
|
dto.RoleCodes?.ToList()?.ForEach(role => AddToClaim(claims, AbpClaimTypes.Role, role));
|
||||||
}
|
}
|
||||||
|
|
||||||
return claims;
|
return claims;
|
||||||
|
|||||||
@@ -66,6 +66,30 @@ namespace Yi.Abp.Web
|
|||||||
{
|
{
|
||||||
private const string DefaultCorsPolicyName = "Default";
|
private const string DefaultCorsPolicyName = "Default";
|
||||||
|
|
||||||
|
public override void PreConfigureServices(ServiceConfigurationContext context)
|
||||||
|
{
|
||||||
|
//动态Api-改进在pre中配置,启动更快
|
||||||
|
PreConfigure<AbpAspNetCoreMvcOptions>(options =>
|
||||||
|
{
|
||||||
|
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly,
|
||||||
|
options => options.RemoteServiceName = "default");
|
||||||
|
options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly,
|
||||||
|
options => options.RemoteServiceName = "rbac");
|
||||||
|
options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly,
|
||||||
|
options => options.RemoteServiceName = "bbs");
|
||||||
|
options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly,
|
||||||
|
options => options.RemoteServiceName = "chat-hub");
|
||||||
|
options.ConventionalControllers.Create(
|
||||||
|
typeof(YiFrameworkTenantManagementApplicationModule).Assembly,
|
||||||
|
options => options.RemoteServiceName = "tenant-management");
|
||||||
|
options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly,
|
||||||
|
options => options.RemoteServiceName = "code-gen");
|
||||||
|
|
||||||
|
//统一前缀
|
||||||
|
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public override Task ConfigureServicesAsync(ServiceConfigurationContext context)
|
public override Task ConfigureServicesAsync(ServiceConfigurationContext context)
|
||||||
{
|
{
|
||||||
var configuration = context.Services.GetConfiguration();
|
var configuration = context.Services.GetConfiguration();
|
||||||
@@ -91,28 +115,7 @@ namespace Yi.Abp.Web
|
|||||||
|
|
||||||
//配置错误处理显示详情
|
//配置错误处理显示详情
|
||||||
Configure<AbpExceptionHandlingOptions>(options => { options.SendExceptionsDetailsToClients = true; });
|
Configure<AbpExceptionHandlingOptions>(options => { options.SendExceptionsDetailsToClients = true; });
|
||||||
|
|
||||||
//动态Api
|
|
||||||
Configure<AbpAspNetCoreMvcOptions>(options =>
|
|
||||||
{
|
|
||||||
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "default");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "rbac");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "bbs");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "chat-hub");
|
|
||||||
options.ConventionalControllers.Create(
|
|
||||||
typeof(YiFrameworkTenantManagementApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "tenant-management");
|
|
||||||
options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly,
|
|
||||||
options => options.RemoteServiceName = "code-gen");
|
|
||||||
|
|
||||||
//统一前缀
|
|
||||||
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
|
|
||||||
});
|
|
||||||
|
|
||||||
//【NewtonsoftJson严重问题!!!!!逆天】设置api格式,留给后人铭记
|
//【NewtonsoftJson严重问题!!!!!逆天】设置api格式,留给后人铭记
|
||||||
// service.AddControllers().AddNewtonsoftJson(options =>
|
// service.AddControllers().AddNewtonsoftJson(options =>
|
||||||
// {
|
// {
|
||||||
|
|||||||
Reference in New Issue
Block a user