ToB企服应用市场:ToB评测及商务社交产业平台

标题: .NET Core基础到实战案例零碎学习笔记 [打印本页]

作者: 花瓣小跑    时间: 2023-8-30 02:36
标题: .NET Core基础到实战案例零碎学习笔记
前言:前段时间根据 [老张的哲学] 大佬讲解的视频做的笔记,讲的很不错。此文主要记录JWT/DI依赖注入/AOP面向切面编程/DTO/解决跨域等相关知识,还包含一些.NET Core项目实战的一些案例。我是西瓜程序猿,感谢大家的支持!
一、ASP.NET Core基础

1.1-.NET Core概述

1.1.1-.NET Croe简介

(1)为什么要学习.NET Core?
.NET Core是为了重新启动某些Framework组件而为其他人提供平台工作的机会,由于.NET Framework主要以委托(C#)代码位基础构建了因此这些部分不需要改代码即可移至.NET Core。

(2).NET Core运用的多吗?
微信支付、网易游戏、三星电子、Adobe、Stackoverflow等

(3)什么是.NET Core?
跨平台、自托管、开源、高性能,.NETCore是基于Kestrel执行的控制台程序。


(4)中间件的执行过程?


(5)中间件3种写法?

1.1.2-进程内托管 和 进程外托管



1.2-JWT详解



1.2.1-为什么要保护API?


1.2.2-设计原则


1.2.3-加密算法


1.2.4-有哪些方式保护方式



1.2.5-JWT的好处?


1.2.6-如何使用JWT?



1.3-DI依赖注入(IOC的思想)

1.3.1-相关基本概念


1.3.2-常见的依赖注入有哪些?


1.3.3-三种注入方法


1.3.4-三种声明周期-注册要保持一致


1.3.5-为什么要使用依赖注入?


1.3.6-依赖注入步骤





1.4-AOP面向切面编程(思想)

1.4.1-什么是AOP?


1.4.2-AOP的特点?


1.4.3-思想的来源


1.4.4-AOP只是流程


1.4.5-AOP应用场景(不是业务逻辑的逻辑、是公共逻辑)


1.4.6-多种思想应用的区别



1.4.7-AOP有哪些优势?


1.4.8-AOP的使用



1.5-DTO与多模型

1.5.1-什么是DTO?

数据传输对象(DTO全称为Data Transfer Object):是一种设计模式之间传输数据的软件应用系统。数据传输对象往往是数据访问对象从数据库检索数据。数据传输对象与数据交互对象或数据访问对象之间的差异是一个以下不具有任何行为除了存储和检索的数据(范文和存取器)。

1.5.2-为什么要使用数据传输对象DTO?


1.5.3-DTO和ViewModel(视图模型)是一回事么?


1.5.5-多种模型概论


1.5.6-如何使用DTO?



1.6-跨域

1.6.1-跨域的相关概念

域名组成:



1.6.2-JSONP



1.6.3-Proxy--接口级别




1.6.4-Cors--项目级别



1.6.5-Nginx



1.6.6-Socket--非HTTP请求



1.6.7-其他跨域操作



二、ASP.NET Core项目实战案例

2.1-Autofac依赖注入

(1)西瓜程序猿创建的项目结构如下:

项目相关依赖如下:

(2)在【Autofac依赖注入】层导入相关Nuget包:

(3)在Program.cs使用Autofac工厂:

(4)在AutofacModuleRegister写入以下代码,继承自Modele,并重写Load方法。
  1.   protected override void Load(ContainerBuilder builder)
  2.         {
  3.             var basePath = AppContext.BaseDirectory;
  4.             #region 带有接口层的服务注入
  5.             var servicesDllFile = Path.Combine(basePath, "Autofac.Service.dll");
  6.             var repositoryDllFile = Path.Combine(basePath, "Autofac.Repository.dll");
  7.             if (!(File.Exists(servicesDllFile) && File.Exists(repositoryDllFile)))
  8.             {
  9.                 var msg = "Repository.dll和service.dll 丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查 bin 文件夹,并拷贝。";
  10.                 throw new Exception(msg);
  11.             }
  12.             // 获取 Service.dll 程序集服务,并注册
  13.             var assemblysServices = Assembly.LoadFrom(servicesDllFile);
  14.             builder.RegisterAssemblyTypes(assemblysServices)
  15.                       .AsImplementedInterfaces()
  16.                       .InstancePerDependency();
  17.             // 获取 Repository.dll 程序集服务,并注册
  18.             var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
  19.             builder.RegisterAssemblyTypes(assemblysRepository)
  20.                    .AsImplementedInterfaces()
  21.                    .PropertiesAutowired()
  22.                    .InstancePerDependency();
  23.             #endregion
  24.         }
复制代码
(5)在控制器中使用构造函数依赖注入。

(6)然后编译项目,最后运行项目试试,可以发现报错了,因为Repository.dll和service.dll 丢失,因为项目解耦了。解决方案如下:
将这下面2个实现层输出位置如下:



2.2-AutoMapper对象映射

(1)引入包。

(2)创建对应的数据实体,和要返回的视图模型实体。
实体:

视图模型实体:

(3)创建一个【CustomProfile】类,需要继承自【Profile】,用来创建关系映射。

(4)创建一个【AutoMapperConfig】类,用来静态全局 AutoMapper 配置文件。

(5)创建一个【AutoMapperSetup】类,用于Automapper的启动服务。

(6)然后在【Startup.cs】的ConfigreServices方法注册相关服务。


2.3-IP Limit限流解析

2.3.1-什么是限流?

2.3.2-时间窗口算法

2.3.3-漏斗算法

2.3.4-令牌算法

2.3.5-时间窗口(代码实现)
(1)安装Nuget包。

(2)创建【IpPolicyRateLimitSetup】类,用于限流,启用服务。

(3)在【Startup.cs】的ConfigreServices方法注册相关服务。

(4)在【appsettings.json】中根节点写入一下配置。
  1. "IpRateLimiting": {
  2.     "EnableEndpointRateLimiting": true, //false: 全局执行API——true:针对每个API
  3.     "StackBlockedRequests": false, //False:应在另一个计数器上记录拒绝次数
  4.     "RealIpHeader": "X-Real-IP",
  5.     "ClientIdHeader": "X-ClientId",
  6.     "IpWhitelist": [], //添加白名单
  7.     "EndpointWhitelist": [ "get:/api/xxx", "*:/api/yyy" ],//添加API的白名单
  8.     "ClientWhitelist": [ "dev-client-1", "dev-client-2" ],//添加客户端的白名单
  9.     "QuotaExceededResponse": {
  10.       "Content": "{{"status":429,"msg":"时间限流:访问过于频繁,请稍后重试","success":false}}",
  11.       "ContentType": "application/json",
  12.       "StatusCode": 429
  13.     },
  14.     "HttpStatusCode": 429, //返回状态码
  15.     "GeneralRules": [ //api规则,结尾一定要带*
  16.       {
  17.         //针对blog的API,1分钟最多访问20次
  18.         "Endpoint": "*:/api/blog*", //规则
  19.         "Period": "1m", //时间
  20.         "Limit": 20 //次数
  21.       },
  22.       {
  23.         //无论什么API,1秒最能请求3次
  24.         "Endpoint": "*/api/*",
  25.         "Period": "1s",
  26.         "Limit": 3
  27.       },
  28.       {
  29.         //无论什么API,1分钟最能请求30次
  30.         "Endpoint": "*/api/*",
  31.         "Period": "1m",
  32.         "Limit": 30
  33.       },
  34.       {
  35.         //无论什么API,12小时秒最能请求50次
  36.         "Endpoint": "*/api/*",
  37.         "Period": "12h",
  38.         "Limit": 500
  39.       }
  40.     ]
  41.   }
复制代码
(5)写一个中间件,用于IP限流。

(6)在【Startup.cs】的Configure中配置中间件。

(7)平凡请求接口时。


2.4-CORS跨域与"钓鱼"


2.4.1-没有跨域会导致什么问题?


2.4.2-CORS跨域代码实现
(1)安装Nuget包。

(2)创建【CorsSetup】类,用于限流,启用服务。

(3)在【Startup.cs】的ConfigreServices方法注册相关服务。

(4)在【appsettings.json】中根节点写入一下配置。
  1.   "Cors": {
  2.       "PolicyName": "CorsIpAccess", //策略名称
  3.       "EnableAllIPs": true, //当为true时,开放所有IP均可访问。
  4.       // 支持多个域名端口,注意端口号后不要带/斜杆:比如localhost:8000/,是错的
  5.       // 注意,http://127.0.0.1:1818 和 http://localhost:1818 是不一样的
  6.       "IPs": "http://127.0.0.1:2364,http://localhost:2364"
  7.     },
复制代码
(5)在【Startup.cs】的Configure中配置中间件。
  1. // CORS跨域
  2. app.UseCors(Appsettings.app(new string[] { "Startup", "Cors", "PolicyName" }));
复制代码
2.5-Swagger接口文文档

(1)导入Nuget包。

(2)创建【SwaggerSetup】类,启动Swagger服务。
  1.   /// <summary>
  2.     /// Swagger 启动服务
  3.     /// </summary>
  4.     public static class SwaggerSetup
  5.     {
  6.         private static readonly ILog log =LogManager.GetLogger(typeof(SwaggerSetup));
  7.         public static void AddSwaggerSetup(this IServiceCollection services)
  8.         {
  9.             if (services == null)
  10.                 throw new ArgumentNullException(nameof(services));
  11.             //获取项目的根路径
  12.             var basePath = AppContext.BaseDirectory;
  13.             //获取项目名
  14.             var ApiName = Appsettings.app(new string[] { "Startup", "ApiName" });
  15.             services.AddSwaggerGen(c =>
  16.             {
  17.                 //遍历出全部的版本,做文档信息展示
  18.                 typeof(ApiVersions).GetEnumNames().ToList().ForEach(version =>
  19.                 {
  20.                     c.SwaggerDoc(version, new OpenApiInfo
  21.                     {
  22.                         Version = version,
  23.                         //RuntimeInformation.FrameworkDescription:运行时版本
  24.                         Title = $"{ApiName} 西瓜程序猿 - 接口文档——{RuntimeInformation.FrameworkDescription}",
  25.                         Description = $"{ApiName} HTTP API " + version,
  26.                         //Contact:联系
  27.                         //License:声明
  28.                     });
  29.                     c.OrderActionsBy(o => o.RelativePath);//接口排序
  30.                 });
  31.                 try
  32.                 {
  33.                     //这个就是刚刚配置的xml文件名【文档API的注释】
  34.                     var xmlPath = Path.Combine(basePath, "Blog.Core.xml");
  35.                     //默认的第二个参数是false,这个是controller的注释,记得修改
  36.                     c.IncludeXmlComments(xmlPath, true);
  37.                     //这个就是Model层的xml文件名【Model相关的注释】
  38.                     var xmlModelPath = Path.Combine(basePath, "Blog.Core.Model.xml");
  39.                     c.IncludeXmlComments(xmlModelPath);
  40.                 }
  41.                 catch (Exception ex)
  42.                 {
  43.                     log.Error("Blog.Core.xml和Blog.Core.Model.xml 丢失,请检查并拷贝。\n" + ex.Message);
  44.                 }
  45.                 // 开启加权小锁
  46.                 c.OperationFilter<AddResponseHeadersFilter>();
  47.                 c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
  48.                 // 在header中添加token,传递到后台
  49.                 c.OperationFilter<SecurityRequirementsOperationFilter>();
  50.                 // ids4和jwt切换
  51.                 if (Permissions.IsUseIds4)
  52.                 {
  53.                     //接入identityserver4
  54.                     c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
  55.                     {
  56.                         Type = SecuritySchemeType.OAuth2,
  57.                         Flows = new OpenApiOAuthFlows
  58.                         {
  59.                             Implicit = new OpenApiOAuthFlow
  60.                             {
  61.                                 AuthorizationUrl = new Uri($"{Appsettings.app(new string[] { "Startup", "IdentityServer4", "AuthorizationUrl" })}/connect/authorize"),
  62.                                 Scopes = new Dictionary<string, string> {
  63.                                 {
  64.                                     "blog.core.api","ApiResource id"
  65.                                 }
  66.                             }
  67.                             }
  68.                         }
  69.                     });
  70.                 }
  71.                 else
  72.                 {
  73.                     // Jwt Bearer 认证,必须是 oauth2
  74.                     c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
  75.                     {
  76.                         Description = "描述:西瓜程序猿 - JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)"",
  77.                         Name = "Authorization",//jwt默认的参数名称
  78.                         In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
  79.                         Type = SecuritySchemeType.ApiKey
  80.                     });
  81.                 }
  82.             });
  83.         }
  84.     }
  85.     /// <summary>
  86.     /// 自定义版本
  87.     /// </summary>
  88.     public class CustomApiVersion
  89.     {
  90.         /// <summary>
  91.         /// Api接口版本 自定义
  92.         /// </summary>
  93.         public enum ApiVersions
  94.         {
  95.             /// <summary>
  96.             /// V1 版本
  97.             /// </summary>
  98.             V1 = 1,
  99.             /// <summary>
  100.             /// V2 版本
  101.             /// </summary>
  102.             V2 = 2,
  103.         }
  104.     }
