using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CompanyName.ProjectName.ConfigurationOptions;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using CompanyName.ProjectName.EntityFrameworkCore;
using CompanyName.ProjectName.Extensions.Filters;
using CompanyNameProjectName.Extensions.Filters;
using Hangfire;
using Hangfire.MySql;
using Microsoft.IdentityModel.Tokens;
using StackExchange.Redis;
using Microsoft.OpenApi.Models;
using Volo.Abp;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.Autofac;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.BackgroundJobs.Hangfire;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;
using Volo.Abp.VirtualFileSystem;
using System.Threading.Tasks;
using CompanyName.ProjectName.CAP;
using CompanyName.ProjectName.Extensions;
using CompanyName.ProjectName.Extensions.Customs.Http;
using CompanyName.ProjectName.MultiTenancy;
using Savorboard.CAP.InMemoryMessageQueue;
using Serilog;
using Swashbuckle.AspNetCore.SwaggerUI;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.MultiTenancy;
namespace CompanyName.ProjectName
{
[DependsOn(
typeof(ProjectNameHttpApiModule),
typeof(AbpAutofacModule),
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpAspNetCoreMvcUiMultiTenancyModule),
typeof(ProjectNameApplicationModule),
typeof(ProjectNameEntityFrameworkCoreDbMigrationsModule),
typeof(AbpAspNetCoreSerilogModule),
typeof(AbpSwashbuckleModule),
typeof(AbpAccountWebModule),
typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(AbpBackgroundJobsHangfireModule),
typeof(AbpCapModule),
typeof(AbpAspNetCoreMultiTenancyModule)
)]
public class ProjectNameHttpApiHostModule : AbpModule
{
private const string DefaultCorsPolicyName = "Default";
public override void OnPostApplicationInitialization(ApplicationInitializationContext context)
{
// context.CreateRecurringJob();
base.OnPostApplicationInitialization(context);
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment();
//ConfigureConventionalControllers();
//ConfigureAuthentication(context, configuration);
ConfigureLocalization();
ConfigureCache(context);
ConfigureVirtualFileSystem(context);
ConfigureCors(context, configuration);
ConfigureSwaggerServices(context, configuration);
ConfigureOptions(context);
ConfigureHealthChecks(context);
ConfigureJwtAuthentication(context, configuration);
ConfigureHangfireMysql(context);
ConfigurationCap(context);
ConfigurationStsHttpClient(context);
ConfigureAbpExceptions(context);
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
app.UseAbpRequestLocalization();
app.UseCorrelationId();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(DefaultCorsPolicyName);
app.UseAuthentication();
if (MultiTenancyConsts.IsEnabled)
{
app.UseMultiTenancy();
}
app.UseAuthorization();
app.UseSwagger();
app.UseAbpSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "ProjectName API");
options.DocExpansion(DocExpansion.None);
options.DefaultModelsExpandDepth(-1);
});
app.UseAuditing();
app.UseAbpSerilogEnrichers();
app.UseSerilogRequestLogging(opts => { opts.EnrichDiagnosticContext = SerilogToEsExtensions.EnrichFromRequest; });
app.UseUnitOfWork();
app.UseConfiguredEndpoints();
app.UseEndpoints(endpoints => { endpoints.MapHealthChecks("/health"); });
app.UseHangfireDashboard("/hangfire", new DashboardOptions()
{
Authorization = new[] {new CustomHangfireAuthorizeFilter()},
IgnoreAntiforgeryToken = true
});
}
///
/// 异常处理
///
///
private void ConfigureAbpExceptions(ServiceConfigurationContext context)
{
context.Services.Configure(options => { options.SendExceptionsDetailsToClients = true; });
}
public void ConfigureHangfireMysql(ServiceConfigurationContext context)
{
Configure(options => { options.IsJobExecutionEnabled = true; });
context.Services.AddHangfire(config =>
{
config.UseStorage(new MySqlStorage(context.Services.GetConfiguration().GetConnectionString("Default"),
new MySqlStorageOptions()
{
//CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
//SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
//QueuePollInterval = TimeSpan.Zero,
//UseRecommendedIsolationLevel = true,
//DisableGlobalLocks = true
}));
});
}
///
/// 配置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 Microsoft.IdentityModel.Tokens.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 accessToken = currentContext.Request.Query["access_token"];
// 如果请求来自signalr
var path = currentContext.HttpContext.Request.Path;
if (path.StartsWithSegments("/signalr"))
{
currentContext.Token = accessToken;
}
// 如果请求来自hangfire 或者cap
if (path.ToString().StartsWith("/hangfire") || path.ToString().StartsWith("/cap"))
{
currentContext.HttpContext.Response.Headers.Remove("X-Frame-Options");
if (!string.IsNullOrEmpty(accessToken))
{
currentContext.Token = accessToken;
currentContext.HttpContext.Response.Cookies
.Append("ProjectNameCookie", accessToken);
}
else
{
var cookies = currentContext.Request.Cookies;
if (cookies.ContainsKey("ProjectNameCookie"))
{
currentContext.Token = cookies["ProjectNameCookie"];
}
}
}
return Task.CompletedTask;
}
};
});
}
///
/// 配置options
///
///
private void ConfigureOptions(ServiceConfigurationContext context)
{
context.Services.Configure(context.Services.GetConfiguration().GetSection("Jwt"));
}
///
/// Redis缓存
///
private void ConfigureCache(ServiceConfigurationContext context)
{
var redisConnectionString =
context.Services.GetConfiguration().GetValue("Cache:Redis:ConnectionString");
var redisDatabaseId = context.Services.GetConfiguration().GetValue("Cache:Redis:DatabaseId");
var password = context.Services.GetConfiguration().GetValue("Cache:Redis:Password");
var connectString = $"{redisConnectionString},password={password},defaultdatabase={redisDatabaseId}";
var redis = ConnectionMultiplexer.Connect(connectString);
context.Services.AddStackExchangeRedisCache(options => { options.Configuration = connectString; });
context.Services
.AddDataProtection()
.PersistKeysToStackExchangeRedis(redis, "ProjectName-Protection-Keys");
}
private void ConfigureVirtualFileSystem(ServiceConfigurationContext context)
{
Configure(options => { options.FileSets.AddEmbedded(); });
// var hostingEnvironment = context.Services.GetHostingEnvironment();
//
// if (hostingEnvironment.IsDevelopment())
// {
// Configure(options =>
// {
// options.FileSets.ReplaceEmbeddedByPhysical(
// Path.Combine(hostingEnvironment.ContentRootPath,
// $"..{Path.DirectorySeparatorChar}CompanyName.ProjectName.Domain.Shared"));
// options.FileSets.ReplaceEmbeddedByPhysical(
// Path.Combine(hostingEnvironment.ContentRootPath,
// $"..{Path.DirectorySeparatorChar}CompanyName.ProjectName.Domain"));
// options.FileSets.ReplaceEmbeddedByPhysical(
// Path.Combine(hostingEnvironment.ContentRootPath,
// $"..{Path.DirectorySeparatorChar}CompanyName.ProjectName.Application.Contracts"));
// options.FileSets.ReplaceEmbeddedByPhysical(
// Path.Combine(hostingEnvironment.ContentRootPath,
// $"..{Path.DirectorySeparatorChar}CompanyName.ProjectName.Application"));
// });
// }
}
private void ConfigurationStsHttpClient(ServiceConfigurationContext context)
{
context.Services.AddHttpClient(HttpClientNameConsts.Sts,
options =>
{
options.BaseAddress =
new Uri(context.Services.GetConfiguration().GetSection("HttpClient:Sts:Url").Value);
});
}
private void ConfigureConventionalControllers()
{
Configure(options =>
{
options.ConventionalControllers.Create(typeof(ProjectNameApplicationModule).Assembly);
});
}
///
/// 健康检查
///
///
private void ConfigureHealthChecks(ServiceConfigurationContext context)
{
var redisConnectionString =
context.Services.GetConfiguration().GetValue("Cache:Redis:ConnectionString");
var redisDatabaseId = context.Services.GetConfiguration().GetValue("Cache:Redis:DatabaseId");
var password = context.Services.GetConfiguration().GetValue("Cache:Redis:Password");
var connectString = $"{redisConnectionString},password={password},defaultdatabase={redisDatabaseId}";
context.Services.AddHealthChecks().AddRedis(redisConnectionString).AddMySql(connectString);
}
private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddSwaggerGen(
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo {Title = "CompanyNameProjectName API", Version = "v1"});
options.DocInclusionPredicate((docName, description) => true);
options.EnableAnnotations(); // 启用注解
options.DocumentFilter();
options.SchemaFilter();
options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme()
{
Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",
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 = "多语言"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "ApiKey"}
},
new string[] { }
}
});
});
}
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", "繁體中文"));
options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch", "de"));
options.Languages.Add(new LanguageInfo("es", "es", "Español", "es"));
});
}
private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddAntiforgery(o => o.SuppressXFrameOptionsHeader = true);
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();
});
});
}
private void ConfigurationCap(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
var enabled = configuration.GetValue("Cap:Enabled", false);
if (enabled)
{
context.AddAbpCap(capOptions =>
{
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");
});
var hostingEnvironment = context.Services.GetHostingEnvironment();
bool auth = !hostingEnvironment.IsDevelopment();
capOptions.UseDashboard(options => { options.UseAuth = auth; });
});
}
else
{
context.AddAbpCap(capOptions =>
{
capOptions.UseInMemoryStorage();
capOptions.UseInMemoryMessageQueue();
var hostingEnvironment = context.Services.GetHostingEnvironment();
bool auth = !hostingEnvironment.IsDevelopment();
capOptions.UseDashboard(options => { options.UseAuth = auth; });
});
}
}
}
}