using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.AspNetCore.Localization;
const string corsScheme = "Open-Dpz-Core";
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.CreateBootstrapLogger();
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseAgileConfig();
var configuration = builder.Configuration;
CdnBaseAddress = configuration["CDNBaseAddress"] ??
throw new Exception("configuration node CDNBaseAddress is null or empty");
var logSeq = configuration.GetSection("LogSeq").Get<LogSeq>();
builder.Host.ConfigurationLog(logSeq);
const int threads = 100;
if (ThreadPool.SetMinThreads(threads, threads))
{
Log.Information("set worker threads:{WorkerThreads},set completion port threads {CompletionPortThreads}",
threads,
threads);
}
builder.WebHost
.UseKestrel((_, option) =>
{
option.AddServerHeader = false;
option.ConfigureHttpsDefaults(x => x.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13);
})
.UseIIS()
.UseIISIntegration();
#region services
var services = builder.Services;
services.AddMvc(x =>
{
x.Filters.Add(typeof(GlobalFilter));
x.Filters.Add(new TypeFilterAttribute(typeof(ExceptionHandleAttribute)));
});
//压缩
services.AddResponseCompression(options =>
{
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
{
"application/font-woff2",
"image/svg+xml",
"text/plain",
"application/lrc"
});
options.EnableForHttps = true;
});
services.Configure<BrotliCompressionProviderOptions>(options => { options.Level = CompressionLevel.Optimal; });
services.Configure<GzipCompressionProviderOptions>(options => { options.Level = CompressionLevel.Optimal; });
#if DEBUG
services.Configure<KestrelServerOptions>(options => { options.Limits.MaxRequestBodySize = int.MaxValue; });
#endif
//依赖注入
services.AddDefaultServices(configuration).AddInject();
//缩小html
services.AddWebMarkupMin(x =>
{
x.AllowMinificationInDevelopmentEnvironment = true;
x.AllowCompressionInDevelopmentEnvironment = true;
})
.AddHtmlMinification(x =>
{
var settings = x.MinificationSettings;
settings.RemoveOptionalEndTags = false;
})
.AddXmlMinification()
.AddHttpCompression(option =>
{
option.CompressorFactories = new List<ICompressorFactory>
{
new BuiltInBrotliCompressorFactory(new BuiltInBrotliCompressionSettings
{
Level = CompressionLevel.Optimal
}),
new DeflateCompressorFactory(new DeflateCompressionSettings
{
Level = CompressionLevel.Optimal
}),
new GZipCompressorFactory(new GZipCompressionSettings
{
Level = CompressionLevel.Optimal
})
};
});
// 响应式服务
services.AddResponsive();
// 设备识别
services.AddDetection();
// .AddDevice().AddBrowser()
// .AddPlatform()
// .AddEngine()
// .AddCrawler();
//注册 响应服务
services.AddResponsive();
//services.AddHostedService<TimedHostedService>();
services.AddControllersWithViews();
//注册 缓存中间件
services.AddResponseCaching();
var redisConnectionString = configuration.GetConnectionString("redis") ??
throw new Exception("configuration node redis is null or empty");
//缓存
services.AddRedisCacheOutput(redisConnectionString);
services.AddBusinessServices(configuration);
// Cors
services.AddCors(options =>
{
options.AddPolicy(corsScheme, cfg =>
{
cfg
.WithOrigins(configuration.GetSection("Origins").Get<string[]>() ?? Array.Empty<string>())
.WithMethods("GET", "PUT", "POST", "DELETE", "PATCH", "OPTION")
.AllowAnyHeader();
});
});
//注册 身份认证服务
services.Configure<TokenManagement>(configuration.GetSection("TokenManagement"));
services
.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = AuthorizeCookieName;
x.DefaultChallengeScheme = AuthorizeCookieName;
x.DefaultSignInScheme = AuthorizeCookieName;
})
.AddCookie(AuthorizeCookieName, options => options.LoginPath = "/login.html")
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, x =>
{
var token = configuration.GetSection("TokenManagement").Get<TokenManagement>();
if (token == null) return;
x.RequireHttpsMetadata = true;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(token.Secret)),
ValidIssuer = token.Issuer,
ValidAudience = token.Audience,
ValidateIssuer = true,
ValidateAudience = true
};
});
//services.AddAuthorization(x => )
services.AddIdentityCore<VmUserInfo>(x => x.ClaimsIdentity.SecurityStampClaimType = AuthorizeCookieName)
.AddUserStore<UserStore>()
.AddSignInManager<ApplicationSignInManager>();
services.AddDataProtection().SetApplicationName(AuthorizeCookieName);
services.AddOptions<KeyManagementOptions>()
.Configure<IServiceScopeFactory>((options, factory) =>
{
options.XmlRepository = new XmlRepositoryService(factory, AuthorizeCookieName + ".Key");
});
//register SignalR
services
.AddSignalR(x =>
{
x.HandshakeTimeout = TimeSpan.FromMinutes(2);
x.MaximumReceiveMessageSize = 32768;
})
.AddStackExchangeRedis(redisConnectionString,
options => { options.Configuration.ChannelPrefix = "Dpz.Core.signalR"; });
// 添加Hangfire 服务
services.HangfireService(configuration);
#endregion
services.ConfigureDynamicProxy(config =>
{
#if DEBUG
config.Interceptors.AddTyped<RecordExecuteTimeAttribute>(
Predicates.ForNameSpace("Dpz.Core.Service.RepositoryService"),
Predicates.ForNameSpace("Dpz.Core.Service.V4.Services"));
#endif
});
builder.Host.UseServiceProviderFactory(new DynamicProxyServiceProviderFactory());
var app = builder.Build();
#region configuration
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseRouteDebugger();
}
var supportedCultures = new[]
{
new CultureInfo("zh-CN"),
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("zh-CN"),
// Formatting numbers, dates, etc.
SupportedCultures = supportedCultures,
// UI strings that we have localized.
SupportedUICultures = supportedCultures
});
app.UseSerilogRequestLogging(options =>
{
options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
diagnosticContext.Set("RequestHost", httpContext.Request.Host.Value);
diagnosticContext.Set("RequestScheme", httpContext.Request.Scheme);
diagnosticContext.Set("UserAgent", httpContext.Request.Headers.UserAgent.ToString());
diagnosticContext.Set("IpAddress", httpContext.Request.GetIpAddress());
};
});
//启用压缩
app.UseResponseCompression();
// app.UseHsts();
// app.UseHttpsRedirection();
//启用静态文件
app.UseStaticFiles(new StaticFileOptions()
{
OnPrepareResponse = ctx =>
{
// 如果访问静态资源的图片,那么设置缓存
if (ctx.Context.Response.ContentType?.StartsWith("image/", StringComparison.CurrentCultureIgnoreCase) ==
true
)
{
ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=2592000");
ctx.Context.Response.Headers.Append("Expires",
DateTime.UtcNow.AddDays(30).ToString("R", CultureInfo.InvariantCulture));
}
}
});
app.UseWebMarkupMin();
//启用缓存中间件
app.UseResponseCaching();
//启用响应服务
app.UseResponsive();
//拒绝爬虫
app.UseRejectBots();
app.UseCors(corsScheme);
app.UseResponsive();
app.UseDetection();
app.UseRouting().UseMiddleware<HttpResponseHeaderHandel>().UseRecordRequest();
//启用身份认证
app.UseAuthentication();
//启用身份授权
app.UseAuthorization();
// 路由
app.ConfigurationRoute();
//系统初始化
app.Init();
// 使用 hangfire UI,及周期性任务调度
app.HangfireSetting();
#endregion
Log.Information("Starting web core host");
app.Run();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
Log.Fatal(ex, "Host terminated unexpectedly");
}
public partial class Program
{
/// <summary>
/// 身份认证Cookie名称
/// </summary>
public const string AuthorizeCookieName = "Dpz.Web.Core.Authoriza";
/// <summary>
/// 获取CDN基础地址
/// </summary>
public static string CdnBaseAddress { get; private set; } = "";
/// <summary>
/// 版本号
/// </summary>
public static string Version => Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "_version";
}