复制代码
(3)在【Startup.cs】的ConfigreServices方法注册相关服务。

(4)创建一个【UseSwaggerMildd】类,开启并处理Swagger中间件。
  1.   private static readonly ILog log = LogManager.GetLogger(typeof(SwaggerMildd));
  2.         public static void UseSwaggerMildd(this IApplicationBuilder app, Func<Stream> streamHtml)
  3.         {
  4.             if (app == null) throw new ArgumentNullException(nameof(app));
  5.             app.UseSwagger();
  6.             app.UseSwaggerUI(c =>
  7.             {
  8.                 //根据版本名称倒序 遍历展示
  9.                 var ApiName = Appsettings.app(new string[] { "Startup", "ApiName" });
  10.                 typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
  11.                 {
  12.                     c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{ApiName} {version}");
  13.                 });
  14.                 c.SwaggerEndpoint($"https://petstore.swagger.io/v2/swagger.json", $"{ApiName} pet");
  15.                 // 将swagger首页,设置成我们自定义的页面,记得这个字符串的写法:{项目名.index.html}
  16.                 if (streamHtml.Invoke() == null)
  17.                 {
  18.                     var msg = "index.html的属性,必须设置为嵌入的资源";
  19.                     log.Error(msg);
  20.                     throw new Exception(msg);
  21.                 }
  22.                 c.IndexStream = streamHtml;
  23.                 if (Permissions.IsUseIds4)
  24.                 {
  25.                     c.OAuthClientId("blogadminjs");
  26.                 }
  27.                 // 路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc";
  28.                 c.RoutePrefix = "";
  29.             });
  30.         }
