using JNPF.API.Entry.Handlers; using JNPF.Common.Cache; using JNPF.Common.Core.Filter; using JNPF.DatabaseAccessor; using JNPF.EventHandler; using JNPF.JsonSerialization; using JNPF.Message.Handlers; using JNPF.TaskScheduler.Interfaces.TaskScheduler; using JNPF.UnifyResult; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Options; using Newtonsoft.Json.Serialization; using Newtonsoft.Json; using Senparc.CO2NET.RegisterServices; using Senparc.CO2NET; using Senparc.Weixin; using Senparc.Weixin.Entities; using Senparc.Weixin.RegisterServices; using SqlSugar; using IGeekFan.AspNetCore.Knife4jUI; using JNPF.SpecificationDocument; using JNPF.Logging; using System.Xml; using System; using System.Text; using Top.Api; namespace JNPF.API.Entry; public class Startup : AppStartup { public void ConfigureServices(IServiceCollection services) { services.AddConsoleFormatter(option => { option.MessageFormat = LoggerConsoleFormat; }); // SqlSugar services.SqlSugarConfigure(); // Jwt处理程序 services.AddJwt(enableGlobalAuthorize: true); // 跨域 services.AddCorsAccessor(); // 注册EventBus服务 services.AddEventBus(options => { //// 创建连接工厂 //var factory = new RabbitMQ.Client.ConnectionFactory //{ // // 设置主机名 // HostName = "192.168.0.232", // // 用户名 // UserName = "jnpf", // // 密码 // Password = "jnpf@2019", //}; //// 创建默认内存通道事件源对象,可自定义队列路由key,比如这里是 eventbus //var rbmqEventSourceStorer = new RabbitMQEventSourceStorer(factory, "eventbus", 3000); //// 替换默认事件总线存储器 //options.ReplaceStorer(serviceProvider => //{ // return rbmqEventSourceStorer; //}); options.UseUtcTimestamp = false; // 不启用事件日志 options.LogEnabled = false; // 事件执行器(失败重试) options.AddExecutor(); }); // 注册远程请求 services.AddRemoteRequest(); services.AddConfigurableOptions(); services.AddConfigurableOptions(); services.AddConfigurableOptions(); services.AddControllers() .AddMvcFilter() .AddInjectWithUnifyResult() .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null) .AddNewtonsoftJson(options => { // 默认命名规则 options.SerializerSettings.ContractResolver = new DefaultContractResolver(); // 设置时区为 UTC options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; // 格式化json输出的日期格式 options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; // 忽略空值 // options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; // 忽略循环引用 options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 格式化json输出的日期格式为时间戳 options.SerializerSettings.Converters.Add(new NewtonsoftDateTimeJsonConverter()); }); // 配置Nginx转发获取客户端真实IP // 注1:如果负载均衡不是在本机通过 Loopback 地址转发请求的,一定要加上options.KnownNetworks.Clear()和options.KnownProxies.Clear() // 注2:如果设置环境变量 ASPNETCORE_FORWARDEDHEADERS_ENABLED 为 True,则不需要下面的配置代码 services.Configure(options => { options.ForwardedHeaders = ForwardedHeaders.All; options.KnownNetworks.Clear(); options.KnownProxies.Clear(); }); // 视图引擎 services.AddViewEngine(); // 任务调度 services.AddTaskScheduler(); // 脱敏词汇检测 services.AddSensitiveDetection(); // WebSocket服务 services.AddWebSocketManager(); // 微信 services.AddSenparcGlobalServices(App.Configuration) // Senparc.CO2NET 全局注册 .AddSenparcWeixinServices(App.Configuration); // Senparc.Weixin 注册(如果使用Senparc.Weixin SDK则添加) services.AddSession(); services.AddMemoryCache(); // 使用本地缓存必须添加 // 日志监听 // services.AddMonitorLogging(options => //{ // options.IgnorePropertyNames = new[] { "Byte" }; // options.IgnorePropertyTypes = new[] { typeof(byte[]) }; //}); services.AddFileLogging(options => { options.MessageFormat = LoggerFileFormat; options.FileNameRule = fileName => string.Format(fileName, DateTime.Now); // 每天创建一个文件 options.HandleWriteError = (writeError) => // 写入失败时启用备用文件 { writeError.UseRollbackFileName(Path.GetFileNameWithoutExtension(writeError.CurrentFileName) + "-oops" + Path.GetExtension(writeError.CurrentFileName)); }; }); services.AddUnitOfWork(); services.OSSServiceConfigure(); services.AddSingleton(); services.AddSchedule(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider, IOptions senparcSetting, IOptions senparcWeixinSetting) { // 添加状态码拦截中间件 app.UseUnifyResultStatusCodes(); // app.UseHttpsRedirection(); // 强制https app.UseStaticFiles(); #region 微信 IRegisterService register = RegisterService.Start(senparcSetting.Value).UseSenparcGlobal();//启动 CO2NET 全局注册,必须! register.UseSenparcWeixin(senparcWeixinSetting.Value, senparcSetting.Value);//微信全局注册,必须! #endregion app.UseWebSockets(); app.UseRouting(); app.UseCorsAccessor(); app.UseAuthentication(); app.UseAuthorization(); app.UseKnife4UI(options => { options.RoutePrefix = "newapi"; // 配置 Knife4UI 路由地址,现在是 /newapi foreach (var groupInfo in SpecificationDocumentBuilder.GetOpenApiGroups()) { options.SwaggerEndpoint("/" + groupInfo.RouteTemplate, groupInfo.Title); } }); app.UseInject(string.Empty); app.MapWebSocketManager("/api/message/websocket", serviceProvider.GetService()); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); serviceProvider.GetRequiredService().StartTimerJob(); } const string DATEFORMAT = "HH:mm:ss.fff"; private string LoggerLevelName(LogLevel level) { return level switch { LogLevel.Trace => "Trace", LogLevel.Debug => "Debug", LogLevel.Information => "Info", LogLevel.Warning => "Warn", LogLevel.Error => "Error", LogLevel.Critical => "Crit", _ => "None" }; } private string LoggerFileFormat(LogMessage msg) { return $"{LoggerLevelName(msg.LogLevel)} {msg.LogDateTime.ToString(DATEFORMAT)} {msg.ThreadId}# {msg.Message}"; } private string LoggerConsoleFormat(LogMessage msg) { var fclr = msg.LogLevel switch { LogLevel.Warning => "\u001b[1m\u001b[33m", LogLevel.Error => "\u001b[1m\u001b[31m", _ => "\u001b[39m\u001b[22m" }; return $"{fclr}{LoggerLevelName(msg.LogLevel)}\u001b[49m \u001b[36m{msg.LogDateTime.ToString(DATEFORMAT)}\u001b[49m \u001b[39m\u001b[22m{msg.ThreadId}#\u001b[49m {fclr}{msg.Message}\u001b[49m"; } }