using CSRedis; using System.IO; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.Hosting; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using WaterCloud.Code; using WaterCloud.Code.Model; using System.Text.Encodings.Web; using System.Text.Unicode; using Newtonsoft.Json.Serialization; using WaterCloud.Service.AutoJob; using WaterCloud.DataBase; using System.Reflection; using System.Linq; using WaterCloud.Service; using Autofac; using Microsoft.AspNetCore.Mvc; using Quartz; using Quartz.Impl; using Quartz.Spi; using System; using Chloe.Infrastructure.Interception; using Microsoft.Extensions.FileProviders; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.ResponseCompression; using System.IO.Compression; using WaterCloud.Domain.SystemOrganize; using Microsoft.OpenApi.Models; namespace WaterCloud.Web { public class Startup { public IConfiguration Configuration { get; } public IWebHostEnvironment WebHostEnvironment { get; set; } public Startup(IConfiguration configuration, IWebHostEnvironment env) { Configuration = configuration; WebHostEnvironment = env; GlobalContext.LogWhenStart(env); GlobalContext.HostingEnvironment = env; } // This method gets called by the runtime. Use this method to add services to the container. public async void ConfigureServices(IServiceCollection services) { GlobalContext.SystemConfig = Configuration.GetSection("SystemConfig").Get(); GlobalContext.Services = services; GlobalContext.Configuration = Configuration; services.AddSwaggerGen(config => { config.SwaggerDoc("v1", new OpenApiInfo { Title = "WaterCloud Api", Version = "v1" }); var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); config.IncludeXmlComments(xmlPath, true); //添加控制器层注释(true表示显示控制器注释) }); services.AddSession(); //代替HttpContext.Current services.AddHttpContextAccessor(); //缓存缓存选择 if (Configuration.GetSection("SystemConfig:CacheProvider").Value!= Define.CACHEPROVIDER_REDIS) { services.AddMemoryCache(); } else { //redis 注入服务 string redisConnectiong = Configuration.GetSection("SystemConfig:RedisConnectionString").Value; // 多客户端 1、基础 2、操作日志 var redisDB1 = new CSRedisClient(redisConnectiong + ",defaultDatabase=" + 0); BaseHelper.Initialization(redisDB1); var redisDB2 = new CSRedisClient(redisConnectiong + ",defaultDatabase=" + 1); HandleLogHelper.Initialization(redisDB2); services.AddSingleton(redisDB1); services.AddSingleton(redisDB2); } //连续guid初始化,示例IDGenerator.NextId() services.AddSingleton(); #region 依赖注入 //注入数据库连接 services.AddScoped((serviceProvider) => { return DBContexHelper.Contex(); }); #region 注入 Quartz调度类 services.AddSingleton(); //注册ISchedulerFactory的实例。 services.AddSingleton(); services.AddSingleton(); //是否开启后台任务 if (Configuration.GetSection("SystemConfig:OpenQuarz").Value == "True") { services.AddHostedService(); } #endregion //注入SignalR实时通讯,默认用json传输 services.AddSignalR(options => { //客户端发保持连接请求到服务端最长间隔,默认30秒,改成4分钟,网页需跟着设置connection.keepAliveIntervalInMilliseconds = 12e4;即2分钟 options.ClientTimeoutInterval = TimeSpan.FromMinutes(4); //服务端发保持连接请求到客户端间隔,默认15秒,改成2分钟,网页需跟着设置connection.serverTimeoutInMilliseconds = 24e4;即4分钟 options.KeepAliveInterval = TimeSpan.FromMinutes(2); }); ////注册html解析 //services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All)); ////注册特性 //services.AddScoped(); //services.AddScoped(); ////ajax不能使用注入 ////services.AddScoped(); //services.AddScoped(); #endregion services.AddCors(options => options.AddPolicy("CorsPolicy", builder => { builder.AllowAnyMethod().AllowAnyHeader() .WithOrigins(Configuration.GetSection("SystemConfig:AllowCorsSite").Value.Split(",")) .AllowCredentials(); })); services.AddHttpClient(); services.AddControllersWithViews(options => { options.Filters.Add(); options.Filters.Add(); options.ModelMetadataDetailsProviders.Add(new ModelBindingMetadataProvider()); //options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()); }).AddNewtonsoftJson(options => { // 返回数据首字母不小写,CamelCasePropertyNamesContractResolver是小写 options.SerializerSettings.ContractResolver = new DefaultContractResolver(); }).AddControllersAsServices().AddRazorRuntimeCompilation(); services.AddDirectoryBrowser(); services.AddControllers(options => { options.Filters.Add(); options.ModelMetadataDetailsProviders.Add(new ModelBindingMetadataProvider()); }).ConfigureApiBehaviorOptions(options => { options.SuppressModelStateInvalidFilter = true; }); services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN"); //启用 Gzip 和 Brotil 压缩功能 services.AddResponseCompression(options => { options.Providers.Add(); options.Providers.Add(); options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( new[] { "image/svg+xml" }); }); services.Configure(options => { options.Level = (CompressionLevel)4; // 4 or 5 is OK }); services.AddOptions(); services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(GlobalContext.HostingEnvironment.ContentRootPath + Path.DirectorySeparatorChar + "DataProtection")); //更新数据库管理员和主系统 try { if (GlobalContext.SystemConfig.ReviseSysem == true) { using (var context = DBContexHelper.Contex()) { var setentity = context.Query().FirstOrDefault(); context.Session.BeginTransaction(); var user = context.Query().Where(a => a.F_Account == setentity.F_AdminAccount).FirstOrDefault(); var userinfo = context.Query().Where(a => a.F_UserId == user.F_Id).FirstOrDefault(); userinfo.F_UserSecretkey = Md5.md5(Utils.CreateNo(), 16).ToLower(); userinfo.F_UserPassword = Md5.md5(DESEncrypt.Encrypt(Md5.md5(GlobalContext.SystemConfig.SysemUserPwd, 32).ToLower(), userinfo.F_UserSecretkey).ToLower(), 32).ToLower(); context.Update(a => a.F_Id == user.F_Id, a => new UserEntity { F_Account = GlobalContext.SystemConfig.SysemUserCode }); var cacheKeyUser = "watercloud_userdata_"; await CacheHelper.Remove(cacheKeyUser + user.F_Id); await context.UpdateAsync(a => a.F_Id == userinfo.F_Id, a => new UserLogOnEntity { F_UserPassword = userinfo.F_UserPassword, F_UserSecretkey = userinfo.F_UserSecretkey }); await context.UpdateAsync(a => a.F_Id == userinfo.F_Id, a => new SystemSetEntity { F_AdminAccount = GlobalContext.SystemConfig.SysemUserCode, F_AdminPassword = GlobalContext.SystemConfig.SysemUserPwd }); context.Session.CommitTransaction(); var cacheKeyOperator = "watercloud_operator_";// +登录者token await CacheHelper.Remove(cacheKeyOperator + "info_" + user.F_Id); } } } catch (Exception ex) { LogHelper.Write(ex); } //清理缓存 //CacheHelper.FlushAll().GetAwaiter().GetResult(); } //AutoFac注入 public void ConfigureContainer(ContainerBuilder builder) { var assemblys = Assembly.Load("WaterCloud.Service");//Service是继承接口的实现方法类库名称             var baseType = typeof(IDenpendency);//IDenpendency 是一个接口(所有要实现依赖注入的借口都要继承该接口)             builder.RegisterAssemblyTypes(assemblys).Where(m => baseType.IsAssignableFrom(m) && m != baseType) .InstancePerLifetimeScope()//生命周期,这里没有使用接口方式 .PropertiesAutowired() ;//属性注入 //Controller中使用属性注入 var controllerBaseType = typeof(Controller); builder.RegisterAssemblyTypes(typeof(Program).Assembly) .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType) .PropertiesAutowired(); //注册html解析 builder.RegisterInstance(HtmlEncoder.Create(UnicodeRanges.All)).SingleInstance(); //注册特性 builder.RegisterType(typeof(HandlerLoginAttribute)).InstancePerLifetimeScope(); builder.RegisterType(typeof(HandlerAuthorizeAttribute)).InstancePerLifetimeScope(); builder.RegisterType(typeof(HandlerAdminAttribute)).InstancePerLifetimeScope(); builder.RegisterType(typeof(HandlerLockAttribute)).InstancePerLifetimeScope(); //ControllerBase中使用属性注入 controllerBaseType = typeof(ControllerBase); builder.RegisterAssemblyTypes(typeof(Program).Assembly) .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType) .PropertiesAutowired(); //注册特性 builder.RegisterType(typeof(AuthorizeFilterAttribute)).InstancePerLifetimeScope(); builder.RegisterType(typeof(LoginFilterAttribute)).InstancePerLifetimeScope(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app) { //由于.Net Core默认只会从wwwroot目录加载静态文件,其他文件夹的静态文件无法正常访问。 //而我们希望将图片上传到网站根目录的upload文件夹下,所以需要额外在Startup.cs类的Configure方法中 string resource = Path.Combine(Directory.GetCurrentDirectory(), "upload"); if (!FileHelper.IsExistDirectory(resource)) { FileHelper.CreateFolder(resource); } app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(resource), RequestPath = "/upload", OnPrepareResponse = ctx => { ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=36000"); } }); app.UseCors("CorsPolicy"); if (WebHostEnvironment.IsDevelopment()) { //打印sql IDbCommandInterceptor interceptor = new DbCommandInterceptor(); DbInterception.Add(interceptor); GlobalContext.SystemConfig.Debug = true; app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error?msg=404"); } //文件地址Resource //静态资源wwwroot app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = new CustomerFileExtensionContentTypeProvider(), OnPrepareResponse = GlobalContext.SetCacheControl }); //启用 Gzip 和 Brotil 压缩功能 app.UseResponseCompression(); app.Use(next => context => { context.Request.EnableBuffering(); return next(context); }); app.UseSwagger(c => { c.RouteTemplate = "api-doc/{documentName}/swagger.json"; }); app.UseSwaggerUI(c => { c.RoutePrefix = "api-doc"; c.SwaggerEndpoint("v1/swagger.json", "WaterCloud Api v1"); }); //session app.UseSession(); //路径 app.UseRouting(); //MVC路由 app.UseEndpoints(endpoints => { endpoints.MapHub("/chatHub"); endpoints.MapControllerRoute("areas", "{area:exists}/{controller=Home}/{action=Index}/{id?}"); endpoints.MapControllerRoute("default", "{controller=Login}/{action=Index}/{id?}"); endpoints.MapControllerRoute("api", "api/{controller=ApiHome}/{action=Index}/{id?}"); }); GlobalContext.ServiceProvider = app.ApplicationServices; } } }