复制代码
(5)在【Startup.cs】中配置中间件,注意顺序。

(6)index.html记得设置为【嵌套的资源】


2.6-MiniProfiler性能分析

(1)导入Nuget包。

(2)创建【AddMiniProfilerSetup】类,启动Swagger服务。
  1.    public static void AddMiniProfilerSetup(this IServiceCollection services)
  2.         {
  3.             if (services == null) throw new ArgumentNullException(nameof(services));
  4.             if(Appsettings.app(new string[] { "Startup", "MiniProfiler", "Enabled" }).ObjToBool())
  5.             {
  6.                 services.AddMiniProfiler();
  7.             }
  8.             // 3.x使用MiniProfiler,必须要注册MemoryCache服务
  9.             // services.AddMiniProfiler(options =>
  10.             // {
  11.             //     options.RouteBasePath = "/profiler";
  12.             //     //(options.Storage as MemoryCacheStorage).CacheDuration = TimeSpan.FromMinutes(10);
  13.             //     options.PopupRenderPosition = StackExchange.Profiling.RenderPosition.Left;
  14.             //     options.PopupShowTimeWithChildren = true;
  15.             //     // 可以增加权限
  16.             //     //options.ResultsAuthorize = request => request.HttpContext.User.IsInRole("Admin");
  17.             //     //options.UserIdProvider = request => request.HttpContext.User.Identity.Name;
  18.             // }
  19.             //);
  20.         }
