Startup.cs 12 KB
using NCC.Common.Cache;
using NCC.Common.Core.Filter;
using NCC.Data.SqlSugar.Extensions;
using NCC.JsonSerialization;
using NCC.Message.Extensions;
using NCC.TaskScheduler.Interfaces.TaskScheduler;
using NCC.UnifyResult;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using OnceMi.AspNetCore.OSS;
using Senparc.CO2NET;
using Senparc.CO2NET.RegisterServices;
using Senparc.Weixin;
using Senparc.Weixin.Entities;
using Senparc.Weixin.RegisterServices;
using Serilog;
using SqlSugar;
using SqlSugar.IOC;
using System;
using System.Collections.Generic;
using Yitter.IdGenerator;
using NCC.Common.Finder;
using Antis.Pay.Core.Interface;
using Antis.Pay.Core;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using NCC.Extend.Interfaces.MqttPublisher;
using NCC.Extend;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.AspNetCore.Server.Kestrel.Core;

namespace NCC.API.Core
{
    /// <summary>
    /// 
    /// </summary>
    [AppStartup(9)]
    public class Startup : AppStartup
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {

            SqlSugarConfigure(services);

            services.AddJwt<JwtHandler>(enableGlobalAuthorize: true);
            //services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            services.AddCorsAccessor();

            services.AddRemoteRequest();

            services.AddConfigurableOptions<CacheOptions>();
            //使用微信支付实现
            services.AddScoped<IWePay, WePay>();

            services.AddControllersWithViews()
                    .AddMvcFilter<RequestActionFilter>()
                    .AddInjectWithUnifyResult<RESTfulResultProvider>()
                     //.AddJsonOptions(options =>
                     //{
                     //    //options.JsonSerializerOptions.Converters.AddDateFormatString("yyyy-MM-dd HH:mm:ss");
                     //    //格式化日期时间格式
                     //    options.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter());
                     //});
                     .AddNewtonsoftJson(options =>
                     {
                         //options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                         //默认命名规则
                         options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                         //设置时区为 UTC
                         options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
                         //格式化json输出的日期格式
                         options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                         //格式化json输出的日期格式为时间戳
                         options.SerializerSettings.Converters.Add(new NewtonsoftDateTimeJsonConverter());
                         //空值处理
                         //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                     });

            services.AddViewEngine();

            #region minio

            services.AddOSSService(option =>
            {
                option.Provider = OSSProvider.Minio;
                option.Endpoint = "192.168.0.60:9000";
                option.AccessKey = "minioadmin";
                option.SecretKey = "minioadmin";
                option.IsEnableHttps = false;
                option.IsEnableCache = true;
            });

            #endregion

            #region 微信
            services.AddSenparcGlobalServices(App.Configuration)//Senparc.CO2NET 全局注册
                        .AddSenparcWeixinServices(App.Configuration);//Senparc.Weixin 注册(如果使用Senparc.Weixin SDK则添加)
            services.AddSession();
            services.AddMemoryCache();//使用本地缓存必须添加
            services.AddSenparcWeixinServices(App.Configuration);
            #endregion

            #region 文件上传设置
            services.Configure<FormOptions>(options =>
            {
                options.ValueLengthLimit = int.MaxValue;
                options.MultipartBodyLengthLimit = int.MaxValue;
                options.MemoryBufferThreshold = int.MaxValue;
                //每个多部分正文的长度限制  默认值约为128MB
                //options.MultipartBodyLengthLimit = 1073741824; //此处限制最大1G 

            });
            services.Configure<IISServerOptions>(options =>
            {
                options.MaxRequestBodySize = 1073741824;

            });
            services.Configure<KestrelServerOptions>(options =>
            {
                options.Limits.MaxRequestBodySize = 1073741824; // 1GB
            });
            #endregion

            #region 微信
            services.AddSenparcGlobalServices(App.Configuration)//Senparc.CO2NET 全局注册
                        .AddSenparcWeixinServices(App.Configuration);//Senparc.Weixin 注册(如果使用Senparc.Weixin SDK则添加)
            services.AddSession();
            services.AddMemoryCache();//使用本地缓存必须添加
            services.AddSenparcWeixinServices(App.Configuration);
            #endregion
            // 添加微信支付依赖注入 
            services.AddWeChatPay();
            services.AddEventBridge();

            //依赖注入mqtt服务
            services.AddSingleton<IMqttPublisherService, MqttPublisherService>();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="senparcSetting"></param>
        /// <param name="senparcWeixinSetting"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions<SenparcSetting> senparcSetting, IOptions<SenparcWeixinSetting> senparcWeixinSetting)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            //  NGINX 反向代理获取真实IP
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
            });

            // 添加状态码拦截中间件
            app.UseUnifyResultStatusCodes();

            app.UseHttpsRedirection(); // 强制https

            string DefaultStatic = "index.html";
            if (env.IsDevelopment())
            {
                DefaultStatic = "default.html";
            }

            #region 配置默认访问的静态地址
            DefaultFilesOptions options = new DefaultFilesOptions();
            options.DefaultFileNames.Clear();
            options.DefaultFileNames.Add(DefaultStatic);
            app.UseDefaultFiles(options);
            app.UseStaticFiles(new StaticFileOptions
            {
                ContentTypeProvider = new FileExtensionContentTypeProvider
                {
                    Mappings =
                    {
                        [".apk"] = "application/vnd.android.package-archive",
                        [".jpg"] = "image/jpeg",
                        [".png"] = "image/png",
                        [".mp4"] = "video/mp4"
                    }
                }
            });

            #endregion

            // Serilog请求日志中间件---必须在 UseStaticFiles 和 UseRouting 之间
            app.UseSerilogRequestLogging();

            app.UseWebSockets(new WebSocketOptions()
            {
                KeepAliveInterval = TimeSpan.FromSeconds(20),
                ReceiveBufferSize = 4 * 1024
            });
            app.UseMiddleware<WebSocketHandlerMiddleware>();

            app.UseRouting();

            app.UseCorsAccessor();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseInject(string.Empty);

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
            // App.GetService<ITimeTaskService>().StartTimerJob();

            // 设置雪花id的workerId,确保每个实例workerId都应不同
            var workerId = ushort.Parse(App.Configuration["SnowId:WorkerId"] ?? "1");
            YitIdHelper.SetIdGenerator(new IdGeneratorOptions { WorkerId = workerId, WorkerIdBitLength = 16 });

            #region 微信

            IRegisterService register = RegisterService.Start(senparcSetting.Value).UseSenparcGlobal();//启动 CO2NET 全局注册,必须!
            register.UseSenparcWeixin(senparcWeixinSetting.Value, senparcSetting.Value);//微信全局注册,必须!

            #endregion

            // 开启自启动定时任务
            App.GetService<ITimeTaskService>().StartTimerJob();
            // 启动 MQTT 服务
            var mqttService = app.ApplicationServices.GetRequiredService<IMqttPublisherService>();
            _ = mqttService.StartAsync();
        }

