389 lines
11 KiB
C#
389 lines
11 KiB
C#
using System;
|
||
using Autofac.Extensions.DependencyInjection;
|
||
using Microsoft.AspNetCore.Hosting;
|
||
using Microsoft.Extensions.Hosting;
|
||
using Microsoft.Extensions.Configuration;
|
||
using Serilog;
|
||
using System.Threading.Tasks;
|
||
using MassTransit;
|
||
using MassTransit.NewIdProviders;
|
||
using System.IO;
|
||
using IRaCIS.Core.Domain.Share;
|
||
using IRaCIS.Core.Infra.EFCore;
|
||
using IRaCIS.Core.Application.Helper;
|
||
using System.Runtime.InteropServices;
|
||
using Microsoft.AspNetCore.Builder;
|
||
using IRaCIS.Core.API;
|
||
using Autofac;
|
||
using Microsoft.AspNetCore.Http.Features;
|
||
using Microsoft.AspNetCore.SignalR;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using IRaCIS.Core.Application.Filter;
|
||
using Microsoft.AspNetCore.HttpOverrides;
|
||
using IRaCIS.Application.Services.BackGroundJob;
|
||
using LogDashboard;
|
||
using FellowOakDicom.Network;
|
||
using IRaCIS.Core.Application.Service.ImageAndDoc;
|
||
using IP2Region.Net.Abstractions;
|
||
using IP2Region.Net.XDB;
|
||
using IRaCIS.Core.Application.BusinessFilter;
|
||
using Microsoft.AspNetCore.Http;
|
||
using IRaCIS.Core.Infrastructure.Extention;
|
||
using Newtonsoft.Json;
|
||
using Microsoft.AspNetCore.Diagnostics;
|
||
using IRaCIS.Core.Application.MassTransit.Command;
|
||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||
|
||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
||
#region 获取环境变量
|
||
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
|
||
var config = new ConfigurationBuilder()
|
||
.AddEnvironmentVariables()
|
||
.Build();
|
||
|
||
var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
|
||
|
||
if (string.IsNullOrWhiteSpace(enviromentName))
|
||
{
|
||
|
||
var index = Array.IndexOf(args, "--env");
|
||
enviromentName = index > -1
|
||
? args[index + 1]
|
||
: "Development";
|
||
}
|
||
#endregion
|
||
|
||
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
|
||
{
|
||
EnvironmentName = enviromentName
|
||
});
|
||
|
||
#region 兼容windows 服务命令行的方式
|
||
|
||
//foreach (var arg in args)
|
||
//{
|
||
// Console.WriteLine(arg);
|
||
//}
|
||
|
||
int urlsIndex = Array.FindIndex(args, arg => arg != null && arg.StartsWith("--urls"));
|
||
|
||
if (urlsIndex > -1)
|
||
{
|
||
var url = args[urlsIndex].Substring("--urls=".Length);
|
||
Console.WriteLine(url);
|
||
builder.WebHost.UseUrls(url);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 主机配置
|
||
|
||
|
||
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
|
||
|
||
builder.Configuration.AddJsonFile(ConfigMapFileProvider.FromRelativePath(""), "appsettings.json", false, true)
|
||
.AddJsonFile(ConfigMapFileProvider.FromRelativePath(""), $"appsettings.{enviromentName}.json", false, true);
|
||
|
||
builder.Host
|
||
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||
.ConfigureContainer<ContainerBuilder>(containerBuilder =>
|
||
{
|
||
containerBuilder.RegisterModule<AutofacModuleSetup>();
|
||
})
|
||
.UseWindowsService().UseSerilog();
|
||
#endregion
|
||
|
||
|
||
#region 配置服务
|
||
var _configuration = builder.Configuration;
|
||
|
||
//健康检查
|
||
builder.Services.AddHealthChecks();
|
||
//本地化
|
||
builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources");
|
||
|
||
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
||
builder.Services.AddControllers(options =>
|
||
{
|
||
//options.Filters.Add<LogActionFilter>();
|
||
options.Filters.Add<ModelActionFilter>();
|
||
options.Filters.Add<ProjectExceptionFilter>();
|
||
options.Filters.Add<UnitOfWorkFilter>();
|
||
options.Filters.Add<EncreptApiResultFilter>(10);
|
||
options.Filters.Add<LimitUserRequestAuthorization>();
|
||
|
||
|
||
})
|
||
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
||
|
||
builder.Services.AddOptions().Configure<SystemEmailSendConfig>(_configuration.GetSection("SystemEmailSendConfig"));
|
||
builder.Services.AddOptions().Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
|
||
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
|
||
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
||
builder.Services.AddOptions().Configure<EncreptResponseOption>(_configuration.GetSection("EncrypteResponseConfig"));
|
||
builder.Services.AddOptions().Configure<SystemPacsConfig>(_configuration.GetSection("SystemPacsConfig"));
|
||
|
||
|
||
//动态WebApi + UnifiedApiResultFilter 省掉控制器代码
|
||
builder.Services.AddDynamicWebApiSetup();
|
||
//AutoMapper
|
||
builder.Services.AddAutoMapperSetup();
|
||
//EF ORM QueryWithNoLock
|
||
builder.Services.AddEFSetup(_configuration,enviromentName);
|
||
//Http 响应压缩
|
||
builder.Services.AddResponseCompressionSetup();
|
||
//Swagger Api 文档
|
||
builder.Services.AddSwaggerSetup();
|
||
//JWT Token 验证
|
||
builder.Services.AddJWTAuthSetup(_configuration);
|
||
|
||
// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
|
||
//builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
|
||
|
||
#region MassTransit
|
||
//masstransit组件 也支持MediatR 中介者模式,但是支持分布式,考虑后续,所以在次替代MediatR
|
||
builder.Services.AddMediator(cfg =>
|
||
{
|
||
cfg.AddConsumer<ConsistencyCheckConsumer>();
|
||
});
|
||
|
||
builder.Services.AddMassTransit(cfg =>
|
||
{
|
||
cfg.UsingInMemory();
|
||
});
|
||
#endregion
|
||
|
||
|
||
#region FusionCache
|
||
|
||
builder.Services.AddFusionCache();
|
||
|
||
#endregion
|
||
|
||
// EasyCaching 缓存
|
||
builder.Services.AddEasyCachingSetup(_configuration);
|
||
|
||
// hangfire 定时任务框架 有界面,更友好~
|
||
builder.Services.AddhangfireSetup(_configuration);
|
||
|
||
|
||
//Serilog 日志可视化 LogDashboard日志
|
||
builder.Services.AddLogDashboardSetup();
|
||
|
||
|
||
builder.Services.AddJsonConfigSetup(_configuration);
|
||
//转发头设置 获取真实IP
|
||
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||
{
|
||
options.ForwardedHeaders =
|
||
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||
});
|
||
//Dicom影像渲染图片 跨平台
|
||
builder.Services.AddDicomSetup();
|
||
|
||
// 实时应用
|
||
builder.Services.AddSignalR();
|
||
|
||
builder.Services.AddSingleton<IUserIdProvider, IRaCISUserIdProvider>();
|
||
|
||
|
||
builder.Services.AddSingleton<ISearcher>(new Searcher(CachePolicy.Content, Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources, "ip2region.xdb")));
|
||
|
||
//builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
|
||
//builder.Services.AddProblemDetails();
|
||
|
||
#region 历史废弃配置
|
||
//builder.Services.AddMemoryCache();
|
||
////上传限制 配置
|
||
//builder.Services.Configure<FormOptions>(options =>
|
||
//{
|
||
// options.MultipartBodyLengthLimit = int.MaxValue;
|
||
// options.ValueCountLimit = int.MaxValue;
|
||
// options.ValueLengthLimit = int.MaxValue;
|
||
//});
|
||
//IP 限流 可设置白名单 或者黑名单
|
||
//services.AddIpPolicyRateLimitSetup(_configuration);
|
||
// 用户类型 策略授权
|
||
//services.AddAuthorizationPolicySetup(_configuration);
|
||
#endregion
|
||
|
||
#endregion
|
||
|
||
var app = builder.Build();
|
||
var env = app.Environment;
|
||
|
||
#region 配置中间件
|
||
|
||
|
||
// Configure the HTTP request pipeline.
|
||
|
||
#region 异常处理 全局业务异常已统一处理了,非业务错误会来到这里 400 -500状态码
|
||
|
||
|
||
//app.UseStatusCodePagesWithReExecute("/Error/{0}");
|
||
|
||
app.UseStatusCodePages(async context =>
|
||
{
|
||
var code = context.HttpContext.Response.StatusCode;
|
||
context.HttpContext.Response.ContentType = "application/json";
|
||
if (code < 500)
|
||
{
|
||
await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk($"Client error, actual request error status code({code})")));
|
||
}
|
||
else
|
||
{
|
||
//ResultFilter 里面的异常并不会到这里
|
||
await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject((ResponseOutput.NotOk($"Server error , actual request error status code({code})"))));
|
||
}
|
||
|
||
});
|
||
|
||
//app.UseExceptionHandler(o => { });
|
||
|
||
//这里没生效,原因未知,官方文档也是这种写法,也用了GlobalExceptionHandler 尝试,还是不行,怀疑框架bug
|
||
//app.UseExceptionHandler(configure =>
|
||
//{
|
||
// configure.Run(async context =>
|
||
// {
|
||
// var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
|
||
//var ex = exceptionHandlerPathFeature?.Error;
|
||
//context.Response.ContentType = "application/json";
|
||
|
||
//if (ex != null)
|
||
//{
|
||
// var errorInfo = $"Exception: {ex.Message}[{ex.StackTrace}]" + (ex.InnerException != null ? $" InnerException: {ex.InnerException.Message}[{ex.InnerException.StackTrace}]" : "");
|
||
|
||
// await context.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk($"{ex?.Message}")));
|
||
|
||
// Log.Logger.Error(errorInfo);
|
||
|
||
|
||
//}
|
||
|
||
// });
|
||
//});
|
||
|
||
|
||
|
||
#endregion
|
||
|
||
//本地化
|
||
app.UseLocalization();
|
||
|
||
app.UseForwardedHeaders();
|
||
|
||
//响应压缩
|
||
app.UseResponseCompression();
|
||
|
||
|
||
//不需要 token 访问的静态文件 wwwroot css, JavaScript, and images don't require authentication.
|
||
app.UseStaticFiles();
|
||
|
||
|
||
|
||
//LogDashboard
|
||
app.UseLogDashboard("/LogDashboard");
|
||
|
||
//hangfire
|
||
app.UseHangfireConfig(env);
|
||
|
||
#region 暂时废弃
|
||
|
||
//app.UseMiddleware<MultiDiskStaticFilesMiddleware>();
|
||
////限流 中间件
|
||
//app.UseIpRateLimiting();
|
||
//if (env.IsDevelopment())
|
||
//{
|
||
// app.UseDeveloperExceptionPage();
|
||
//}
|
||
//else
|
||
//{
|
||
// //app.UseHsts();
|
||
//}
|
||
#endregion
|
||
|
||
|
||
|
||
|
||
|
||
SwaggerSetup.Configure(app, env);
|
||
|
||
|
||
////serilog 记录请求的用户信息
|
||
app.UseSerilogConfig(env);
|
||
|
||
app.UseRouting();
|
||
|
||
app.UseCors(t => t.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
|
||
|
||
//app.UseIRacisHostStaticFileStore(env);
|
||
|
||
|
||
app.UseAuthentication();
|
||
app.UseAuthorization();
|
||
|
||
app.MapControllers();
|
||
|
||
app.MapHub<UploadHub>("/UploadHub");
|
||
app.MapHealthChecks("/health");
|
||
|
||
|
||
// Serilog
|
||
SerilogExtension.AddSerilogSetup(enviromentName, app.Services);
|
||
|
||
|
||
var hangfireJobService = app.Services.GetRequiredService<IIRaCISHangfireJob>();
|
||
|
||
await hangfireJobService.InitHangfireJobTaskAsync();
|
||
|
||
|
||
|
||
#endregion
|
||
|
||
try
|
||
{
|
||
#region 运行环境 部署平台
|
||
|
||
Log.Logger.Warning($"当前环境:{enviromentName}");
|
||
|
||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||
{
|
||
Log.Logger.Warning($"当前部署平台环境:windows");
|
||
}
|
||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||
{
|
||
Log.Logger.Warning($"当前部署平台环境:linux");
|
||
}
|
||
else
|
||
{
|
||
Log.Logger.Warning($"当前部署平台环境:OSX or FreeBSD");
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
Log.Logger.Warning($"ContentRootPath:{env.ContentRootPath}");
|
||
|
||
|
||
string parentDirectory = Path.GetFullPath(Path.Combine(env.ContentRootPath, ".."));
|
||
|
||
|
||
Log.Logger.Warning($"ContentRootPath——parentDirectory:{parentDirectory}");
|
||
|
||
//Log.Logger.Warning($"ContentRootPath——GetParent:{Directory.GetParent(env.ContentRootPath).Parent.FullName}");
|
||
//Log.Logger.Warning($"ContentRootPath——xx:{Path.GetDirectoryName(Path.GetDirectoryName(env.ContentRootPath))}");
|
||
|
||
|
||
app.Run();
|
||
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
|
||
Log.Logger.Error(e.InnerException is null ? e.Message + e.StackTrace : e.InnerException?.Message + e.InnerException?.StackTrace);
|
||
}
|
||
|
||
|
||
|