复制代码
(3)在【Startup.cs】的ConfigreServices方法注册相关服务。

(4)创建一个【UseMiniProfilerMildd】类,开启并处理Swagger中间件。
  1.    private static readonly ILog log = LogManager.GetLogger(typeof(MiniProfilerMildd));
  2.         public static void UseMiniProfilerMildd(this IApplicationBuilder app)
  3.         {
  4.             if (app == null) throw new ArgumentNullException(nameof(app));
  5.             try
  6.             {
  7.                 if (Appsettings.app("Startup", "MiniProfiler", "Enabled").ObjToBool())
  8.                 {
  9.                     // 性能分析
  10.                     app.UseMiniProfiler();
  11.                 }
  12.             }
  13.             catch (Exception e)
  14.             {
  15.                 log.Error($"An error was reported when starting the MiniProfilerMildd.\n{e.Message}");
  16.                 throw;
  17.             }
  18.         }
复制代码
(5)在【Startup.cs】中配置中间件,注意顺序。


2.7-StackEx.Redis安装与使用

(1)导入Nuget包。

(2)创建【RedisCacheSetup】类,启动Redis服务。

(3)在【Startup.cs】的ConfigreServices方法注册相关服务。

(4)创建一个名为【IRedisCacheManager】接口,用于Redis缓存。
  1.   /// <summary>
  2.     /// Redis缓存接口
  3.     /// </summary>
  4.     public interface IRedisCacheManager
  5.     {
  6.         //获取 Reids 缓存值
  7.         string GetValue(string key);
  8.         //获取值,并序列化
  9.         TEntity Get<TEntity>(string key);
  10.         //保存
  11.         void Set(string key, object value, TimeSpan cacheTime);
  12.         //判断是否存在
  13.         bool Get(string key);
  14.         //移除某一个缓存值
  15.         void Remove(string key);
  16.         //全部清除
  17.         void Clear();
  18.     }
