diff --git a/aspnet-core/Lion.AbpPro.sln b/aspnet-core/Lion.AbpPro.sln index 9bf49b97..5e27339e 100644 --- a/aspnet-core/Lion.AbpPro.sln +++ b/aspnet-core/Lion.AbpPro.sln @@ -113,12 +113,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "host", "host", "{8C1B8C6C-C EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lion.AbpPro.HttpApi.Host", "services\host\Lion.AbpPro.HttpApi.Host\Lion.AbpPro.HttpApi.Host.csproj", "{FB20372D-6C96-4733-9AAC-12522F15CAA6}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{6434E3F2-B352-4B30-839A-88C2BA166D96}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lion.AbpPro.Shared.Hosting.Microservices", "shared\Lion.AbpPro.Shared.Hosting.Microservices\Lion.AbpPro.Shared.Hosting.Microservices.csproj", "{A091AE9B-3A1E-49AC-9AD5-D29310512A3D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lion.AbpPro.Shared.Hosting.Gateways", "shared\Lion.AbpPro.Shared.Hosting.Gateways\Lion.AbpPro.Shared.Hosting.Gateways.csproj", "{C018EFF9-579E-43B3-9181-543BE95E2E03}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gateways", "gateways", "{5C304CBC-F30D-413C-A0AF-8B6814A2D4A3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lion.AbpPro.WebGateway", "gateways\Lion.AbpPro.WebGateway\Lion.AbpPro.WebGateway.csproj", "{D9108313-8D05-4F5F-9AA0-B443EC3374B6}" @@ -255,6 +249,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lion.AbpPro.Starter", "fram EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lion.AbpPro.HttpClient", "frameworks\src\Lion.AbpPro.HttpClient\Lion.AbpPro.HttpClient.csproj", "{9C88C5AE-21A1-4A62-9FA3-173806CD9EE3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lion.AbpPro.AspNetCore", "frameworks\src\Lion.AbpPro.AspNetCore\Lion.AbpPro.AspNetCore.csproj", "{89CCAEA6-8176-4E4B-8D84-A2ACE2715F88}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -409,14 +405,6 @@ Global {FB20372D-6C96-4733-9AAC-12522F15CAA6}.Debug|Any CPU.Build.0 = Debug|Any CPU {FB20372D-6C96-4733-9AAC-12522F15CAA6}.Release|Any CPU.ActiveCfg = Release|Any CPU {FB20372D-6C96-4733-9AAC-12522F15CAA6}.Release|Any CPU.Build.0 = Release|Any CPU - {A091AE9B-3A1E-49AC-9AD5-D29310512A3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A091AE9B-3A1E-49AC-9AD5-D29310512A3D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A091AE9B-3A1E-49AC-9AD5-D29310512A3D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A091AE9B-3A1E-49AC-9AD5-D29310512A3D}.Release|Any CPU.Build.0 = Release|Any CPU - {C018EFF9-579E-43B3-9181-543BE95E2E03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C018EFF9-579E-43B3-9181-543BE95E2E03}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C018EFF9-579E-43B3-9181-543BE95E2E03}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C018EFF9-579E-43B3-9181-543BE95E2E03}.Release|Any CPU.Build.0 = Release|Any CPU {D9108313-8D05-4F5F-9AA0-B443EC3374B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D9108313-8D05-4F5F-9AA0-B443EC3374B6}.Debug|Any CPU.Build.0 = Debug|Any CPU {D9108313-8D05-4F5F-9AA0-B443EC3374B6}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -625,6 +613,10 @@ Global {9C88C5AE-21A1-4A62-9FA3-173806CD9EE3}.Debug|Any CPU.Build.0 = Debug|Any CPU {9C88C5AE-21A1-4A62-9FA3-173806CD9EE3}.Release|Any CPU.ActiveCfg = Release|Any CPU {9C88C5AE-21A1-4A62-9FA3-173806CD9EE3}.Release|Any CPU.Build.0 = Release|Any CPU + {89CCAEA6-8176-4E4B-8D84-A2ACE2715F88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89CCAEA6-8176-4E4B-8D84-A2ACE2715F88}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89CCAEA6-8176-4E4B-8D84-A2ACE2715F88}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89CCAEA6-8176-4E4B-8D84-A2ACE2715F88}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -677,8 +669,6 @@ Global {8D196E3D-6F95-4793-B948-79669AF09017} = {5AACD0EE-F2B2-49F6-868F-8FE08D7243C0} {8C1B8C6C-C518-4290-B070-622CCA6004DA} = {2C861ADD-76E9-4B3B-8A3C-638EBB67D683} {FB20372D-6C96-4733-9AAC-12522F15CAA6} = {8C1B8C6C-C518-4290-B070-622CCA6004DA} - {A091AE9B-3A1E-49AC-9AD5-D29310512A3D} = {6434E3F2-B352-4B30-839A-88C2BA166D96} - {C018EFF9-579E-43B3-9181-543BE95E2E03} = {6434E3F2-B352-4B30-839A-88C2BA166D96} {D9108313-8D05-4F5F-9AA0-B443EC3374B6} = {5C304CBC-F30D-413C-A0AF-8B6814A2D4A3} {F604F9BE-CAAB-4D94-8989-22DE4D966C7A} = {F8A8EB2A-2D4B-464F-9A13-F8F7B6A8FAA3} {C188A1F4-9601-42E5-9A0A-B282E13EAC41} = {F604F9BE-CAAB-4D94-8989-22DE4D966C7A} @@ -746,6 +736,7 @@ Global {2B2110E1-4C29-41AF-ADB5-C1B5F3C3C1D0} = {EFC415F8-872F-4C7E-8645-31A51481BCFC} {A70659A2-91F4-4FE7-80D0-DA12430543FD} = {7BE85EBC-99AD-4CDE-957E-4BDD087FC4E3} {9C88C5AE-21A1-4A62-9FA3-173806CD9EE3} = {7BE85EBC-99AD-4CDE-957E-4BDD087FC4E3} + {89CCAEA6-8176-4E4B-8D84-A2ACE2715F88} = {7BE85EBC-99AD-4CDE-957E-4BDD087FC4E3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F} diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/GlobalUsings.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/GlobalUsings.cs similarity index 76% rename from aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/GlobalUsings.cs rename to aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/GlobalUsings.cs index d83618ba..cf2765ce 100644 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/GlobalUsings.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/GlobalUsings.cs @@ -1,25 +1,32 @@ // Global using directives +global using Microsoft.Extensions.DependencyInjection; +global using Ocelot.DependencyInjection; +global using Ocelot.Provider.Consul; +global using Ocelot.Provider.Polly; +global using Volo.Abp.Modularity; + global using System; global using System.Collections.Concurrent; global using System.Collections.Generic; +global using System.Diagnostics.CodeAnalysis; global using System.Linq; global using System.Net; global using System.Reflection; global using System.Text; -global using System.Text.RegularExpressions; -global using Consul; +global using System.Text.Json; +global using System.Threading.Tasks; global using Lion.AbpPro; global using Lion.AbpPro.Core; global using Lion.AbpPro.Localization; global using Microsoft.AspNetCore.Builder; global using Microsoft.AspNetCore.Cors; +global using Microsoft.AspNetCore.Hosting; global using Microsoft.AspNetCore.Http; -global using Microsoft.AspNetCore.Localization; +global using Microsoft.AspNetCore.HttpsPolicy; global using Microsoft.AspNetCore.Mvc; global using Microsoft.AspNetCore.Mvc.Abstractions; global using Microsoft.AspNetCore.Mvc.ApiExplorer; -global using Microsoft.AspNetCore.Mvc.Filters; global using Microsoft.EntityFrameworkCore; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; @@ -28,10 +35,9 @@ global using Microsoft.Extensions.Localization; global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Logging.Abstractions; global using Microsoft.Extensions.Options; -global using Microsoft.Extensions.Primitives; global using Microsoft.OpenApi.Any; global using Microsoft.OpenApi.Models; -global using Serilog; +global using Ocelot.Middleware; global using Serilog.Exceptions; global using Serilog.Sinks.Elasticsearch; global using Swashbuckle.AspNetCore.Swagger; @@ -39,18 +45,12 @@ global using Swashbuckle.AspNetCore.SwaggerGen; global using Volo.Abp; global using Volo.Abp.AspNetCore.ExceptionHandling; global using Volo.Abp.AspNetCore.Mvc; -global using Volo.Abp.AspNetCore.Mvc.AntiForgery; global using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; global using Volo.Abp.Authorization; -global using Volo.Abp.Autofac; global using Volo.Abp.DependencyInjection; global using Volo.Abp.Domain.Entities; global using Volo.Abp.ExceptionHandling; global using Volo.Abp.Http; global using Volo.Abp.Json; -global using Volo.Abp.Localization; -global using Volo.Abp.Localization.ExceptionHandling; global using Volo.Abp.Modularity; -global using Volo.Abp.Swashbuckle; -global using Volo.Abp.UI.Navigation.Urls; global using Volo.Abp.Validation; \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion.AbpPro.Shared.Hosting.Microservices.csproj b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion.AbpPro.AspNetCore.csproj similarity index 92% rename from aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion.AbpPro.Shared.Hosting.Microservices.csproj rename to aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion.AbpPro.AspNetCore.csproj index bb1b1cbb..5c4c3896 100644 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion.AbpPro.Shared.Hosting.Microservices.csproj +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion.AbpPro.AspNetCore.csproj @@ -1,8 +1,9 @@ - - + + net9.0 + Lion.AbpPro.AspNetCore @@ -22,7 +23,7 @@ - + @@ -34,7 +35,7 @@ - + @@ -43,9 +44,10 @@ - + - + + diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/AbpProAspNetCoreConsts.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/AbpProAspNetCoreConsts.cs new file mode 100644 index 00000000..b2cb4344 --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/AbpProAspNetCoreConsts.cs @@ -0,0 +1,44 @@ +namespace Lion.AbpPro.AspNetCore; + +public class AbpProAspNetCoreConsts +{ + /// + /// 默认跨域策略名称 + /// + public const string DefaultCorsPolicyName = "Default"; + + /// + /// Cookies名称 + /// + public const string DefaultCookieName = "Lion.AbpPro.Http.Api"; + + /// + /// 网关配置节名称 + /// + public const string Gateway = "Gateway"; + + /// + /// 跨域配置节名称 + /// + public const string Cors = "Cors"; + + /// + /// MiniProfiler配置节名称 + /// + public const string MiniProfiler = "MiniProfiler"; + + /// + /// 多租户配置节名称 + /// + public const string MultiTenancy = "MultiTenancy"; + + /// + /// Swagger配置节名称 + /// + public const string Swagger = "Swagger"; + + /// + /// 审计配置节名称 + /// + public const string Audit = "Audit"; +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/AbpProAspNetCoreModule.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/AbpProAspNetCoreModule.cs new file mode 100644 index 00000000..9cb3b7d0 --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/AbpProAspNetCoreModule.cs @@ -0,0 +1,22 @@ +using Lion.AbpPro.AspNetCore.Options; + +namespace Lion.AbpPro.AspNetCore; + +public class AbpProAspNetCoreModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var s = context.Configuration.GetSection(AbpProAspNetCoreConsts.Cors); + context.Services.Configure(context.Configuration.GetSection(AbpProAspNetCoreConsts.Gateway)); + context.Services.Configure(context.Configuration.GetSection(AbpProAspNetCoreConsts.Cors)); + context.Services.Configure(context.Configuration.GetSection(AbpProAspNetCoreConsts.MiniProfiler)); + context.Services.Configure(context.Configuration.GetSection(AbpProAspNetCoreConsts.MultiTenancy)); + context.Services.Configure(context.Configuration.GetSection(AbpProAspNetCoreConsts.Swagger)); + context.Services.Configure(context.Configuration.GetSection(AbpProAspNetCoreConsts.Audit)); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + + } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProAuditOptions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProAuditOptions.cs new file mode 100644 index 00000000..5f805b65 --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProAuditOptions.cs @@ -0,0 +1,14 @@ +namespace Lion.AbpPro.AspNetCore.Options; + +public class AbpProAuditOptions +{ + /// + /// 是否启用 + /// + public bool Enabled { get; set; } + + /// + /// 应用名称 + /// + public string ApplicationName { get; set; } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProCorsOptions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProCorsOptions.cs new file mode 100644 index 00000000..d63678be --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProCorsOptions.cs @@ -0,0 +1,14 @@ +namespace Lion.AbpPro.AspNetCore.Options; + +public class AbpProCorsOptions +{ + /// + /// 是否启用 + /// + public bool Enabled { get; set; } + + /// + /// 跨越设置,多个用英文逗号隔开。 + /// + public string CorsOrigins { get; set; } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProGatewayOptions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProGatewayOptions.cs new file mode 100644 index 00000000..784485ca --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProGatewayOptions.cs @@ -0,0 +1,24 @@ +namespace Lion.AbpPro.AspNetCore.Options; + +public class AbpProGatewayOptions +{ + /// + /// 是否启用 + /// + public bool Enabled { get; set; } + + /// + /// consul服务地址 + /// + public string ConsulServiceUrl { get; set; } + + /// + /// consul服务名称 + /// + public string ServiceName { get; set; } + + /// + /// 健康检查地址 + /// + public string HealthUrl { get; set; } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProJwtOptions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProJwtOptions.cs new file mode 100644 index 00000000..e5926e62 --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProJwtOptions.cs @@ -0,0 +1,28 @@ +namespace Lion.AbpPro.AspNetCore.Options; + +public class AbpProJwtOptions +{ + /// + /// JWT令牌颁发者(Issuer) + /// 用于标识令牌的颁发机构 + /// + public string Issuer { get; set; } + + /// + /// JWT令牌受众(Audience) + /// 指定令牌的目标接收方 + /// + public string Audience { get; set; } + + /// + /// JWT安全密钥 + /// 用于签名和验证JWT令牌的密钥 + /// + public string SecurityKey { get; set; } + + /// + /// JWT令牌过期时间(分钟) + /// 令牌在颁发后多少分钟过期 + /// + public int ExpirationTime { get; set; } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProMiniProfilerOptions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProMiniProfilerOptions.cs new file mode 100644 index 00000000..cdf828af --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProMiniProfilerOptions.cs @@ -0,0 +1,14 @@ +namespace Lion.AbpPro.AspNetCore.Options; + +public class AbpProMiniProfilerOptions +{ + /// + /// 是否启用 + /// + public bool Enabled { get; set; } + + /// + /// path + /// + public string RouteBasePath { get; set; } = "/profiler"; +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProMultiTenancyOptions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProMultiTenancyOptions.cs new file mode 100644 index 00000000..5c28da8c --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProMultiTenancyOptions.cs @@ -0,0 +1,9 @@ +namespace Lion.AbpPro.AspNetCore.Options; + +public class AbpProMultiTenancyOptions +{ + /// + /// 是否启用 + /// + public bool Enabled { get; set; } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProSwaggerOptions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProSwaggerOptions.cs new file mode 100644 index 00000000..56f2a674 --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Lion/AbpPro/AspNetCore/Options/AbpProSwaggerOptions.cs @@ -0,0 +1,9 @@ +namespace Lion.AbpPro.AspNetCore.Options; + +public class AbpProSwaggerOptions +{ + /// + /// 是否启用 + /// + public bool Enabled { get; set; } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Builder/ApplicationBuilderExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Builder/ApplicationBuilderExtensions.cs new file mode 100644 index 00000000..2a626b2f --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Builder/ApplicationBuilderExtensions.cs @@ -0,0 +1,143 @@ +using Consul; +using Lion.AbpPro.AspNetCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Volo.Abp.Timing; +using System.Threading.Tasks; +using Lion.AbpPro.AspNetCore.Options; +using Microsoft.AspNetCore.Localization; +using Swashbuckle.AspNetCore.SwaggerUI; + +namespace Microsoft.AspNetCore.Builder; + +public static class ApplicationBuilderExtensions +{ + + + /// + /// consul服务 + /// + public static IApplicationBuilder UseAbpProConsul(this IApplicationBuilder app) + { + // 获取 AbpProGatewayOptions 配置 + var consulOptions = app.ApplicationServices.GetRequiredService>().Value; + if (!consulOptions.Enabled) + return app; + + var appLifetime = app.ApplicationServices.GetService(); + using var scope = app.ApplicationServices.CreateScope(); + var clock = scope.ServiceProvider.GetService(); + var appUrl = new Uri(consulOptions.ConsulServiceUrl, UriKind.Absolute); + + var client = scope.ServiceProvider.GetService(); + + var consulServiceRegistration = new AgentServiceRegistration + { + Name = consulOptions.ServiceName, + ID = $"{consulOptions.ServiceName}:{clock.Now:yyyyMMddHHmmssfff}", + Address = appUrl.Host, + Port = appUrl.Port, + Check = new AgentServiceCheck + { + DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), //服务停止多久后注销 + Interval = TimeSpan.FromSeconds(3), //健康检查时间间隔,或者称为心跳 间隔 + HTTP = consulOptions.HealthUrl, //健康检查地址 + Timeout = TimeSpan.FromSeconds(15) //超时时间 + } + }; + + client.Agent.ServiceRegister(consulServiceRegistration); + appLifetime.ApplicationStopping.Register(() => { client.Agent.ServiceDeregister(consulServiceRegistration.ID); }); + return app; + } + + /// + /// Ocelot服务 + /// + public static IApplicationBuilder UseAbpProOcelot(this IApplicationBuilder app) + { + // 获取 AbpProGatewayOptions 配置 + var consulOptions = app.ApplicationServices.GetRequiredService>().Value; + if (!consulOptions.Enabled) + return app; + app.UseOcelot().Wait(); + return app; + } + + /// + /// 多语言中间件 + /// 浏览器传递的请求头:Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6而abp钟简体中文为:zh-Hans + /// + public static IApplicationBuilder UseAbpProRequestLocalization(this IApplicationBuilder app) + { + return app.UseAbpRequestLocalization(options => + { + // 移除自带header解析器 + options.RequestCultureProviders.RemoveAll(provider => provider is AcceptLanguageHeaderRequestCultureProvider); + // 添加header解析器 + options.RequestCultureProviders.Add(new AbpProAcceptLanguageHeaderRequestCultureProvider()); + }); + } + + /// + /// SwaggerUI + /// + // ReSharper disable once InconsistentNaming + public static IApplicationBuilder UseAbpProSwaggerUI(this IApplicationBuilder app, string endpoint, string name) + { + var swaggerOptions = app.ApplicationServices.GetRequiredService>().Value; + if (!swaggerOptions.Enabled) return app; + app.UseSwagger(); + app.UseAbpSwaggerUI(options => + { + options.SwaggerEndpoint(endpoint, name); + options.DocExpansion(DocExpansion.None); + options.DefaultModelsExpandDepth(-1); + }); + return app; + } + + /// + /// MiniProfiler + /// + public static IApplicationBuilder UseAbpProMiniProfiler(this IApplicationBuilder app) + { + var miniProfilerOptions = app.ApplicationServices.GetRequiredService>().Value; + if (!miniProfilerOptions.Enabled) return app; + app.UseMiniProfiler(); + return app; + } + + /// + /// MultiTenancy + /// + public static IApplicationBuilder UseAbpProMultiTenancy(this IApplicationBuilder app) + { + var abpProMultiTenancyOptions = app.ApplicationServices.GetRequiredService>().Value; + if (!abpProMultiTenancyOptions.Enabled) return app; + app.UseMultiTenancy(); + return app; + } + + /// + /// 跨域设置 + /// + public static IApplicationBuilder UseAbpProCors(this IApplicationBuilder app) + { + var corsOptions = app.ApplicationServices.GetRequiredService>().Value; + if (!corsOptions.Enabled) return app; + app.UseCors(AbpProAspNetCoreConsts.DefaultCorsPolicyName); + return app; + } + + /// + /// 审计日志 + /// + public static IApplicationBuilder UseAbpProAuditing(this IApplicationBuilder app) + { + var auditOptions = app.ApplicationServices.GetRequiredService>().Value; + if (!auditOptions.Enabled) return app; + app.UseAuditing(); + return app; + } +} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Localization/AbpProAcceptLanguageHeaderRequestCultureProvider.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Localization/AbpProAcceptLanguageHeaderRequestCultureProvider.cs similarity index 92% rename from aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Localization/AbpProAcceptLanguageHeaderRequestCultureProvider.cs rename to aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Localization/AbpProAcceptLanguageHeaderRequestCultureProvider.cs index e7d617a4..ecd9957b 100644 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Localization/AbpProAcceptLanguageHeaderRequestCultureProvider.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Localization/AbpProAcceptLanguageHeaderRequestCultureProvider.cs @@ -1,4 +1,6 @@ -namespace Microsoft.AspNetCore.Localization; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNetCore.Localization; public class AbpProAcceptLanguageHeaderRequestCultureProvider : AcceptLanguageHeaderRequestCultureProvider { diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Mvc/Filters/AbpProExceptionFilter.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Mvc/Filters/AbpProExceptionFilter.cs similarity index 100% rename from aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Mvc/Filters/AbpProExceptionFilter.cs rename to aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Mvc/Filters/AbpProExceptionFilter.cs diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Mvc/Filters/AbpProResultFilter.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Mvc/Filters/AbpProResultFilter.cs new file mode 100644 index 00000000..d71b2b2d --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/AspNetCore/Mvc/Filters/AbpProResultFilter.cs @@ -0,0 +1,35 @@ +namespace Microsoft.AspNetCore.Mvc.Filters; + +public class AbpProResultFilter : IResultFilter, ITransientDependency +{ + public void OnResultExecuting(ResultExecutingContext context) + { + // 如果是page 直接return + if (context.ActionDescriptor.IsPageAction()) return; + + var controllerHasDontWrapResultAttribute = + context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.GetCustomAttributes(typeof(WrapResultAttribute), true).Any(); + var controllerActionHasDontWrapResultAttribute = context.ActionDescriptor.GetMethodInfo().GetCustomAttributes(typeof(WrapResultAttribute), true).Any(); + if (!controllerHasDontWrapResultAttribute && !controllerActionHasDontWrapResultAttribute) return; + + context.HttpContext.Response.StatusCode = 200; + var result = new WrapResult(); + if (context.Result is not EmptyResult) + { + result.SetSuccess(((ObjectResult)context.Result).Value); + } + + var jsonSerializer = context.GetRequiredService(); + + context.Result = new ContentResult() + { + StatusCode = (int)HttpStatusCode.OK, + ContentType = "application/json;charset=utf-8", + Content = jsonSerializer.Serialize(result) + }; + } + + public void OnResultExecuted(ResultExecutedContext context) + { + } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/Extensions/DependencyInjection/ServiceCollectionExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/Extensions/DependencyInjection/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..043a0bca --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Microsoft/Extensions/DependencyInjection/ServiceCollectionExtensions.cs @@ -0,0 +1,338 @@ +using Consul; +using Lion.AbpPro.AspNetCore; +using Lion.AbpPro.AspNetCore.Options; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.IdentityModel.Tokens; +using Swagger; +using Volo.Abp.AspNetCore.Auditing; +using Volo.Abp.AspNetCore.MultiTenancy; +using Volo.Abp.AspNetCore.Mvc.AntiForgery; +using Volo.Abp.Auditing; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + + + /// + /// Ocelot配置 + /// + public static IServiceCollection AddAbpProOcelot(this IServiceCollection service) + { + var configuration = service.GetConfiguration(); + service.AddOcelot(configuration).AddConsul().AddPolly(); + return service; + } + + public static IServiceCollection AddAbpProConsul(this IServiceCollection service) + { + var consulOptions = service.GetRequiredService>().Value; + if (!consulOptions.Enabled) + return service; + + service.AddSingleton(p => new ConsulClient(config => { config.Address = new Uri(consulOptions.ConsulServiceUrl); })); + + return service; + } + + /// + /// 健康检查 + /// + public static IServiceCollection AddAbpProHealthChecks(this IServiceCollection service) + { + // TODO 检查数据库和redis是否正常 AspNetCore.HealthChecks.Redis AspNetCore.HealthChecks.MySql + // context.Services.AddHealthChecks().AddRedis(redisConnectionString).AddMySql(connectString); + return service; + } + + /// + /// 配置租户解析 + /// + public static IServiceCollection AddAbpProTenantResolvers(this IServiceCollection service) + { + service.Configure(options => + { + options.TenantResolvers.Clear(); + // 只保留通过请求头解析租户 + // options.TenantResolvers.Add(new QueryStringTenantResolveContributor()); + // options.TenantResolvers.Add(new RouteTenantResolveContributor()); + options.TenantResolvers.Add(new HeaderTenantResolveContributor()); + // options.TenantResolvers.Add(new CookieTenantResolveContributor()); + }); + + return service; + } + + /// + /// 多语言配置 + /// + public static IServiceCollection AddAbpProLocalization(this IServiceCollection service) + { + service.Configure(options => + { + options.Languages.Add(new LanguageInfo("ar", "ar", "العربية")); + options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština")); + options.Languages.Add(new LanguageInfo("en", "en", "English")); + options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)")); + options.Languages.Add(new LanguageInfo("fr", "fr", "Français")); + options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar")); + options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português")); + options.Languages.Add(new LanguageInfo("ru", "ru", "Русский")); + options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe")); + options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文")); + }); + return service; + } + + /// + /// 配置跨域 + /// + public static IServiceCollection AddAbpProCors(this IServiceCollection service) + { + var corsOptions = service.GetRequiredService>().Value; + if (!corsOptions.Enabled) return service; + + service.AddCors(options => + { + options.AddPolicy(AbpProAspNetCoreConsts.DefaultCorsPolicyName, builder => + { + builder + .WithOrigins( + corsOptions.CorsOrigins + .Split(",", StringSplitOptions.RemoveEmptyEntries) + .Select(o => o.RemovePostFix("/")) + .ToArray() + ) + //.WithAbpExposedHeaders() + .SetIsOriginAllowedToAllowWildcardSubdomains() + .AllowAnyHeader() + .AllowAnyMethod() + //.AllowCredentials() + // https://www.cnblogs.com/JulianHuang/p/14225515.html + // https://learn.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-7.0 + .SetPreflightMaxAge((TimeSpan.FromHours(24))); + }); + }); + return service; + } + + /// + /// 阻止跨站点请求伪造 + /// https://docs.microsoft.com/zh-cn/aspnet/core/security/anti-request-forgery?view=aspnetcore-6.0 + /// + public static IServiceCollection AddAbpProAntiForgery(this IServiceCollection service) + { + service.Configure(options => { options.AutoValidate = false; }); + return service; + } + + /// + /// 异常处理 + /// + public static IServiceCollection AddAbpProExceptions(this IServiceCollection service) + { + service.AddMvc(options => + { + options.Filters.Add(typeof(AbpProExceptionFilter)); + options.Filters.Add(typeof(AbpProResultFilter)); + } + ); + return service; + } + + /// + /// 添加swagger + /// + public static IServiceCollection AddAbpProSwagger(this IServiceCollection service, string name, string version = "v1") + { + var swaggerOptions = service.GetRequiredService>().Value; + if (!swaggerOptions.Enabled) return service; + + service.AddSwaggerGen(options => + { + // 文件下载类型 + options.MapType(() => new OpenApiSchema() { Type = "file" }); + options.SwaggerDoc(name, new OpenApiInfo { Title = name, Version = version }); + options.DocInclusionPredicate((docName, description) => true); + options.EnableAnnotations(); // 启用注解 + options.DocumentFilter(); + options.SchemaFilter(); + // 加载所有xml注释,这里会导致swagger加载有点缓慢 + var xmlPaths = Directory.GetFiles(AppContext.BaseDirectory, "*.xml"); + foreach (var xml in xmlPaths) + { + options.IncludeXmlComments(xml, true); + } + + options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, + new OpenApiSecurityScheme() + { + Description = "直接在下框输入JWT生成的Token", + Name = "Authorization", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + Scheme = JwtBearerDefaults.AuthenticationScheme, + BearerFormat = "JWT" + }); + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, Id = "Bearer" + } + }, + new List() + } + }); + + options.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme() + { + Type = SecuritySchemeType.ApiKey, + In = ParameterLocation.Header, + Name = "Accept-Language", + Description = "多语言设置,系统预设语言有zh-Hans、en,默认为zh-Hans", + }); + + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { Type = ReferenceType.SecurityScheme, Id = "ApiKey" } + }, + Array.Empty() + } + }); + }); + return service; + } + + /// + /// 配置MiniProfiler + /// + public static IServiceCollection AddAbpProMiniProfiler(this IServiceCollection service) + { + var options = service.GetRequiredService>().Value; + if (!options.Enabled) return service; + service.AddMiniProfiler(opt => opt.RouteBasePath = "/profiler").AddEntityFramework(); + return service; + } + + /// + /// 添加多租户支持 + /// + public static IServiceCollection AddAbpProMultiTenancy(this IServiceCollection service) + { + var multiTenancyOptions = service.GetRequiredService>().Value; + service.Configure(options => { options.IsEnabled = multiTenancyOptions.Enabled; }); + return service; + } + + /// + /// 配置JWT + /// + public static IServiceCollection AddAbpProAuthentication(this IServiceCollection service) + { + var jwtOptions = service.GetRequiredService>().Value; + + service.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => + { + options.TokenValidationParameters = + new TokenValidationParameters() + { + // 是否开启签名认证 + ValidateIssuerSigningKey = true, + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + ClockSkew = TimeSpan.Zero, + ValidIssuer = jwtOptions.Issuer, + ValidAudience = jwtOptions.Audience, + IssuerSigningKey = + new SymmetricSecurityKey( + Encoding.ASCII.GetBytes(jwtOptions.SecurityKey)) + }; + + options.Events = new JwtBearerEvents + { + OnMessageReceived = currentContext => + { + var path = currentContext.HttpContext.Request.Path; + if (path.StartsWithSegments("/login")) + { + return Task.CompletedTask; + } + + var accessToken = string.Empty; + if (currentContext.HttpContext.Request.Headers.ContainsKey("Authorization")) + { + accessToken = currentContext.HttpContext.Request.Headers["Authorization"]; + if (!string.IsNullOrWhiteSpace(accessToken)) + { + accessToken = accessToken.Split(" ").LastOrDefault(); + } + } + + if (accessToken.IsNullOrWhiteSpace()) + { + accessToken = currentContext.Request.Query["access_token"].FirstOrDefault(); + } + + if (accessToken.IsNullOrWhiteSpace()) + { + accessToken = currentContext.Request.Cookies[AbpProAspNetCoreConsts.DefaultCookieName]; + } + + currentContext.Token = accessToken; + currentContext.Request.Headers.Remove("Authorization"); + currentContext.Request.Headers.Append("Authorization", $"Bearer {accessToken}"); + + return Task.CompletedTask; + } + }; + }); + + return service; + } + + + /// + /// 审计日志 + /// + public static IServiceCollection AddAbpProAuditLog(this IServiceCollection service) + { + var auditOptions = service.GetRequiredService>().Value; + service.Configure + (options => + { + options.IsEnabled = auditOptions.Enabled; + options.EntityHistorySelectors.AddAllEntities(); + options.ApplicationName = auditOptions.ApplicationName; + } + ); + + service.Configure(options => + { + options.IgnoredUrls.Add("/AuditLogs/page"); + options.IgnoredUrls.Add("/hangfire/stats"); + options.IgnoredUrls.Add("/hangfire/recurring/trigger"); + options.IgnoredUrls.Add("/cap"); + options.IgnoredUrls.Add("/"); + }); + return service; + } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Serilog/SerilogToEsExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Serilog/SerilogToEsExtensions.cs new file mode 100644 index 00000000..57466e36 --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Serilog/SerilogToEsExtensions.cs @@ -0,0 +1,118 @@ +namespace Serilog; + +public static class SerilogToEsExtensions +{ + public static void SetSerilogConfiguration(LoggerConfiguration loggerConfiguration, IConfiguration configuration) + { + // 默认读取 configuration 中 "Serilog" 节点下的配置 + loggerConfiguration + .ReadFrom.Configuration(configuration) + .Enrich.FromLogContext(); + + var writeToElasticSearch = configuration.GetValue("ElasticSearch:Enabled", false); + + + // LogToElasticSearch:Enabled = true 才输出至ES + if (!writeToElasticSearch) + return; + + var applicationName = "Lion.AbpPro.HttpApi.Host"; + + var esUrl = configuration["ElasticSearch:Url"]; + // 需要设置ES URL + if (string.IsNullOrEmpty(esUrl)) + return; + + + var indexFormat = configuration["ElasticSearch:IndexFormat"]; + + // 需要设置ES URL + if (string.IsNullOrEmpty(indexFormat)) + return; + + var esUserName = configuration["ElasticSearch:UserName"]; + var esPassword = configuration["ElasticSearch:Password"]; + + loggerConfiguration.Enrich.FromLogContext().Enrich.WithExceptionDetails().WriteTo + .Elasticsearch(BuildElasticSearchSinkOptions(esUrl, indexFormat, esUserName, esPassword)); + loggerConfiguration.Enrich.WithProperty("Application", applicationName); + } + + // 创建Es连接 + private static ElasticsearchSinkOptions BuildElasticSearchSinkOptions( + string url, + string indexFormat, + string userName, + string password) + { + if (string.IsNullOrEmpty(userName)) + { + return new ElasticsearchSinkOptions(new Uri(url)) + { + AutoRegisterTemplate = true, + AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, + IndexFormat = indexFormat + }; + } + + return new ElasticsearchSinkOptions(new Uri(url)) + { + AutoRegisterTemplate = true, + AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, + IndexFormat = indexFormat, + ModifyConnectionSettings = x => x.BasicAuthentication(userName, password) + }; + } + + public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext) + { + var request = httpContext.Request; + + // 为每个请求都设置通用的属性 + diagnosticContext.Set("Host", request.Host); + diagnosticContext.Set("Protocol", request.Protocol); + diagnosticContext.Set("Scheme", request.Scheme); + diagnosticContext.Set("RemoteIpAddress", httpContext.Connection.RemoteIpAddress); + // 如果要记录 Request Body 或 Response Body + // 参考 https://stackoverflow.com/questions/60076922/serilog-logging-web-api-methods-adding-context-properties-inside-middleware + string requestBody = ReadRequestBody(httpContext.Request).Result; + if (!string.IsNullOrEmpty(requestBody)) + { + diagnosticContext.Set("RequestBody", requestBody); + } + + // string responseBody = ReadResponseBody(httpContext.Response).Result; + // if (!string.IsNullOrEmpty(responseBody)) + // { + // diagnosticContext.Set("ResponseBody", requestBody); + // } + + if (request.QueryString.HasValue) + { + diagnosticContext.Set("QueryString", request?.QueryString.Value ?? string.Empty); + } + } + + private static async Task ReadRequestBody(HttpRequest request) + { + HttpRequestRewindExtensions.EnableBuffering(request); + + var body = request.Body; + var buffer = new byte[Convert.ToInt32(request.ContentLength)]; + await request.Body.ReadAsync(buffer, 0, buffer.Length); + string requestBody = Encoding.UTF8.GetString(buffer); + body.Seek(0, SeekOrigin.Begin); + request.Body = body; + + return $"{requestBody}"; + } + + private static async Task ReadResponseBody(HttpResponse response) + { + response.Body.Seek(0, SeekOrigin.Begin); + string responseBody = await new StreamReader(response.Body).ReadToEndAsync(); + response.Body.Seek(0, SeekOrigin.Begin); + + return $"{responseBody}"; + } +} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Swagger/CachingSwaggerProvider.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Swagger/CachingSwaggerProvider.cs similarity index 100% rename from aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Swagger/CachingSwaggerProvider.cs rename to aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Swagger/CachingSwaggerProvider.cs diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Swagger/EnumSchemaFilter.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Swagger/EnumSchemaFilter.cs similarity index 100% rename from aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Swagger/EnumSchemaFilter.cs rename to aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Swagger/EnumSchemaFilter.cs diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Swagger/HiddenAbpDefaultApiFilter.cs b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Swagger/HiddenAbpDefaultApiFilter.cs new file mode 100644 index 00000000..e4155e36 --- /dev/null +++ b/aspnet-core/frameworks/src/Lion.AbpPro.AspNetCore/Swagger/HiddenAbpDefaultApiFilter.cs @@ -0,0 +1,48 @@ +namespace Swagger; + +/// +/// 在使用nswag的时候,原生默认的api导致生产的代理类存在问题 +/// 所有隐藏原生的api,重写路由 +/// +public class HiddenAbpDefaultApiFilter : IDocumentFilter +{ + public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) + { + foreach (ApiDescription apiDescription in context.ApiDescriptions) + { + if (apiDescription.TryGetMethodInfo(out MethodInfo method)) + { + string key = "/" + apiDescription.RelativePath; + var reuslt = IsHidden(key); + if (reuslt) swaggerDoc.Paths.Remove(key); + } + } + } + + private bool IsHidden(string key) + { + var list = GetHiddenAbpDefaultApiList(); + foreach (var item in list) + { + if (key.Contains(item)) return true; + } + + return false; + } + + private List GetHiddenAbpDefaultApiList() + { + return new List() { + "/api/abp/multi-tenancy/tenants", + "/api/account", + "/api/feature-management/features", + "/api/permission-management/permissions", + "/api/identity/my-profile", + "/api/identity", + "/api/multi-tenancy/tenants", + "/api/setting-management/emailing", + "/configuration", + "/outputcache" + }; + } +} \ No newline at end of file diff --git a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/AbpProCapServiceCollectionExtensions.cs b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/AbpProCapServiceCollectionExtensions.cs index 49272527..c7d1a325 100644 --- a/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/AbpProCapServiceCollectionExtensions.cs +++ b/aspnet-core/frameworks/src/Lion.AbpPro.CAP/Lion/AbpPro/CAP/AbpProCapServiceCollectionExtensions.cs @@ -11,4 +11,14 @@ public static class AbpProCapServiceCollectionExtensions context.Services.AddCap(capAction); return context; } + + public static IServiceCollection AddAbpCap(this IServiceCollection service, Action capAction) + { + service.Replace(ServiceDescriptor.Transient()); + service.Replace(ServiceDescriptor.Transient()); + service.AddSingleton(); + service.AddTransient(); + service.AddCap(capAction); + return service; + } } \ No newline at end of file diff --git a/aspnet-core/gateways/Lion.AbpPro.WebGateway/AbpProWebGatewayModule.cs b/aspnet-core/gateways/Lion.AbpPro.WebGateway/AbpProWebGatewayModule.cs index e4005326..254c8d09 100644 --- a/aspnet-core/gateways/Lion.AbpPro.WebGateway/AbpProWebGatewayModule.cs +++ b/aspnet-core/gateways/Lion.AbpPro.WebGateway/AbpProWebGatewayModule.cs @@ -1,7 +1,9 @@ +using Lion.AbpPro.AspNetCore; + namespace Lion.AbpPro.WebGateway { [DependsOn( - typeof(AbpProSharedHostingGatewayModule))] + typeof(AbpProAspNetCoreModule))] public class AbpProWebGatewayModule : AbpModule { private const string DefaultCorsPolicyName = "Default"; diff --git a/aspnet-core/gateways/Lion.AbpPro.WebGateway/Lion.AbpPro.WebGateway.csproj b/aspnet-core/gateways/Lion.AbpPro.WebGateway/Lion.AbpPro.WebGateway.csproj index 3739da0a..aa8a69ca 100644 --- a/aspnet-core/gateways/Lion.AbpPro.WebGateway/Lion.AbpPro.WebGateway.csproj +++ b/aspnet-core/gateways/Lion.AbpPro.WebGateway/Lion.AbpPro.WebGateway.csproj @@ -4,9 +4,8 @@ net9.0 - - + diff --git a/aspnet-core/modules/BasicManagement/host/Lion.AbpPro.BasicManagement.HttpApi.Host/BasicManagementHttpApiHostModule.cs b/aspnet-core/modules/BasicManagement/host/Lion.AbpPro.BasicManagement.HttpApi.Host/BasicManagementHttpApiHostModule.cs index fdcab2cb..0264bdd5 100644 --- a/aspnet-core/modules/BasicManagement/host/Lion.AbpPro.BasicManagement.HttpApi.Host/BasicManagementHttpApiHostModule.cs +++ b/aspnet-core/modules/BasicManagement/host/Lion.AbpPro.BasicManagement.HttpApi.Host/BasicManagementHttpApiHostModule.cs @@ -1,4 +1,5 @@ using System.Text; +using Lion.AbpPro.AspNetCore; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.DataProtection; using Lion.AbpPro.BasicManagement.EntityFrameworkCore; @@ -34,7 +35,7 @@ namespace Lion.AbpPro.BasicManagement; typeof(AbpEntityFrameworkCoreMySQLModule), typeof(AbpAspNetCoreSerilogModule), typeof(AbpSwashbuckleModule), - typeof(AbpProSharedHostingMicroserviceModule) + typeof(AbpProAspNetCoreModule) )] public class BasicManagementHttpApiHostModule : AbpModule { diff --git a/aspnet-core/modules/BasicManagement/host/Lion.AbpPro.BasicManagement.HttpApi.Host/Lion.AbpPro.BasicManagement.HttpApi.Host.csproj b/aspnet-core/modules/BasicManagement/host/Lion.AbpPro.BasicManagement.HttpApi.Host/Lion.AbpPro.BasicManagement.HttpApi.Host.csproj index 225b2fdc..263d3ec4 100644 --- a/aspnet-core/modules/BasicManagement/host/Lion.AbpPro.BasicManagement.HttpApi.Host/Lion.AbpPro.BasicManagement.HttpApi.Host.csproj +++ b/aspnet-core/modules/BasicManagement/host/Lion.AbpPro.BasicManagement.HttpApi.Host/Lion.AbpPro.BasicManagement.HttpApi.Host.csproj @@ -26,7 +26,7 @@ - + diff --git a/aspnet-core/modules/DataDictionaryManagement/host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host/DataDictionaryManagementHttpApiHostModule.cs b/aspnet-core/modules/DataDictionaryManagement/host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host/DataDictionaryManagementHttpApiHostModule.cs index 57f5c214..bc66f7f6 100644 --- a/aspnet-core/modules/DataDictionaryManagement/host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host/DataDictionaryManagementHttpApiHostModule.cs +++ b/aspnet-core/modules/DataDictionaryManagement/host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host/DataDictionaryManagementHttpApiHostModule.cs @@ -1,3 +1,5 @@ +using Lion.AbpPro.AspNetCore; + namespace Lion.AbpPro.DataDictionaryManagement { [DependsOn( @@ -12,7 +14,8 @@ namespace Lion.AbpPro.DataDictionaryManagement typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), typeof(AbpAspNetCoreSerilogModule), - typeof(AbpSwashbuckleModule) + typeof(AbpSwashbuckleModule), + typeof(AbpProAspNetCoreModule) )] public class DataDictionaryManagementHttpApiHostModule : AbpModule { diff --git a/aspnet-core/modules/DataDictionaryManagement/host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host.csproj b/aspnet-core/modules/DataDictionaryManagement/host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host.csproj index 03a08e39..da09e1b0 100644 --- a/aspnet-core/modules/DataDictionaryManagement/host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host.csproj +++ b/aspnet-core/modules/DataDictionaryManagement/host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host/Lion.AbpPro.DataDictionaryManagement.HttpApi.Host.csproj @@ -26,7 +26,7 @@ - + diff --git a/aspnet-core/modules/FileManagement/host/Lion.AbpPro.FileManagement.HttpApi.Host/FileManagementHttpApiHostModule.cs b/aspnet-core/modules/FileManagement/host/Lion.AbpPro.FileManagement.HttpApi.Host/FileManagementHttpApiHostModule.cs index 67d4797d..ee88f312 100644 --- a/aspnet-core/modules/FileManagement/host/Lion.AbpPro.FileManagement.HttpApi.Host/FileManagementHttpApiHostModule.cs +++ b/aspnet-core/modules/FileManagement/host/Lion.AbpPro.FileManagement.HttpApi.Host/FileManagementHttpApiHostModule.cs @@ -1,3 +1,5 @@ +using Lion.AbpPro.AspNetCore; + namespace Lion.AbpPro.FileManagement; [DependsOn( @@ -8,7 +10,8 @@ namespace Lion.AbpPro.FileManagement; typeof(AbpCachingStackExchangeRedisModule), typeof(AbpAspNetCoreSerilogModule), typeof(AbpSwashbuckleModule), - typeof(AbpEntityFrameworkCoreMySQLModule) + typeof(AbpEntityFrameworkCoreMySQLModule), + typeof(AbpProAspNetCoreModule) )] public class FileManagementHttpApiHostModule : AbpModule { diff --git a/aspnet-core/modules/FileManagement/host/Lion.AbpPro.FileManagement.HttpApi.Host/Lion.AbpPro.FileManagement.HttpApi.Host.csproj b/aspnet-core/modules/FileManagement/host/Lion.AbpPro.FileManagement.HttpApi.Host/Lion.AbpPro.FileManagement.HttpApi.Host.csproj index a4b2007a..a41965bd 100644 --- a/aspnet-core/modules/FileManagement/host/Lion.AbpPro.FileManagement.HttpApi.Host/Lion.AbpPro.FileManagement.HttpApi.Host.csproj +++ b/aspnet-core/modules/FileManagement/host/Lion.AbpPro.FileManagement.HttpApi.Host/Lion.AbpPro.FileManagement.HttpApi.Host.csproj @@ -32,7 +32,7 @@ - + diff --git a/aspnet-core/modules/LanguageManagement/host/Lion.AbpPro.LanguageManagement.HttpApi.Host/LanguageManagementHttpApiHostModule.cs b/aspnet-core/modules/LanguageManagement/host/Lion.AbpPro.LanguageManagement.HttpApi.Host/LanguageManagementHttpApiHostModule.cs index 006a0551..c46e0ac6 100644 --- a/aspnet-core/modules/LanguageManagement/host/Lion.AbpPro.LanguageManagement.HttpApi.Host/LanguageManagementHttpApiHostModule.cs +++ b/aspnet-core/modules/LanguageManagement/host/Lion.AbpPro.LanguageManagement.HttpApi.Host/LanguageManagementHttpApiHostModule.cs @@ -1,3 +1,5 @@ +using Lion.AbpPro.AspNetCore; + namespace Lion.AbpPro.LanguageManagement { [DependsOn( @@ -12,7 +14,8 @@ namespace Lion.AbpPro.LanguageManagement typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), typeof(AbpAspNetCoreSerilogModule), - typeof(AbpSwashbuckleModule) + typeof(AbpSwashbuckleModule), + typeof(AbpProAspNetCoreModule) )] public class LanguageManagementHttpApiHostModule : AbpModule { diff --git a/aspnet-core/modules/LanguageManagement/host/Lion.AbpPro.LanguageManagement.HttpApi.Host/Lion.AbpPro.LanguageManagement.HttpApi.Host.csproj b/aspnet-core/modules/LanguageManagement/host/Lion.AbpPro.LanguageManagement.HttpApi.Host/Lion.AbpPro.LanguageManagement.HttpApi.Host.csproj index a3eed333..b364eef6 100644 --- a/aspnet-core/modules/LanguageManagement/host/Lion.AbpPro.LanguageManagement.HttpApi.Host/Lion.AbpPro.LanguageManagement.HttpApi.Host.csproj +++ b/aspnet-core/modules/LanguageManagement/host/Lion.AbpPro.LanguageManagement.HttpApi.Host/Lion.AbpPro.LanguageManagement.HttpApi.Host.csproj @@ -26,7 +26,7 @@ - + diff --git a/aspnet-core/modules/NotificationManagement/host/Lion.AbpPro.NotificationManagement.HttpApi.Host/Lion.AbpPro.NotificationManagement.HttpApi.Host.csproj b/aspnet-core/modules/NotificationManagement/host/Lion.AbpPro.NotificationManagement.HttpApi.Host/Lion.AbpPro.NotificationManagement.HttpApi.Host.csproj index 83b41e4a..5f6be1df 100644 --- a/aspnet-core/modules/NotificationManagement/host/Lion.AbpPro.NotificationManagement.HttpApi.Host/Lion.AbpPro.NotificationManagement.HttpApi.Host.csproj +++ b/aspnet-core/modules/NotificationManagement/host/Lion.AbpPro.NotificationManagement.HttpApi.Host/Lion.AbpPro.NotificationManagement.HttpApi.Host.csproj @@ -31,8 +31,8 @@ + - diff --git a/aspnet-core/modules/NotificationManagement/host/Lion.AbpPro.NotificationManagement.HttpApi.Host/NotificationManagementHttpApiHostModule.cs b/aspnet-core/modules/NotificationManagement/host/Lion.AbpPro.NotificationManagement.HttpApi.Host/NotificationManagementHttpApiHostModule.cs index 4169f739..fc341b4d 100644 --- a/aspnet-core/modules/NotificationManagement/host/Lion.AbpPro.NotificationManagement.HttpApi.Host/NotificationManagementHttpApiHostModule.cs +++ b/aspnet-core/modules/NotificationManagement/host/Lion.AbpPro.NotificationManagement.HttpApi.Host/NotificationManagementHttpApiHostModule.cs @@ -1,3 +1,5 @@ +using Lion.AbpPro.AspNetCore; + namespace Lion.AbpPro.NotificationManagement; [DependsOn( @@ -9,7 +11,8 @@ namespace Lion.AbpPro.NotificationManagement; typeof(AbpAspNetCoreSerilogModule), typeof(AbpSwashbuckleModule), typeof(AbpProCapModule), - typeof(AbpEntityFrameworkCoreMySQLModule) + typeof(AbpEntityFrameworkCoreMySQLModule), + typeof(AbpProAspNetCoreModule) )] public class NotificationManagementHttpApiHostModule : AbpModule { diff --git a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.Configure.cs b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.Configure.cs deleted file mode 100644 index 766bfdaa..00000000 --- a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.Configure.cs +++ /dev/null @@ -1,293 +0,0 @@ -using Medallion.Threading; -using Medallion.Threading.Redis; -using Volo.Abp.BlobStoring; -using Volo.Abp.BlobStoring.FileSystem; -#pragma warning disable CS0618 // Type or member is obsolete - -namespace Lion.AbpPro; - -public partial class AbpProHttpApiHostModule -{ - private void ConfigureHangfire(ServiceConfigurationContext context) - { - var redisStorageOptions = new RedisStorageOptions() - { - Db = context.Services.GetConfiguration().GetValue("Hangfire:Redis:DB") - }; - - Configure(options => { options.IsJobExecutionEnabled = true; }); - - context.Services.AddHangfire(config => - { - config.UseRedisStorage( - context.Services.GetConfiguration().GetValue("Hangfire:Redis:Host"), redisStorageOptions) - .WithJobExpirationTimeout(TimeSpan.FromDays(7)); - var delaysInSeconds = new[] { 10, 60, 60 * 3 }; // 重试时间间隔 - const int Attempts = 3; // 重试次数 - config.UseFilter(new AutomaticRetryAttribute() { Attempts = Attempts, DelaysInSeconds = delaysInSeconds }); - //config.UseFilter(new AutoDeleteAfterSuccessAttribute(TimeSpan.FromDays(7))); - config.UseFilter(new JobRetryLastFilter(Attempts)); - }); - } - - /// - /// 配置MiniProfiler - /// - private void ConfigureMiniProfiler(ServiceConfigurationContext context) - { - if (context.Services.GetConfiguration().GetValue("MiniProfiler:Enabled", false)) - { - context.Services.AddMiniProfiler(options => options.RouteBasePath = "/profiler").AddEntityFramework(); - } - } - - /// - /// 配置JWT - /// - private void ConfigureJwtAuthentication(ServiceConfigurationContext context, IConfiguration configuration) - { - context.Services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(options => - { - options.TokenValidationParameters = - new TokenValidationParameters() - { - // 是否开启签名认证 - ValidateIssuerSigningKey = true, - ValidateIssuer = true, - ValidateAudience = true, - ValidateLifetime = true, - ClockSkew = TimeSpan.Zero, - ValidIssuer = configuration["Jwt:Issuer"], - ValidAudience = configuration["Jwt:Audience"], - IssuerSigningKey = - new SymmetricSecurityKey( - Encoding.ASCII.GetBytes(configuration["Jwt:SecurityKey"])) - }; - - options.Events = new JwtBearerEvents - { - OnMessageReceived = currentContext => - { - var path = currentContext.HttpContext.Request.Path; - if (path.StartsWithSegments("/login")) - { - return Task.CompletedTask; - } - - var accessToken = string.Empty; - if (currentContext.HttpContext.Request.Headers.ContainsKey("Authorization")) - { - accessToken = currentContext.HttpContext.Request.Headers["Authorization"]; - if (!string.IsNullOrWhiteSpace(accessToken)) - { - accessToken = accessToken.Split(" ").LastOrDefault(); - } - } - - if (accessToken.IsNullOrWhiteSpace()) - { - accessToken = currentContext.Request.Query["access_token"].FirstOrDefault(); - } - - if (accessToken.IsNullOrWhiteSpace()) - { - accessToken = currentContext.Request.Cookies[AbpProHttpApiHostConst.DefaultCookieName]; - } - - currentContext.Token = accessToken; - currentContext.Request.Headers.Remove("Authorization"); - currentContext.Request.Headers.Append("Authorization", $"Bearer {accessToken}"); - - return Task.CompletedTask; - } - }; - }); - } - - - /// - /// Redis缓存 - /// - private void ConfigureCache(ServiceConfigurationContext context) - { - Configure( - options => { options.KeyPrefix = "AbpPro:"; }); - var configuration = context.Services.GetConfiguration(); - var redis = ConnectionMultiplexer.Connect(configuration.GetValue("Redis:Configuration")); - context.Services - .AddDataProtection() - .PersistKeysToStackExchangeRedis(redis, "AbpPro-Protection-Keys"); - } - - /// - /// 配置Identity - /// - private void ConfigureIdentity(ServiceConfigurationContext context) - { - context.Services.Configure(options => { options.Lockout = new LockoutOptions() { AllowedForNewUsers = false }; }); - } - - private void ConfigurationSignalR(ServiceConfigurationContext context) - { - context.Services - .AddSignalR() - .AddStackExchangeRedis(context.Services.GetConfiguration().GetValue("Redis:Configuration"), - options => { options.Configuration.ChannelPrefix = "Lion.AbpPro"; }); - } - - private void ConfigureSwaggerServices(ServiceConfigurationContext context) - { - context.Services.AddSwaggerGen( - options => - { - // 文件下载类型 - options.MapType(() => new OpenApiSchema() { Type = "file" }); - - options.SwaggerDoc("AbpPro", - new OpenApiInfo { Title = "AbpPro API", Version = "v1" }); - options.DocInclusionPredicate((docName, description) => true); - options.EnableAnnotations(); // 启用注解 - options.DocumentFilter(); - options.SchemaFilter(); - // 加载所有xml注释,这里会导致swagger加载有点缓慢 - var xmlPaths = Directory.GetFiles(AppContext.BaseDirectory, "*.xml"); - foreach (var xml in xmlPaths) - { - options.IncludeXmlComments(xml, true); - } - - options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, - new OpenApiSecurityScheme() - { - Description = "直接在下框输入JWT生成的Token", - Name = "Authorization", - In = ParameterLocation.Header, - Type = SecuritySchemeType.Http, - Scheme = JwtBearerDefaults.AuthenticationScheme, - BearerFormat = "JWT" - }); - options.AddSecurityRequirement(new OpenApiSecurityRequirement - { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { - Type = ReferenceType.SecurityScheme, Id = "Bearer" - } - }, - new List() - } - }); - - options.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme() - { - Type = SecuritySchemeType.ApiKey, - In = ParameterLocation.Header, - Name = "Accept-Language", - Description = "多语言设置,系统预设语言有zh-Hans、en,默认为zh-Hans", - }); - - options.AddSecurityRequirement(new OpenApiSecurityRequirement - { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference - { Type = ReferenceType.SecurityScheme, Id = "ApiKey" } - }, - Array.Empty() - } - }); - }); - } - - - private void ConfigureCap(ServiceConfigurationContext context) - { - var configuration = context.Services.GetConfiguration(); - context.AddAbpCap(capOptions => - { - capOptions.SetCapDbConnectionString(configuration["ConnectionStrings:Default"]); - capOptions.UseEntityFramework(); - capOptions.UseRabbitMQ(option => - { - option.HostName = configuration.GetValue("Cap:RabbitMq:HostName"); - option.UserName = configuration.GetValue("Cap:RabbitMq:UserName"); - option.Password = configuration.GetValue("Cap:RabbitMq:Password"); - option.Port = configuration.GetValue("Cap:RabbitMq:Port"); - }); - capOptions.UseDashboard(options => - { - options.AuthorizationPolicy = AbpProCapPermissions.CapManagement.Cap; - }); - }); - } - - /// - /// 审计日志 - /// - private void ConfigureAuditLog(ServiceConfigurationContext context) - { - Configure - ( - options => - { - options.IsEnabled = true; - options.EntityHistorySelectors.AddAllEntities(); - options.ApplicationName = "Lion.AbpPro"; - } - ); - - Configure( - options => - { - options.IgnoredUrls.Add("/AuditLogs/page"); - options.IgnoredUrls.Add("/hangfire/stats"); - options.IgnoredUrls.Add("/hangfire/recurring/trigger"); - options.IgnoredUrls.Add("/cap"); - options.IgnoredUrls.Add("/"); - }); - } - - private void ConfigurationMultiTenancy() - { - Configure(options => { options.IsEnabled = MultiTenancyConsts.IsEnabled; }); - } - - /// - /// 配置redis分布式锁 - /// - private void ConfigurationDistributedLocking(ServiceConfigurationContext context) - { - var configuration = context.Services.GetConfiguration(); - var connectionString = configuration.GetValue("Redis:Configuration"); - context.Services.AddSingleton(sp => - { - var connection = ConnectionMultiplexer.Connect(connectionString); - return new RedisDistributedSynchronizationProvider(connection.GetDatabase()); - }); - } - - /// - /// 配置blob设置 - /// - private void ConfigureBlobStorage() - { - Configure(options => - { - options.Containers.ConfigureDefault(container => - { - container.UseFileSystem(fileSystem => - { - fileSystem.BasePath = "C:\\my-files"; - }); - }); - }); - } -} \ No newline at end of file diff --git a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.cs b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.cs index c9a56ca8..c21925b3 100644 --- a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.cs +++ b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/AbpProHttpApiHostModule.cs @@ -1,12 +1,8 @@ -using Lion.AbpPro.Starter; -using Volo.Abp.BlobStoring.FileSystem; -using Volo.Abp.DistributedLocking; - namespace Lion.AbpPro { [DependsOn( typeof(AbpProHttpApiModule), - typeof(AbpProSharedHostingMicroserviceModule), + typeof(AbpProAspNetCoreModule), typeof(AbpAspNetCoreMvcUiMultiTenancyModule), typeof(AbpProEntityFrameworkCoreModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule), @@ -33,55 +29,102 @@ namespace Lion.AbpPro public override void ConfigureServices(ServiceConfigurationContext context) { - var configuration = context.Services.GetConfiguration(); - ConfigureCache(context); - ConfigurationDistributedLocking(context); - ConfigureSwaggerServices(context); - ConfigureJwtAuthentication(context, configuration); - //ConfigureHangfire(context); - ConfigureMiniProfiler(context); - ConfigureIdentity(context); - //ConfigureCap(context); - ConfigureAuditLog(context); - ConfigurationSignalR(context); - ConfigurationMultiTenancy(); - ConfigureBlobStorage(); + context.Services + + .AddAbpProAuditLog() + .AddAbpProAuthentication() + .AddAbpProMultiTenancy() + .AddAbpProRedis() + .AddAbpProRedisDistributedLocking() + .AddAbpProMiniProfiler() + .AddAbpProCors() + .AddAbpProAntiForgery() + .AddAbpProIdentity() + .AddAbpProBlobStorage() + .AddAbpProSignalR() + .AddAbpProHealthChecks() + .AddAbpProTenantResolvers() + .AddAbpProLocalization() + .AddAbpProExceptions() + .AddAbpProSwagger("AbpPro"); + + + // //ConfigureCache(context); + // context.Services.AddAbpProRedis(); + // + // //ConfigurationDistributedLocking(context); + // context.Services.AddAbpProRedisDistributedLocking(); + // + // + // //ConfigureSwaggerServices(context); + // context.Services.AddAbpProSwagger("AbpPro"); + // + // //ConfigureJwtAuthentication(context, configuration); + // context.Services.AddAbpProAuthentication(); + // + // //ConfigureHangfire(context); + // + // //ConfigureMiniProfiler(context); + // context.Services.AddAbpProMiniProfiler(); + // + // //ConfigureIdentity(context); + // context.Services.AddAbpProIdentity(); + // + // //ConfigureCap(context); + // + // //ConfigureAuditLog(context); + // context.Services.AddAbpProAuditLog(); + // + // //ConfigurationSignalR(context); + // context.Services.AddAbpProSignalR(); + // + // //ConfigurationMultiTenancy(); + // context.Services.AddAbpProMultiTenancy(); + // + // //ConfigureBlobStorage(); + // context.Services.AddAbpProBlobStorage(); } public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); - var configuration = context.GetConfiguration(); + //var configuration = context.GetConfiguration(); app.UseAbpProRequestLocalization(); app.UseCorrelationId(); app.MapAbpStaticAssets(); - if (configuration.GetValue("MiniProfiler:Enabled", false)) - { - app.UseMiniProfiler(); - } + // if (configuration.GetValue("MiniProfiler:Enabled", false)) + // { + // app.UseMiniProfiler(); + // } + app.UseAbpProMiniProfiler(); app.UseRouting(); - app.UseCors(AbpProHttpApiHostConst.DefaultCorsPolicyName); + //app.UseCors(AbpProHttpApiHostConst.DefaultCorsPolicyName); + app.UseAbpProCors(); app.UseAuthentication(); - if (MultiTenancyConsts.IsEnabled) - { - app.UseMultiTenancy(); - } + // if (MultiTenancyConsts.IsEnabled) + // { + // app.UseMultiTenancy(); + // } + + app.UseAbpProMultiTenancy(); app.UseAuthorization(); - app.UseSwagger(); - app.UseAbpSwaggerUI(options => - { - options.SwaggerEndpoint("/swagger/AbpPro/swagger.json", "AbpPro API"); - options.DocExpansion(DocExpansion.None); - options.DefaultModelsExpandDepth(-1); - }); + // app.UseSwagger(); + // app.UseAbpSwaggerUI(options => + // { + // options.SwaggerEndpoint("/swagger/AbpPro/swagger.json", "AbpPro API"); + // options.DocExpansion(DocExpansion.None); + // options.DefaultModelsExpandDepth(-1); + // }); - app.UseAuditing(); + app.UseAbpProSwaggerUI("/swagger/AbpPro/swagger.json","AbpPro"); + //app.UseAuditing(); + app.UseAbpProAuditing(); + app.UseAbpSerilogEnrichers(); app.UseUnitOfWork(); - app.UseConfiguredEndpoints(endpoints => { endpoints.MapHealthChecks("/health"); @@ -94,10 +137,7 @@ namespace Lion.AbpPro }); - if (configuration.GetValue("Consul:Enabled", false)) - { - app.UseConsul(); - } + app.UseAbpProConsul(); } } } \ No newline at end of file diff --git a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/GlobalUsings.cs b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/GlobalUsings.cs index 0261428a..d9c3fe10 100644 --- a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/GlobalUsings.cs +++ b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/GlobalUsings.cs @@ -7,6 +7,7 @@ global using System.Linq; global using System.Text; global using System.Text.RegularExpressions; global using System.Threading.Tasks; +global using Consul; global using Hangfire; global using Hangfire.Common; global using Hangfire.Dashboard; @@ -14,6 +15,8 @@ global using Hangfire.Redis; global using Hangfire.Redis.StackExchange; global using Hangfire.States; global using Hangfire.Storage; +global using Lion.AbpPro.AspNetCore; +global using Lion.AbpPro.AspNetCore.Options; global using Lion.AbpPro.CAP; global using Lion.AbpPro.CAP.EntityFrameworkCore; global using Lion.AbpPro.EntityFrameworkCore; @@ -21,8 +24,11 @@ global using Lion.AbpPro.Core; global using Lion.AbpPro.Extensions; global using Lion.AbpPro.Extensions.Hangfire; global using Lion.AbpPro.MultiTenancy; +global using Lion.AbpPro.Starter; global using Magicodes.ExporterAndImporter.Core; global using Magicodes.ExporterAndImporter.Excel; +global using Medallion.Threading; +global using Medallion.Threading.Redis; global using Microsoft.AspNetCore.Authentication.JwtBearer; global using Microsoft.AspNetCore.Builder; global using Microsoft.AspNetCore.DataProtection; @@ -51,7 +57,9 @@ global using Volo.Abp.Account.Web; global using Volo.Abp.AspNetCore.Auditing; global using Volo.Abp.AspNetCore.Authentication.JwtBearer; global using Volo.Abp.AspNetCore.ExceptionHandling; +global using Volo.Abp.AspNetCore.MultiTenancy; global using Volo.Abp.AspNetCore.Mvc; +global using Volo.Abp.AspNetCore.Mvc.AntiForgery; global using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; global using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; global using Volo.Abp.AspNetCore.Serilog; @@ -59,13 +67,17 @@ global using Volo.Abp.Auditing; global using Volo.Abp.Authorization; global using Volo.Abp.BackgroundJobs; global using Volo.Abp.BackgroundJobs.Hangfire; +global using Volo.Abp.BlobStoring; +global using Volo.Abp.BlobStoring.FileSystem; global using Volo.Abp.Caching; global using Volo.Abp.Caching.StackExchangeRedis; global using Volo.Abp.DependencyInjection; +global using Volo.Abp.DistributedLocking; global using Volo.Abp.Domain.Entities; global using Volo.Abp.ExceptionHandling; global using Volo.Abp.Http; global using Volo.Abp.Json; +global using Volo.Abp.Localization; global using Volo.Abp.Modularity; global using Volo.Abp.MultiTenancy; global using Volo.Abp.Users; diff --git a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Lion.AbpPro.HttpApi.Host.csproj b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Lion.AbpPro.HttpApi.Host.csproj index 516d9e3b..3d0c5e8a 100644 --- a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Lion.AbpPro.HttpApi.Host.csproj +++ b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Lion.AbpPro.HttpApi.Host.csproj @@ -44,10 +44,10 @@ + - diff --git a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Microsoft/Extensions/DependencyInjection/ServiceCollectionExtensions.cs b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Microsoft/Extensions/DependencyInjection/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..81051bd8 --- /dev/null +++ b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/Microsoft/Extensions/DependencyInjection/ServiceCollectionExtensions.cs @@ -0,0 +1,113 @@ +#pragma warning disable CS0618 // Type or member is obsolete + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + /// + /// 注册Redis缓存 + /// + public static IServiceCollection AddAbpProRedis(this IServiceCollection service) + { + service.Configure(options => { options.KeyPrefix = "AbpPro:"; }); + var configuration = service.GetConfiguration(); + var redis = ConnectionMultiplexer.Connect(configuration.GetValue("Redis:Configuration")); + service + .AddDataProtection() + .PersistKeysToStackExchangeRedis(redis, "AbpPro-Protection-Keys"); + return service; + } + + /// + /// 注册redis分布式锁 + /// + public static IServiceCollection AddAbpProRedisDistributedLocking(this IServiceCollection service) + { + var configuration = service.GetConfiguration(); + var connectionString = configuration.GetValue("Redis:Configuration"); + service.AddSingleton(sp => + { + var connection = ConnectionMultiplexer.Connect(connectionString); + return new RedisDistributedSynchronizationProvider(connection.GetDatabase()); + }); + return service; + } + + /// + /// 注册Identity + /// + public static IServiceCollection AddAbpProIdentity(this IServiceCollection service) + { + service.Configure(options => { options.Lockout = new LockoutOptions() { AllowedForNewUsers = false }; }); + return service; + } + + /// + /// 注册SignalR + /// + public static IServiceCollection AddAbpProSignalR(this IServiceCollection service) + { + service + .AddSignalR() + .AddStackExchangeRedis(service.GetConfiguration().GetValue("Redis:Configuration"), + options => { options.Configuration.ChannelPrefix = "Lion.AbpPro"; }); + return service; + } + + /// + /// 注册blob设置 + /// + public static IServiceCollection AddAbpProBlobStorage(this IServiceCollection service) + { + service.Configure(options => { options.Containers.ConfigureDefault(container => { container.UseFileSystem(fileSystem => { fileSystem.BasePath = "C:\\my-files"; }); }); }); + return service; + } + + /// + /// 注册cap + /// + public static IServiceCollection AddAbpProCap(this IServiceCollection service) + { + var configuration = service.GetConfiguration(); + service.AddAbpCap(capOptions => + { + capOptions.SetCapDbConnectionString(configuration["ConnectionStrings:Default"]); + capOptions.UseEntityFramework(); + capOptions.UseRabbitMQ(option => + { + option.HostName = configuration.GetValue("Cap:RabbitMq:HostName"); + option.UserName = configuration.GetValue("Cap:RabbitMq:UserName"); + option.Password = configuration.GetValue("Cap:RabbitMq:Password"); + option.Port = configuration.GetValue("Cap:RabbitMq:Port"); + }); + capOptions.UseDashboard(options => { options.AuthorizationPolicy = AbpProCapPermissions.CapManagement.Cap; }); + }); + return service; + } + + /// + /// 注册hangfire + /// + public static IServiceCollection AddAbpProHangfire(this IServiceCollection service) + { + var redisStorageOptions = new RedisStorageOptions() + { + Db = service.GetConfiguration().GetValue("Hangfire:Redis:DB") + }; + + service.Configure(options => { options.IsJobExecutionEnabled = true; }); + + service.AddHangfire(config => + { + config.UseRedisStorage( + service.GetConfiguration().GetValue("Hangfire:Redis:Host"), redisStorageOptions) + .WithJobExpirationTimeout(TimeSpan.FromDays(7)); + var delaysInSeconds = new[] { 10, 60, 60 * 3 }; // 重试时间间隔 + const int attempts = 3; // 重试次数 + config.UseFilter(new AutomaticRetryAttribute() { Attempts = 3, DelaysInSeconds = delaysInSeconds }); + //config.UseFilter(new AutoDeleteAfterSuccessAttribute(TimeSpan.FromDays(7))); + config.UseFilter(new JobRetryLastFilter(attempts)); + }); + return service; + } +} \ No newline at end of file diff --git a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/appsettings.json b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/appsettings.json index 531a631e..10bb14d3 100644 --- a/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/appsettings.json +++ b/aspnet-core/services/host/Lion.AbpPro.HttpApi.Host/appsettings.json @@ -38,12 +38,12 @@ }, "Hangfire": { "Redis": { - "Host": "localhost:6379,password=1q2w3E*", + "Host": "117.72.203.231:6379,password=1q2w3E*", "DB": "2" } }, "Redis": { - "Configuration": "localhost:6379,password=1q2w3E*,defaultdatabase=9" + "Configuration": "117.72.203.231:6379,password=75He82bB5jFA84XZ1,defaultdatabase=2" }, "Jwt": { "Audience": "Lion.AbpPro", @@ -67,14 +67,27 @@ "Password": "aVVhjQ95RP7nbwNy", "SearchIndexFormat": "Lion.AbpPro.development*" }, - "Consul": { - "Enabled": false, - "Host": "http://localhost:8500", - "Service": "LionAbpPro-Service" - }, "MiniProfiler": { + "Enabled": true, + "RouteBasePath": "profiler" + }, + "Swagger": { + "Enabled": true + }, + "Audit": { + "Enabled": true, + "ApplicationName": "Lion.AbpPro" + }, + "Cors": { + "Enabled": true, + "CorsOrigins": "http://localhost:4200,http://localhost:4201" + }, + "Gateway": { "Enabled": false }, + "MultiTenancy": { + "Enabled": true + }, "Preheat": { "Enabled": true, "RequestUrl": "http://localhost:44315/api/abp/application-configuration?IncludeLocalizationResources=false" diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Gateways/GlobalUsings.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Gateways/GlobalUsings.cs deleted file mode 100644 index 155d071b..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Gateways/GlobalUsings.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Global using directives - -global using Microsoft.Extensions.DependencyInjection; -global using Ocelot.DependencyInjection; -global using Ocelot.Provider.Consul; -global using Ocelot.Provider.Polly; -global using Volo.Abp.Autofac; -global using Volo.Abp.Modularity; -global using Volo.Abp.Swashbuckle; \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Gateways/Lion.AbpPro.Shared.Hosting.Gateways.csproj b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Gateways/Lion.AbpPro.Shared.Hosting.Gateways.csproj deleted file mode 100644 index 791a51d7..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Gateways/Lion.AbpPro.Shared.Hosting.Gateways.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - net9.0 - - - - - - - - - - - - - - - - - diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Gateways/Lion/AbpPro/AbpProSharedHostingGatewayModule.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Gateways/Lion/AbpPro/AbpProSharedHostingGatewayModule.cs deleted file mode 100644 index e1c8c5f2..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Gateways/Lion/AbpPro/AbpProSharedHostingGatewayModule.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Lion.AbpPro -{ - [DependsOn( - typeof(AbpSwashbuckleModule), - typeof(AbpAutofacModule))] - public class AbpProSharedHostingGatewayModule : AbpModule - { - - public override void ConfigureServices(ServiceConfigurationContext context) - { - ConfigureOcelot(context); - ConfigureHealthChecks(context); - } - - /// - /// Ocelot配置 - /// - private static void ConfigureOcelot(ServiceConfigurationContext context) - { - var configuration = context.Services.GetConfiguration(); - context.Services.AddOcelot(configuration).AddConsul().AddPolly(); - } - /// - /// 健康检查 - /// - /// - private void ConfigureHealthChecks(ServiceConfigurationContext context) - { - context.Services.AddHealthChecks(); - } - } -} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion/AbpPro/AbpProSharedHostingMicroserviceModule.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion/AbpPro/AbpProSharedHostingMicroserviceModule.cs deleted file mode 100644 index 87887ec8..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Lion/AbpPro/AbpProSharedHostingMicroserviceModule.cs +++ /dev/null @@ -1,140 +0,0 @@ -using Microsoft.AspNetCore.DataProtection; -using StackExchange.Redis; -using Volo.Abp.AspNetCore.MultiTenancy; -using Volo.Abp.Caching; -using Volo.Abp.MultiTenancy; -using Volo.Abp.Settings; - -namespace Lion.AbpPro; - -[DependsOn( - typeof(AbpSwashbuckleModule), - typeof(AbpAutofacModule), - typeof(AbpProCoreModule))] -public class AbpProSharedHostingMicroserviceModule : AbpModule -{ - private const string DefaultCorsPolicyName = "Default"; - - public override void ConfigureServices(ServiceConfigurationContext context) - { - var configuration = context.Services.GetConfiguration(); - context.Services.AddConsulConfig(configuration); - ConfigureHealthChecks(context); - ConfigureLocalization(); - ConfigureCors(context); - ConfigureConsul(context, configuration); - ConfigAntiForgery(); - ConfigureAbpExceptions(context); - ConfigureTenantResolvers(); - } - - /// - /// 异常处理 - /// - private void ConfigureAbpExceptions(ServiceConfigurationContext context) - { - context.Services.AddMvc - ( - options => - { - options.Filters.Add(typeof(AbpProExceptionFilter)); - options.Filters.Add(typeof(AbpProResultFilter)); - } - ); - } - - /// - /// 阻止跨站点请求伪造 - /// https://docs.microsoft.com/zh-cn/aspnet/core/security/anti-request-forgery?view=aspnetcore-6.0 - /// - private void ConfigAntiForgery() - { - Configure(options => { options.AutoValidate = false; }); - } - - private void ConfigureConsul(ServiceConfigurationContext context, IConfiguration configuration) - { - if (configuration.GetValue("Consul:Enabled", false)) - { - context.Services.AddConsulConfig(configuration); - } - } - - - /// - /// 配置跨域 - /// - private void ConfigureCors(ServiceConfigurationContext context) - { - var configuration = context.Services.GetConfiguration(); - context.Services.AddCors(options => - { - options.AddPolicy(DefaultCorsPolicyName, builder => - { - builder - .WithOrigins( - configuration["App:CorsOrigins"] - .Split(",", StringSplitOptions.RemoveEmptyEntries) - .Select(o => o.RemovePostFix("/")) - .ToArray() - ) - //.WithAbpExposedHeaders() - .SetIsOriginAllowedToAllowWildcardSubdomains() - .AllowAnyHeader() - .AllowAnyMethod() - //.AllowCredentials() - // https://www.cnblogs.com/JulianHuang/p/14225515.html - // https://learn.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-7.0 - .SetPreflightMaxAge((TimeSpan.FromHours(24))); - }); - }); - } - - - /// - /// 多语言配置 - /// - private void ConfigureLocalization() - { - Configure(options => - { - options.Languages.Add(new LanguageInfo("ar", "ar", "العربية")); - options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština")); - options.Languages.Add(new LanguageInfo("en", "en", "English")); - options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)")); - options.Languages.Add(new LanguageInfo("fr", "fr", "Français")); - options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar")); - options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português")); - options.Languages.Add(new LanguageInfo("ru", "ru", "Русский")); - options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe")); - options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); - options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文")); - }); - } - - /// - /// 健康检查 - /// - private void ConfigureHealthChecks(ServiceConfigurationContext context) - { - // TODO 检查数据库和redis是否正常 AspNetCore.HealthChecks.Redis AspNetCore.HealthChecks.MySql - // context.Services.AddHealthChecks().AddRedis(redisConnectionString).AddMySql(connectString); - context.Services.AddHealthChecks(); - } - - /// - /// 配置租户解析 - /// - private void ConfigureTenantResolvers() - { - Configure(options => - { - options.TenantResolvers.Clear(); - // 只保留通过请求头解析租户 - // options.TenantResolvers.Add(new QueryStringTenantResolveContributor()); - // options.TenantResolvers.Add(new RouteTenantResolveContributor()); - options.TenantResolvers.Add(new HeaderTenantResolveContributor()); - // options.TenantResolvers.Add(new CookieTenantResolveContributor()); - }); - } -} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Builder/ApplicationBuilderExtensions.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Builder/ApplicationBuilderExtensions.cs deleted file mode 100644 index d5146536..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Builder/ApplicationBuilderExtensions.cs +++ /dev/null @@ -1,79 +0,0 @@ -using Microsoft.AspNetCore.RequestLog; - -namespace Microsoft.AspNetCore.Builder -{ - public static class ApplicationBuilderExtensions - { - public static string UseConsul(this IApplicationBuilder app) - { - var appLifetime = app.ApplicationServices.GetService(); - using var scope = app.ApplicationServices.CreateScope(); - var configuration = scope.ServiceProvider.GetService(); - - bool isEnabled = configuration.GetValue("Consul:Enabled"); - string serviceName = configuration.GetValue("Consul:Service"); - var appString = configuration.GetValue("App:SelfUrl"); - Uri appUrl = new Uri(appString, UriKind.Absolute); - - if (!isEnabled) - return String.Empty; - - Guid serviceId = Guid.NewGuid(); - string consulServiceId = $"{serviceName}:{serviceId}"; - - var client = scope.ServiceProvider.GetService(); - - var consulServiceRegistration = new AgentServiceRegistration - { - Name = serviceName, - ID = consulServiceId, - Address = appUrl.Host, - Port = appUrl.Port, - Check = new AgentServiceCheck - { - DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), //服务停止多久后注销 - Interval = TimeSpan.FromSeconds(3), //健康检查时间间隔,或者称为心跳 间隔 - HTTP = $"http://{appUrl.Host}:{appUrl.Port}/health", //健康检查地址 - Timeout = TimeSpan.FromSeconds(15) //超时时间 - } - }; - - client.Agent.ServiceRegister(consulServiceRegistration); - appLifetime.ApplicationStopping.Register(() => { client.Agent.ServiceDeregister(consulServiceRegistration.ID); }); - - return consulServiceId; - } - - /// - /// 记录请求响应日志 - /// - /// - public static IApplicationBuilder UseRequestLog(this IApplicationBuilder app) - { - return app.UseMiddleware(); - } - - /// - /// 多语言中间件 - /// 浏览器传递的请求头:Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6而abp钟简体中文为:zh-Hans - /// - /// app.UseAbpProRequestLocalization(); - /// - /// - public static IApplicationBuilder UseAbpProRequestLocalization(this IApplicationBuilder app) - { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - return app.UseAbpRequestLocalization(options => - { - // 移除自带header解析器 - options.RequestCultureProviders.RemoveAll(provider=> provider is AcceptLanguageHeaderRequestCultureProvider); - // 添加header解析器 - options.RequestCultureProviders.Add(new AbpProAcceptLanguageHeaderRequestCultureProvider()); - }); - } - } -} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Mvc/Filters/AbpProResultFilter.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Mvc/Filters/AbpProResultFilter.cs deleted file mode 100644 index aa30cf38..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/Mvc/Filters/AbpProResultFilter.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Text.Json; - -namespace Microsoft.AspNetCore.Mvc.Filters; - -public class AbpProResultFilter : IResultFilter, ITransientDependency -{ - public void OnResultExecuting(ResultExecutingContext context) - { - // 如果是page 直接return - if (context.ActionDescriptor.IsPageAction()) return; - - var controllerHasDontWrapResultAttribute = - context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.GetCustomAttributes(typeof(WrapResultAttribute), true).Any(); - var controllerActionHasDontWrapResultAttribute = context.ActionDescriptor.GetMethodInfo().GetCustomAttributes(typeof(WrapResultAttribute), true).Any(); - if (controllerHasDontWrapResultAttribute || controllerActionHasDontWrapResultAttribute) - { - context.HttpContext.Response.StatusCode = 200; - var result = new WrapResult(); - if (context.Result is not EmptyResult) - { - result.SetSuccess(((ObjectResult)context.Result).Value); - } - - var jsonSerializer = context.GetService(); - - context.Result = new ContentResult() - { - StatusCode = (int)HttpStatusCode.OK, - ContentType = "application/json;charset=utf-8", - Content = jsonSerializer.Serialize(result) - }; - } - } - - public void OnResultExecuted(ResultExecutedContext context) - { - } -} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/RequestLog/RequestLogMiddleware.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/RequestLog/RequestLogMiddleware.cs deleted file mode 100644 index 5f2f7779..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/AspNetCore/RequestLog/RequestLogMiddleware.cs +++ /dev/null @@ -1,77 +0,0 @@ -namespace Microsoft.AspNetCore.RequestLog; - -public class RequestLogMiddleware -{ - private readonly RequestDelegate _next; - private readonly ILogger _logger; - - public RequestLogMiddleware(RequestDelegate next, - ILogger logger) - { - _next = next; - _logger = logger; - } - - public async Task InvokeAsync(HttpContext context) - { - context.Request.EnableBuffering(); - var originalBody = context.Response.Body; - if (context.Request.Path.ToString().ToLower().Contains("swagger") - || context.Request.Path.ToString().ToLower().Contains("login") - || context.Request.Path.ToString().ToLower().Contains("monitor") - || context.Request.Path.ToString().ToLower().Contains("cap") - || context.Request.Path.ToString().ToLower().Contains("hangfire") - || context.Request.Path.ToString() == "/" - ) - { - await _next(context); - } - else - { - try - { - var logRequestId = Guid.NewGuid().ToString(); - await RequestDataLog(context, logRequestId); - using (var ms = new MemoryStream()) - { - context.Response.Body = ms; - await _next(context); - ResponseDataLog(ms, logRequestId); - ms.Position = 0; - await ms.CopyToAsync(originalBody); - } - } - catch (Exception ex) - { - // 记录异常 - _logger.LogError(ex.Message + "" + ex.InnerException); - } - finally - { - context.Response.Body = originalBody; - } - } - } - - private async Task RequestDataLog(HttpContext context, - string requestId) - { - var request = context.Request; - var body = new StreamReader(request.Body); - var requestData = $" 请求路径:{request.Path}\r\n 请求Body参数:{await body.ReadToEndAsync()}"; - _logger.LogInformation($"日志中间件[Request],LogRequestId:{requestId}:请求接口信息:{requestData}"); - request.Body.Position = 0; - } - - private void ResponseDataLog(MemoryStream ms, string requestId) - { - ms.Position = 0; - var responseBody = new StreamReader(ms).ReadToEnd(); - // 去除 Html - var isHtml = Regex.IsMatch(responseBody, "<[^>]+>"); - if (!isHtml && !string.IsNullOrEmpty(responseBody)) - { - _logger.LogInformation($"日志中间件[Response],LogRequestId:{requestId}:响应接口信息:{responseBody}"); - } - } -} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/Extensions/DependencyInjection/ServiceCollectionExtensions.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/Extensions/DependencyInjection/ServiceCollectionExtensions.cs deleted file mode 100644 index 66533c21..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Microsoft/Extensions/DependencyInjection/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Microsoft.Extensions.DependencyInjection -{ - public static class ServiceCollectionExtensions - { - public static IServiceCollection AddConsulConfig(this IServiceCollection services, IConfiguration configuration) - { - services.AddSingleton(p => new ConsulClient(consulConfig => - { - var address = configuration.GetValue("Consul:Host"); - consulConfig.Address = new Uri(address); - })); - return services; - } - } -} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Serilog/SerilogToEsExtensions.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Serilog/SerilogToEsExtensions.cs deleted file mode 100644 index 97a31646..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Serilog/SerilogToEsExtensions.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace Serilog -{ - [SuppressMessage("Reliability", "CA2022:避免使用 \"Stream.Read\" 进行不准确读取")] - public static class SerilogToEsExtensions - { - public static void SetSerilogConfiguration(LoggerConfiguration loggerConfiguration, IConfiguration configuration) - { - // 默认读取 configuration 中 "Serilog" 节点下的配置 - loggerConfiguration - .ReadFrom.Configuration(configuration) - .Enrich.FromLogContext(); - - var writeToElasticSearch = configuration.GetValue("ElasticSearch:Enabled", false); - - - // LogToElasticSearch:Enabled = true 才输出至ES - if (!writeToElasticSearch) - return; - - var applicationName = "Lion.AbpPro.HttpApi.Host"; - - var esUrl = configuration["ElasticSearch:Url"]; - // 需要设置ES URL - if (string.IsNullOrEmpty(esUrl)) - return; - - - var indexFormat = configuration["ElasticSearch:IndexFormat"]; - - // 需要设置ES URL - if (string.IsNullOrEmpty(indexFormat)) - return; - - var esUserName = configuration["ElasticSearch:UserName"]; - var esPassword = configuration["ElasticSearch:Password"]; - - loggerConfiguration.Enrich.FromLogContext().Enrich.WithExceptionDetails().WriteTo - .Elasticsearch(BuildElasticSearchSinkOptions(esUrl, indexFormat, esUserName, esPassword)); - loggerConfiguration.Enrich.WithProperty("Application", applicationName); - } - - // 创建Es连接 - private static ElasticsearchSinkOptions BuildElasticSearchSinkOptions( - string url, - string indexFormat, - string userName, - string password) - { - if (string.IsNullOrEmpty(userName)) - { - return new ElasticsearchSinkOptions(new Uri(url)) - { - AutoRegisterTemplate = true, - AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, - IndexFormat = indexFormat - }; - } - - return new ElasticsearchSinkOptions(new Uri(url)) - { - AutoRegisterTemplate = true, - AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv7, - IndexFormat = indexFormat, - ModifyConnectionSettings = x => x.BasicAuthentication(userName, password) - }; - } - - public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext) - { - var request = httpContext.Request; - - // 为每个请求都设置通用的属性 - diagnosticContext.Set("Host", request.Host); - diagnosticContext.Set("Protocol", request.Protocol); - diagnosticContext.Set("Scheme", request.Scheme); - diagnosticContext.Set("RemoteIpAddress", httpContext.Connection.RemoteIpAddress); - // 如果要记录 Request Body 或 Response Body - // 参考 https://stackoverflow.com/questions/60076922/serilog-logging-web-api-methods-adding-context-properties-inside-middleware - string requestBody = ReadRequestBody(httpContext.Request).Result; - if (!string.IsNullOrEmpty(requestBody)) - { - diagnosticContext.Set("RequestBody", requestBody); - } - - // string responseBody = ReadResponseBody(httpContext.Response).Result; - // if (!string.IsNullOrEmpty(responseBody)) - // { - // diagnosticContext.Set("ResponseBody", requestBody); - // } - - if (request.QueryString.HasValue) - { - diagnosticContext.Set("QueryString", request.QueryString.Value); - } - } - - private static async Task ReadRequestBody(HttpRequest request) - { - HttpRequestRewindExtensions.EnableBuffering(request); - - var body = request.Body; - var buffer = new byte[Convert.ToInt32(request.ContentLength)]; - await request.Body.ReadAsync(buffer, 0, buffer.Length); - string requestBody = Encoding.UTF8.GetString(buffer); - body.Seek(0, SeekOrigin.Begin); - request.Body = body; - - return $"{requestBody}"; - } - - private static async Task ReadResponseBody(HttpResponse response) - { - response.Body.Seek(0, SeekOrigin.Begin); - string responseBody = await new StreamReader(response.Body).ReadToEndAsync(); - response.Body.Seek(0, SeekOrigin.Begin); - - return $"{responseBody}"; - } - } -} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Swagger/HiddenAbpDefaultApiFilter.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Swagger/HiddenAbpDefaultApiFilter.cs deleted file mode 100644 index 34110bd4..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Swagger/HiddenAbpDefaultApiFilter.cs +++ /dev/null @@ -1,49 +0,0 @@ -namespace Swagger -{ - /// - /// 在使用nswag的时候,原生默认的api导致生产的代理类存在问题 - /// 所有隐藏原生的api,重写路由 - /// - public class HiddenAbpDefaultApiFilter : IDocumentFilter - { - public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) - { - foreach (ApiDescription apiDescription in context.ApiDescriptions) - { - if (apiDescription.TryGetMethodInfo(out MethodInfo method)) - { - string key = "/" + apiDescription.RelativePath; - var reuslt = IsHidden(key); - if (reuslt) swaggerDoc.Paths.Remove(key); - } - } - } - - private bool IsHidden(string key) - { - var list = GetHiddenAbpDefaultApiList(); - foreach (var item in list) - { - if (key.Contains(item)) return true; - } - - return false; - } - - private List GetHiddenAbpDefaultApiList() - { - return new List() { - "/api/abp/multi-tenancy/tenants", - "/api/account", - "/api/feature-management/features", - "/api/permission-management/permissions", - "/api/identity/my-profile", - "/api/identity", - "/api/multi-tenancy/tenants", - "/api/setting-management/emailing", - "/configuration", - "/outputcache" - }; - } - } -} \ No newline at end of file diff --git a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Volo/Abp/DefaultHttpExceptionStatusCodeFinder.cs b/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Volo/Abp/DefaultHttpExceptionStatusCodeFinder.cs deleted file mode 100644 index 9b0c4e54..00000000 --- a/aspnet-core/shared/Lion.AbpPro.Shared.Hosting.Microservices/Volo/Abp/DefaultHttpExceptionStatusCodeFinder.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace Volo.Abp -{ - /// - /// 修改Abp 返回状态码 - /// 原因: 抛出BusinessException异常 不应该抛403异常 - /// - public class DefaultHttpExceptionStatusCodeFinder : IHttpExceptionStatusCodeFinder, ITransientDependency - { - protected AbpExceptionHttpStatusCodeOptions Options { get; } - - public DefaultHttpExceptionStatusCodeFinder( - IOptions options) - { - Options = options.Value; - } - - public HttpStatusCode GetStatusCode(HttpContext httpContext, Exception exception) - { - if (exception is IHasHttpStatusCode exceptionWithHttpStatusCode && - exceptionWithHttpStatusCode.HttpStatusCode > 0) - { - return (HttpStatusCode)exceptionWithHttpStatusCode.HttpStatusCode; - } - - if (exception is IHasErrorCode exceptionWithErrorCode && - !exceptionWithErrorCode.Code.IsNullOrWhiteSpace()) - { - if (Options.ErrorCodeToHttpStatusCodeMappings.TryGetValue(exceptionWithErrorCode.Code, out var status)) - { - return status; - } - } - - if (exception is AbpAuthorizationException) - { - return HttpStatusCode.Forbidden; - } - - //TODO: Handle SecurityException..? - - if (exception is AbpValidationException) - { - return HttpStatusCode.BadRequest; - } - - if (exception is EntityNotFoundException) - { - return HttpStatusCode.NotFound; - } - - if (exception is NotImplementedException) - { - return HttpStatusCode.NotImplemented; - } - - if (exception is IBusinessException) - { - return HttpStatusCode.InternalServerError; - } - - return HttpStatusCode.InternalServerError; - } - } -} \ No newline at end of file