// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddMemoryCache(); //使用本地缓需要添加 services.Add(ServiceDescriptor.Singleton(typeof(ILogger <>), typeof(Logger <>))); //使用 Memcached 或 Logger 需要添加 var builder = services.AddMvcCore(); //Senparc.CO2NET 全局注册(必须) services.AddSenparcGlobalServices(Configuration); #region WebApiEngine //忽略测试,注释掉以下代码后,可看到微信公众号SDK接口及注释信息 WebApi.Register.OmitCategoryList.Add(NeuChar.PlatformType.WeChat_OfficialAccount.ToString()); //额外增加测试 WebApi.Register.AdditionalClasses.Add(typeof(AdditionalType), "Additional"); WebApi.Register.AdditionalMethods.Add(typeof(AdditionalMethod).GetMethod("TestApi"), "Additional"); WebApi.Register.AdditionalMethods.Add(typeof(EncryptHelper).GetMethod("GetMD5", new[] { typeof(string), typeof(string) }), "Additional"); var docXmlPath = Path.Combine(WebHostEnvironment.ContentRootPath, "App_Data", "ApiDocXml"); services.AddAndInitDynamicApi(builder, options => { options.DocXmlPath = docXmlPath; options.DefaultRequestMethod = ApiRequestMethod.Get; options.BaseApiControllerType = null; options.CopyCustomAttributes = true; options.TaskCount = Environment.ProcessorCount * 4; options.ShowDetailApiLog = true; options.AdditionalAttributeFunc = null; options.ForbiddenExternalAccess = true; }); #endregion #region 独立测试 services.AddScoped(typeof(ApiBindTestService)); services.AddScoped(typeof(EntityApiBindTestService)); var apiBindTestService = new ApiBindTestService(); apiBindTestService.DynamicBuild(services, builder); #endregion #region Swagger //.NET Core 3.0 for Swagger https://www.thecodebuzz.com/swagger-api-documentation-in-net-core-3-0/ //添加Swagger services.AddSwaggerGen(c => { //为每个程序集创建文档 foreach (var apiAssembly in WebApiEngine.ApiAssemblyCollection) { var version = WebApiEngine.ApiAssemblyVersions[apiAssembly.Key]; //neucharApiDocAssembly.Value.ImageRuntimeVersion; var docName = WebApiEngine.GetDocName(apiAssembly.Key); c.SwaggerDoc(docName, new OpenApiInfo { Title = $"CO2NET Dynamic WebApi Engine : {apiAssembly.Key}", //Version = $"v{version}",//"v16.5.4" Description = $"Senparc CO2NET WebApi 动态引擎({apiAssembly.Key} - v{version})", //License = new OpenApiLicense() //{ // Name = "Apache License Version 2.0", // Url = new Uri("https://github.com/JeffreySu/WeiXinMPSDK") //}, Contact = new OpenApiContact() { Email = "*****@*****.**", Name = "Senparc Team", Url = new Uri("https://www.senparc.com") }, //TermsOfService = new Uri("https://github.com/JeffreySu/WeiXinMPSDK") }); //c.DocumentFilter<TagDescriptionsDocumentFilter>(); var docXmlFile = Path.Combine(WebApiEngine.GetDynamicFilePath(docXmlPath), $"{WebApiEngine.ApiAssemblyNames[apiAssembly.Key]}.xml"); if (File.Exists(docXmlFile)) { c.IncludeXmlComments(docXmlFile); } } //分组显示 https://www.cnblogs.com/toiv/archive/2018/07/28/9379249.html c.DocInclusionPredicate((docName, apiDesc) => { if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo)) { return(false); } //获取方法上的特性 var catalogNames = methodInfo.GetCustomAttributes(true) .OfType <SwaggerOperationAttribute>() .Select(z => z.Tags[0].Split(':')[0]); if (catalogNames?.Count() == 0) { //获取类上的特性 catalogNames = methodInfo.DeclaringType.GetCustomAttributes(true) .OfType <SwaggerOperationAttribute>() .Select(z => z.Tags[0].Split(':')[0]); } if (catalogNames?.Count() == 0) { return(false);//不符合要求的都不显示 } //docName: $"{neucharApiDocAssembly.Key}-v1" return(catalogNames.Any(z => docName.StartsWith(z))); }); c.OrderActionsBy(z => z.RelativePath); //c.DescribeAllEnumsAsStrings();//枚举显示字符串 c.EnableAnnotations(); c.DocumentFilter <RemoveVerbsFilter>(); c.CustomSchemaIds(x => x.FullName);//规避错误:InvalidOperationException: Can't use schemaId "$JsApiTicketResult" for type "$Senparc.Weixin.Open.Entities.JsApiTicketResult". The same schemaId was already used for type "$Senparc.Weixin.MP.Entities.JsApiTicketResult" /* 需要登陆,暂不考虑 —— Jeffrey Su 2021.06.17 * var oAuthDocName = "oauth2";// WeixinApiService.GetDocName(PlatformType.WeChat_OfficialAccount); * * //添加授权 * var authorizationUrl = NeuChar.App.AppStore.Config.IsDebug * //以下是 appPurachase 的 Id,实际应该是 appId * //? "http://localhost:12222/App/LoginOAuth/Authorize/1002/" * //: "https://www.neuchar.com/App/LoginOAuth/Authorize/4664/"; * //以下是正确的 appId * ? "http://localhost:12222/App/LoginOAuth/Authorize?appId=xxx" * : "https://www.neuchar.com/App/LoginOAuth/Authorize?appId=3035"; * * c.AddSecurityDefinition(oAuthDocName,//"Bearer" * new OpenApiSecurityScheme * { * Description = "请输入带有Bearer开头的Token", * Name = oAuthDocName,// "Authorization", * In = ParameterLocation.Header, * Type = SecuritySchemeType.OAuth2, * //OpenIdConnectUrl = new Uri("https://www.neuchar.com/"), * Flows = new OpenApiOAuthFlows() * { * Implicit = new OpenApiOAuthFlow() * { * AuthorizationUrl = new Uri(authorizationUrl), * Scopes = new Dictionary<string, string> { { "swagger_api", "Demo API - full access" } } * } * } * }); * * //认证方式,此方式为全局添加 * c.AddSecurityRequirement(new OpenApiSecurityRequirement() * { * { new OpenApiSecurityScheme(){ Name =oAuthDocName//"Bearer" * }, new List<string>() } * //{ "Bearer", Enumerable.Empty<string>() } * }); * * //c.OperationFilter<AuthResponsesOperationFilter>();//AuthorizeAttribute过滤 * */ }); #endregion }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions <SenparcSetting> senparcSetting) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); // 启动 CO2NET 全局注册,必须! app.UseSenparcGlobal(env, senparcSetting.Value, register => { #region CO2NET 全局配置 #region 全局缓存配置(按需) //当同一个分布式缓存同时服务于多个网站(应用程序池)时,可以使用命名空间将其隔离(非必须) register.ChangeDefaultCacheNamespace("CO2NETCache.net6.0"); #region 配置和使用 Redis //配置全局使用Redis缓存(按需,独立) var redisConfigurationStr = senparcSetting.Value.Cache_Redis_Configuration; var useRedis = !string.IsNullOrEmpty(redisConfigurationStr) && redisConfigurationStr != "Redis配置"; if (useRedis) //这里为了方便不同环境的开发者进行配置,做成了判断的方式,实际开发环境一般是确定的,这里的if条件可以忽略 { /* 说明: * 1、Redis 的连接字符串信息会从 Config.SenparcSetting.Cache_Redis_Configuration 自动获取并注册,如不需要修改,下方方法可以忽略 * /* 2、如需手动修改,可以通过下方 SetConfigurationOption 方法手动设置 Redis 链接信息(仅修改配置,不立即启用) */ Senparc.CO2NET.Cache.CsRedis.Register.SetConfigurationOption(redisConfigurationStr); //以下会立即将全局缓存设置为 Redis Senparc.CO2NET.Cache.CsRedis.Register.UseKeyValueRedisNow(); //键值对缓存策略(推荐) //Senparc.CO2NET.Cache.Redis.Register.UseHashRedisNow();//HashSet储存格式的缓存策略 //也可以通过以下方式自定义当前需要启用的缓存策略 //CacheStrategyFactory.RegisterObjectCacheStrategy(() => RedisObjectCacheStrategy.Instance);//键值对 //CacheStrategyFactory.RegisterObjectCacheStrategy(() => RedisHashSetObjectCacheStrategy.Instance);//HashSet } //如果这里不进行Redis缓存启用,则目前还是默认使用内存缓存 #endregion #region 配置和使用 Memcached //配置Memcached缓存(按需,独立) var memcachedConfigurationStr = senparcSetting.Value.Cache_Memcached_Configuration; var useMemcached = !string.IsNullOrEmpty(memcachedConfigurationStr) && memcachedConfigurationStr != "Memcached配置"; if (useMemcached) //这里为了方便不同环境的开发者进行配置,做成了判断的方式,实际开发环境一般是确定的,这里的if条件可以忽略 { app.UseEnyimMemcached(); /* 说明: * 1、Memcached 的连接字符串信息会从 Config.SenparcSetting.Cache_Memcached_Configuration 自动获取并注册,如不需要修改,下方方法可以忽略 * /* 2、如需手动修改,可以通过下方 SetConfigurationOption 方法手动设置 Memcached 链接信息(仅修改配置,不立即启用) */ Senparc.CO2NET.Cache.Memcached.Register.SetConfigurationOption(redisConfigurationStr); //以下会立即将全局缓存设置为 Memcached Senparc.CO2NET.Cache.Memcached.Register.UseMemcachedNow(); //也可以通过以下方式自定义当前需要启用的缓存策略 CacheStrategyFactory.RegisterObjectCacheStrategy(() => MemcachedObjectCacheStrategy.Instance); } #endregion #endregion #region 注册日志(按需,建议) register.RegisterTraceLog(ConfigTraceLog); //配置TraceLog #endregion #endregion }, #region 扫描自定义扩展缓存 //自动扫描自定义扩展缓存(二选一) autoScanExtensionCacheStrategies: true //默认为 true,可以不传入 //指定自定义扩展缓存(二选一) //autoScanExtensionCacheStrategies: false, extensionCacheStrategiesFunc: () => GetExCacheStrategies(senparcSetting.Value) #endregion ); app.UseSwagger(); app.UseSwaggerUI(c => { //c.DocumentTitle = "Senparc Weixin SDK Demo API"; c.InjectJavascript("/lib/jquery/dist/jquery.min.js"); c.InjectJavascript("/js/swagger.js"); //c.InjectJavascript("/js/tongji.js"); c.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None); foreach (var co2netApiDocAssembly in WebApiEngine.ApiAssemblyCollection) { //TODO:真实的动态版本号 var version = WebApiEngine.ApiAssemblyVersions[co2netApiDocAssembly.Key]; //neucharApiDocAssembly.Value.ImageRuntimeVersion; var docName = WebApiEngine.GetDocName(co2netApiDocAssembly.Key); //Console.WriteLine($"\tAdd {docName}"); c.SwaggerEndpoint($"/swagger/{docName}/swagger.json", $"{co2netApiDocAssembly.Key}"); } //OAuth https://www.cnblogs.com/miskis/p/10083985.html c.OAuthClientId("e65ea785b96b442a919965ccf857aba3"); //客服端名称 c.OAuthAppName("微信 API Swagger 文档 "); // 描述 }); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); }