复制代码
(5)创建一个【RedisCacheManager】类,并实现【IRedisCacheManager】接口
  1. public class RedisCacheManager : IRedisCacheManager
  2.     {
  3.         private readonly string redisConnenctionString;
  4.         public volatile ConnectionMultiplexer redisConnection;
  5.         private readonly object redisConnectionLock = new object();
  6.         public RedisCacheManager()
  7.         {
  8.             string redisConfiguration = Appsettings.app(new string[] { "AppSettings", "RedisCachingAOP", "ConnectionString" });//获取连接字符串
  9.             if (string.IsNullOrWhiteSpace(redisConfiguration))
  10.             {
  11.                 throw new ArgumentException("Redis配置为空", nameof(redisConfiguration));
  12.             }
  13.             this.redisConnenctionString = redisConfiguration;
  14.             this.redisConnection = GetRedisConnection();
  15.         }
  16.         /// <summary>
  17.         /// 核心代码,获取连接实例
  18.         /// 通过双if 夹lock的方式,实现单例模式
  19.         /// </summary>
  20.         /// <returns></returns>
  21.         private ConnectionMultiplexer GetRedisConnection()
  22.         {
  23.             //如果已经连接实例,直接返回
  24.             if (this.redisConnection != null && this.redisConnection.IsConnected)
  25.             {
  26.                 return this.redisConnection;
  27.             }
  28.             //加锁,防止异步编程中,出现单例无效的问题
  29.             lock (redisConnectionLock)
  30.             {
  31.                 if (this.redisConnection != null)
  32.                 {
  33.                     //释放redis连接
  34.                     this.redisConnection.Dispose();
  35.                 }
  36.                 try
  37.                 {
  38.                     var config = new ConfigurationOptions
  39.                     {
  40.                         AbortOnConnectFail = false,
  41.                         AllowAdmin = true,
  42.                         ConnectTimeout = 15000,//改成15s
  43.                         SyncTimeout = 5000,
  44.                         //Password = "Pwd",//Redis数据库密码
  45.                         EndPoints = { redisConnenctionString }// connectionString 为IP:Port 如”192.168.2.110:6379”
  46.                     };
  47.                     this.redisConnection = ConnectionMultiplexer.Connect(config);
  48.                 }
  49.                 catch (Exception)
  50.                 {
  51.                     throw new Exception("Redis服务未启用,请开启该服务,并且请注意端口号,本项目使用的的6319,而且我的是没有设置密码。");
  52.                 }
  53.             }
  54.             return this.redisConnection;
  55.         }
  56.         /// <summary>
  57.         /// 清除
  58.         /// </summary>
  59.         public void Clear()
  60.         {
  61.             foreach (var endPoint in this.GetRedisConnection().GetEndPoints())
  62.             {
  63.                 var server = this.GetRedisConnection().GetServer(endPoint);
  64.                 foreach (var key in server.Keys())
  65.                 {
  66.                     redisConnection.GetDatabase().KeyDelete(key);
  67.                 }
  68.             }
  69.         }
  70.         /// <summary>
  71.         /// 判断是否存在
  72.         /// </summary>
  73.         /// <param name="key"></param>
  74.         /// <returns></returns>
  75.         public bool Get(string key)
  76.         {
  77.             return redisConnection.GetDatabase().KeyExists(key);
  78.         }
  79.         /// <summary>
  80.         /// 查询
  81.         /// </summary>
  82.         /// <param name="key"></param>
  83.         /// <returns></returns>
  84.         public string GetValue(string key)
  85.         {
  86.             return redisConnection.GetDatabase().StringGet(key);
  87.         }
  88.         /// <summary>
  89.         /// 获取
  90.         /// </summary>
  91.         /// <typeparam name="TEntity"></typeparam>
  92.         /// <param name="key"></param>
  93.         /// <returns></returns>
  94.         public TEntity Get<TEntity>(string key)
  95.         {
  96.             var value = redisConnection.GetDatabase().StringGet(key);
  97.             if (value.HasValue)
  98.             {
  99.                 //需要用的反序列化,将Redis存储的Byte[],进行反序列化
  100.                 return SerializeHelper.Deserialize<TEntity>(value);
  101.             }
  102.             else
  103.             {
  104.                 return default(TEntity);
  105.             }
  106.         }
  107.         /// <summary>
  108.         /// 移除
  109.         /// </summary>
  110.         /// <param name="key"></param>
  111.         public void Remove(string key)
  112.         {
  113.             redisConnection.GetDatabase().KeyDelete(key);
  114.         }
  115.         /// <summary>
  116.         /// 设置
  117.         /// </summary>
  118.         /// <param name="key"></param>
  119.         /// <param name="value"></param>
  120.         /// <param name="cacheTime"></param>
  121.         public void Set(string key, object value, TimeSpan cacheTime)
  122.         {
  123.             if (value != null)
  124.             {
  125.                 //序列化,将object值生成RedisValue
  126.                 redisConnection.GetDatabase().StringSet(key, SerializeHelper.Serialize(value), cacheTime);
  127.             }
  128.         }
  129.         /// <summary>
  130.         /// 增加/修改
  131.         /// </summary>
  132.         /// <param name="key"></param>
  133.         /// <param name="value"></param>
  134.         /// <returns></returns>
  135.         public bool SetValue(string key, byte[] value)
  136.         {
  137.             return redisConnection.GetDatabase().StringSet(key, value, TimeSpan.FromSeconds(120));
  138.         }
  139.     }