        /// <summary>
        /// 配置SqlSugar
        /// </summary>
        /// <param name="services"></param>
        private void SqlSugarConfigure(IServiceCollection services)
        {
            #region 配置sqlsuagr

            List<ConnectionConfig> connectConfigList = new List<ConnectionConfig>();
            var connectionStr = $"{App.Configuration["ConnectionStrings:DefaultConnection"]}";
            var dataBase = $"{App.Configuration["ConnectionStrings:DBName"]}";
            var dbType = (DbType)Enum.Parse(typeof(DbType), App.Configuration["ConnectionStrings:DBType"]);
            var ConfigId = $"{App.Configuration["ConnectionStrings:ConfigId"]}";
            var iocDbType = (IocDbType)Enum.Parse(typeof(IocDbType), App.Configuration["ConnectionStrings:DBType"]);

            SugarIocServices.AddSqlSugar(new IocConfig()
            {
                ConnectionString = string.Format(connectionStr, dataBase),
                DbType = iocDbType,
                ConfigId = ConfigId,
                IsAutoCloseConnection = true//自动释放
            });

            connectConfigList.Add(new ConnectionConfig
            {
                ConnectionString = string.Format(connectionStr, dataBase),
                DbType = dbType,
                IsAutoCloseConnection = true,
                InitKeyType = InitKeyType.Attribute,
                ConfigId = ConfigId,
                ConfigureExternalServices = new ConfigureExternalServicesExtenisons()
                {
                    EntityNameServiceType = typeof(SugarTable)//这个不管是不是自定义都要写,主要是用来获取所有实体
                }
            });

            services.AddSqlSugar(connectConfigList.ToArray(), db =>
            {
                db.Aop.OnLogExecuting = (sql, pars) =>
                {
                    if (sql.StartsWith("SELECT"))
                    {
                        Console.ForegroundColor = ConsoleColor.Green;
                    }
                    if (sql.StartsWith("UPDATE") || sql.StartsWith("INSERT"))
                    {
                        Console.ForegroundColor = ConsoleColor.White;
                    }
                    if (sql.StartsWith("DELETE"))
                    {
                        Console.ForegroundColor = ConsoleColor.Blue;
                    }
                    //在控制台输出sql语句
                    Console.WriteLine(SqlProfiler.ParameterFormat(sql, pars));
                    //App.PrintToMiniProfiler("SqlSugar", "Info", SqlProfiler.ParameterFormat(sql, pars));
                };
            });

            #endregion
        }
    }
}