复制代码
(6)修改【appsetting.json】配置文件。


(4)创建一个【UseSwaggerMildd】类,开启并处理Swagger中间件。
  1.   private static readonly ILog log = LogManager.GetLogger(typeof(SwaggerMildd));
  2.         public static void UseSwaggerMildd(this IApplicationBuilder app, Func<Stream> streamHtml)
  3.         {
  4.             if (app == null) throw new ArgumentNullException(nameof(app));
  5.             app.UseSwagger();
  6.             app.UseSwaggerUI(c =>
  7.             {
  8.                 //根据版本名称倒序 遍历展示
  9.                 var ApiName = Appsettings.app(new string[] { "Startup", "ApiName" });
  10.                 typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
  11.                 {
  12.                     c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{ApiName} {version}");
  13.                 });
  14.                 c.SwaggerEndpoint($"https://petstore.swagger.io/v2/swagger.json", $"{ApiName} pet");
  15.                 // 将swagger首页,设置成我们自定义的页面,记得这个字符串的写法:{项目名.index.html}
  16.                 if (streamHtml.Invoke() == null)
  17.                 {
  18.                     var msg = "index.html的属性,必须设置为嵌入的资源";
  19.                     log.Error(msg);
  20.                     throw new Exception(msg);
  21.                 }
  22.                 c.IndexStream = streamHtml;
  23.                 if (Permissions.IsUseIds4)
  24.                 {
  25.                     c.OAuthClientId("blogadminjs");
  26.                 }
  27.                 // 路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc";
  28.                 c.RoutePrefix = "";
  29.             });
  30.         }
复制代码
(5)在【Startup.cs】中配置中间件,注意顺序。



原文链接:https://www.cnblogs.com/kimiliucn/p/17641252.html
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4