前言:前段时间根据 [老张的哲学] 大佬讲解的视频做的笔记,讲的很不错。此文主要记录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种写法?

  • Run
  • Use
  • Map和MapThen

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

1.2-JWT详解

1.2.1-为什么要保护API?

  • 防泄漏
  • 防攻击
    • 防伪装攻击(案例:在公共网络环境里,第三方有意或者无意的调用我们的接口)
    • 放篡改工具(案例:在公共网络环境里,请求头/查询字符串/内容在传输过程中被修改)
    • 防重放工具(案例:在公共环境网络里,请求呗捕获后,稍后被重放或者多次)
  • 收益化:将数据进行开发,然后进行付费才能使用。

1.2.2-设计原则

  • 轻量级
  • 易于开发、测试和部署
  • 适合于异构系统(跨操作系统、多语言简易实现)
  • 所有写操作接口(增删改查)
  • 非公开的读接口(如:泄密/敏感/隐私等)

1.2.3-加密算法

  • ES:对称可逆加密算法

    • DES
    • AES
  • RSA:非对称可逆算法
  • Base64
  • MD5:不可逆加密

1.2.4-有哪些方式保护方式

1.2.5-JWT的好处?

  • 服务无状态
  • 解决跨域问题:这是基于Token的访问策略可以克服Cookie的跨域问题。
  • 服务端无状态可以横向扩展,Token可完成认证,不许存储Seesion
  • 系统解耦,Token携带所有的用户信息,无需绑定一个特定的认证方案,只需要知道加密的方法和秘钥就可以进行加密解密,有利于解耦。
  • 防止跨站点脚本攻击,没有Cokkie技术,无需考虑跨站请求的安全问题。

1.2.6-如何使用JWT?

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

1.3.1-相关基本概念

  • 他距离我们不遥远:类和对象——实例化的过程
  • 依赖注入实现了new,不是为了省一个new
  • 解除依赖的思想是如何产生的。
  • 控制反装:
    • 是一种设计原则,最早由Martin Fowler提出,因为其理论提出时间和成熟时间比较晚,所以并没有包含在Gof的《设计模式》中。
    • 对依赖的控制从自己,转到自己的调用者上。
  • 依赖注入是实现控制反转思想的一种实现(不要弄混淆了),依赖的对象注入到调用者,你不应该自己创建他,而是通过由你的调用者给你——容器。

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

  • 微软自带的DI(建议使用)
  • Autofac:貌似目前.NET、.NET Core下用的最多(建议使用)
  • Ninject:目前好像没什么人用了
  • Unity:也是比较常用

1.3.3-三种注入方法

  • 构造函数注入——遵循显示依赖原则
  • 属性注入
  • 方法注入

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

  • AddTransient:(服务级别的)每次注入或请求时都会转瞬即逝的服务(每次访问Services都会创建一个实例对象)。
  • AddScoped:(会话级别的)是按照范围创建的,在Web应用程序中,每个Web请求都会创建一个新的服务范围(每次访问的HTTP范围内使用的是同一个对象,然后到下一个接口又会产生一个新的对象)。
  • AddSingleton:(容器/项目级别的)每个DI容器创建一个单例服务,通常意味着他们在每个应用程序只创建一次,然后用于整个应用程序生命周期。

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

  • 依赖注入实现了new,不是为了省去一个new!
  • 修改配置文件不需要重启服务器(配置到文件中)。
  • 减少代码量,更灵活。
  • 防止重构——参数的变化
  • 忽略内部复杂依赖(不管我依赖的内容里面又依赖了什么,这个咱们不管的)
  • 项目代码松耦合
  • 管理生命周期——防止内存泄漏
  • 单元测试——Mock
  • 方便进行代理——AOP

1.3.6-依赖注入步骤



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

1.4.1-什么是AOP?

  • AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译的方式和运行代码实现程序功能的同意维护的一种技术。
  • AOP是OOP(面向对象程序设计)的延续。是软件开发中的一个热点,是函数式编程的一种衍生泛型,利用AOP可以对业务逻辑的各个部分进行隔离,从而是业务逻辑各部分之间进行隔离,从而是业务逻辑个部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

1.4.2-AOP的特点?

  • 分散的
  • 毫无关联的(有关联、可拔插)
  • 却是又有联系的
  • 关注点的不同导致切面的产生。

1.4.3-思想的来源

  • 面向过程编程——POP——c/c++:关注的是过程和行为,动作步骤
  • 面向对象编程——OOP——封装、继承、多态等概念来简历一种对象层次结构,用已模拟公共行为的一个集合。当我们需要分散的对象引入公共行为的时候,OOP则显得无能为力:具备功能的对象、分工(解决面向过程总耦合的问题、面向过程关注的是事件,太多太复杂)。
  • 面向抽象编程——接口
  • Gof四人23中设计模式——还是OOP的方位
  • 面向切面编程:解决面向对象编程中,出现的那些不是自己公共行文的一些行为

1.4.4-AOP只是流程

  • Join Point:连接点、关注点
  • Pointcut:切点——我们日志功能和服务相交叉的点。
  • Aspect:切面——日志记录、异常处理就是一个一个的切面。
  • Advice:通知——访问前、中、后的三个步骤

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

  • 日志
  • 事务
  • 缓存
  • 异常处理
  • 性能优化

1.4.6-多种思想应用的区别

1.4.7-AOP有哪些优势?

  • 隔离:核心和关注点,减少关联的错误。
  • 可以深入到具体的对象内部,各种操作。
  • 动态修改静态的OO模型,快速迭代。

1.4.8-AOP的使用

1.5-DTO与多模型

1.5.1-什么是DTO?

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

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

  • 简洁直观
  • 数据安全性:业务和UI解耦,防止错误——表现层不引用Model层的东西
  • 更精简——领域模型带有业务
  • 效率更好——扁平化
  • 跨平台——多平台的字符类型不一致

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

  • 相同点:

    • Dto和ViewModel都是将数据从数据库中拿出来进行前端展示的。
  • 不同点:
    • ViewModel视图模型比DTO数据模型更靠近页面。

1.5.5-多种模型概论

  • BO(Business object)——业务对象:主要作用是把业务逻辑封装成一个对象,这个对象可以包括一个或者多个其他的对象。
  • DAO(data sccess object)——数据访问对象
  • DO(domain object)——领域对象
  • DTO(data tansfer object)——数据传输对象
  • PO(persistant object)持有对象——从db拿出来的展示数据,没有操作
  • POCO(plain old CLR Object)——简单无规则CLR对象
  • VO(View Object)——视图对象:用于展示层,他的作用就是吧某个指定页面(组件)的所有数据封装起来。

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方法。

  protected override void Load(ContainerBuilder builder)
{
var basePath = AppContext.BaseDirectory; #region 带有接口层的服务注入
var servicesDllFile = Path.Combine(basePath, "Autofac.Service.dll");
var repositoryDllFile = Path.Combine(basePath, "Autofac.Repository.dll"); if (!(File.Exists(servicesDllFile) && File.Exists(repositoryDllFile)))
{
var msg = "Repository.dll和service.dll 丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查 bin 文件夹,并拷贝。";
throw new Exception(msg);
} // 获取 Service.dll 程序集服务,并注册
var assemblysServices = Assembly.LoadFrom(servicesDllFile);
builder.RegisterAssemblyTypes(assemblysServices)
.AsImplementedInterfaces()
.InstancePerDependency(); // 获取 Repository.dll 程序集服务,并注册
var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
builder.RegisterAssemblyTypes(assemblysRepository)
.AsImplementedInterfaces()
.PropertiesAutowired()
.InstancePerDependency();
#endregion
}

(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】中根节点写入一下配置。

"IpRateLimiting": {
"EnableEndpointRateLimiting": true, //false: 全局执行API——true:针对每个API
"StackBlockedRequests": false, //False:应在另一个计数器上记录拒绝次数
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"IpWhitelist": [], //添加白名单
"EndpointWhitelist": [ "get:/api/xxx", "*:/api/yyy" ],//添加API的白名单
"ClientWhitelist": [ "dev-client-1", "dev-client-2" ],//添加客户端的白名单
"QuotaExceededResponse": {
"Content": "{{\"status\":429,\"msg\":\"时间限流:访问过于频繁,请稍后重试\",\"success\":false}}",
"ContentType": "application/json",
"StatusCode": 429
},
"HttpStatusCode": 429, //返回状态码
"GeneralRules": [ //api规则,结尾一定要带*
{
//针对blog的API,1分钟最多访问20次
"Endpoint": "*:/api/blog*", //规则
"Period": "1m", //时间
"Limit": 20 //次数
},
{
//无论什么API,1秒最能请求3次
"Endpoint": "*/api/*",
"Period": "1s",
"Limit": 3
},
{
//无论什么API,1分钟最能请求30次
"Endpoint": "*/api/*",
"Period": "1m",
"Limit": 30
},
{
//无论什么API,12小时秒最能请求50次
"Endpoint": "*/api/*",
"Period": "12h",
"Limit": 500
}
]
}

(5)写一个中间件,用于IP限流。

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

(7)平凡请求接口时。

2.4-CORS跨域与"钓鱼"

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

  • 任意读取Dom

  • 任意执行JS脚本

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

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

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

(4)在【appsettings.json】中根节点写入一下配置。

  "Cors": {
"PolicyName": "CorsIpAccess", //策略名称
"EnableAllIPs": true, //当为true时,开放所有IP均可访问。
// 支持多个域名端口,注意端口号后不要带/斜杆:比如localhost:8000/,是错的
// 注意,http://127.0.0.1:1818 和 http://localhost:1818 是不一样的
"IPs": "http://127.0.0.1:2364,http://localhost:2364"
},

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

// CORS跨域
app.UseCors(Appsettings.app(new string[] { "Startup", "Cors", "PolicyName" }));

2.5-Swagger接口文文档

(1)导入Nuget包。

(2)创建【SwaggerSetup】类,启动Swagger服务。

  /// <summary>
/// Swagger 启动服务
/// </summary>
public static class SwaggerSetup
{
private static readonly ILog log =LogManager.GetLogger(typeof(SwaggerSetup)); public static void AddSwaggerSetup(this IServiceCollection services)
{
if (services == null)
throw new ArgumentNullException(nameof(services)); //获取项目的根路径
var basePath = AppContext.BaseDirectory;
//获取项目名
var ApiName = Appsettings.app(new string[] { "Startup", "ApiName" }); services.AddSwaggerGen(c =>
{
//遍历出全部的版本,做文档信息展示
typeof(ApiVersions).GetEnumNames().ToList().ForEach(version =>
{
c.SwaggerDoc(version, new OpenApiInfo
{
Version = version,
//RuntimeInformation.FrameworkDescription:运行时版本
Title = $"{ApiName} 西瓜程序猿 - 接口文档——{RuntimeInformation.FrameworkDescription}",
Description = $"{ApiName} HTTP API " + version,
//Contact:联系
//License:声明
});
c.OrderActionsBy(o => o.RelativePath);//接口排序
}); try
{
//这个就是刚刚配置的xml文件名【文档API的注释】
var xmlPath = Path.Combine(basePath, "Blog.Core.xml");
//默认的第二个参数是false,这个是controller的注释,记得修改
c.IncludeXmlComments(xmlPath, true);
//这个就是Model层的xml文件名【Model相关的注释】
var xmlModelPath = Path.Combine(basePath, "Blog.Core.Model.xml");
c.IncludeXmlComments(xmlModelPath);
}
catch (Exception ex)
{
log.Error("Blog.Core.xml和Blog.Core.Model.xml 丢失,请检查并拷贝。\n" + ex.Message);
} // 开启加权小锁
c.OperationFilter<AddResponseHeadersFilter>();
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>(); // 在header中添加token,传递到后台
c.OperationFilter<SecurityRequirementsOperationFilter>(); // ids4和jwt切换
if (Permissions.IsUseIds4)
{
//接入identityserver4
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri($"{Appsettings.app(new string[] { "Startup", "IdentityServer4", "AuthorizationUrl" })}/connect/authorize"),
Scopes = new Dictionary<string, string> {
{
"blog.core.api","ApiResource id"
}
}
}
}
});
}
else
{
// Jwt Bearer 认证,必须是 oauth2
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
Description = "描述:西瓜程序猿 - JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
Name = "Authorization",//jwt默认的参数名称
In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
Type = SecuritySchemeType.ApiKey
});
} });
}
} /// <summary>
/// 自定义版本
/// </summary>
public class CustomApiVersion
{
/// <summary>
/// Api接口版本 自定义
/// </summary>
public enum ApiVersions
{
/// <summary>
/// V1 版本
/// </summary>
V1 = 1,
/// <summary>
/// V2 版本
/// </summary>
V2 = 2,
}
}

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

(4)创建一个【UseSwaggerMildd】类,开启并处理Swagger中间件。

  private static readonly ILog log = LogManager.GetLogger(typeof(SwaggerMildd));
public static void UseSwaggerMildd(this IApplicationBuilder app, Func<Stream> streamHtml)
{
if (app == null) throw new ArgumentNullException(nameof(app)); app.UseSwagger();
app.UseSwaggerUI(c =>
{
//根据版本名称倒序 遍历展示
var ApiName = Appsettings.app(new string[] { "Startup", "ApiName" });
typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
{
c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{ApiName} {version}");
}); c.SwaggerEndpoint($"https://petstore.swagger.io/v2/swagger.json", $"{ApiName} pet"); // 将swagger首页,设置成我们自定义的页面,记得这个字符串的写法:{项目名.index.html}
if (streamHtml.Invoke() == null)
{
var msg = "index.html的属性,必须设置为嵌入的资源";
log.Error(msg);
throw new Exception(msg);
}
c.IndexStream = streamHtml; if (Permissions.IsUseIds4)
{
c.OAuthClientId("blogadminjs");
} // 路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc";
c.RoutePrefix = "";
});
}

(5)在【Startup.cs】中配置中间件,注意顺序。

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

2.6-MiniProfiler性能分析

(1)导入Nuget包。

(2)创建【AddMiniProfilerSetup】类,启动Swagger服务。

   public static void AddMiniProfilerSetup(this IServiceCollection services)
{ if (services == null) throw new ArgumentNullException(nameof(services));
if(Appsettings.app(new string[] { "Startup", "MiniProfiler", "Enabled" }).ObjToBool())
{
services.AddMiniProfiler();
} // 3.x使用MiniProfiler,必须要注册MemoryCache服务
// services.AddMiniProfiler(options =>
// {
// options.RouteBasePath = "/profiler";
// //(options.Storage as MemoryCacheStorage).CacheDuration = TimeSpan.FromMinutes(10);
// options.PopupRenderPosition = StackExchange.Profiling.RenderPosition.Left;
// options.PopupShowTimeWithChildren = true; // // 可以增加权限
// //options.ResultsAuthorize = request => request.HttpContext.User.IsInRole("Admin");
// //options.UserIdProvider = request => request.HttpContext.User.Identity.Name;
// }
//);
}

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

(4)创建一个【UseMiniProfilerMildd】类,开启并处理Swagger中间件。

   private static readonly ILog log = LogManager.GetLogger(typeof(MiniProfilerMildd));
public static void UseMiniProfilerMildd(this IApplicationBuilder app)
{
if (app == null) throw new ArgumentNullException(nameof(app)); try
{
if (Appsettings.app("Startup", "MiniProfiler", "Enabled").ObjToBool())
{
// 性能分析
app.UseMiniProfiler(); }
}
catch (Exception e)
{
log.Error($"An error was reported when starting the MiniProfilerMildd.\n{e.Message}");
throw;
}
}

(5)在【Startup.cs】中配置中间件,注意顺序。

2.7-StackEx.Redis安装与使用

(1)导入Nuget包。

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

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

(4)创建一个名为【IRedisCacheManager】接口,用于Redis缓存。

  /// <summary>
/// Redis缓存接口
/// </summary>
public interface IRedisCacheManager
{
//获取 Reids 缓存值
string GetValue(string key); //获取值,并序列化
TEntity Get<TEntity>(string key); //保存
void Set(string key, object value, TimeSpan cacheTime); //判断是否存在
bool Get(string key); //移除某一个缓存值
void Remove(string key); //全部清除
void Clear();
}

(5)创建一个【RedisCacheManager】类,并实现【IRedisCacheManager】接口

public class RedisCacheManager : IRedisCacheManager
{ private readonly string redisConnenctionString;
public volatile ConnectionMultiplexer redisConnection;
private readonly object redisConnectionLock = new object(); public RedisCacheManager()
{
string redisConfiguration = Appsettings.app(new string[] { "AppSettings", "RedisCachingAOP", "ConnectionString" });//获取连接字符串 if (string.IsNullOrWhiteSpace(redisConfiguration))
{
throw new ArgumentException("Redis配置为空", nameof(redisConfiguration));
}
this.redisConnenctionString = redisConfiguration;
this.redisConnection = GetRedisConnection();
} /// <summary>
/// 核心代码,获取连接实例
/// 通过双if 夹lock的方式,实现单例模式
/// </summary>
/// <returns></returns>
private ConnectionMultiplexer GetRedisConnection()
{
//如果已经连接实例,直接返回
if (this.redisConnection != null && this.redisConnection.IsConnected)
{
return this.redisConnection;
}
//加锁,防止异步编程中,出现单例无效的问题
lock (redisConnectionLock)
{
if (this.redisConnection != null)
{
//释放redis连接
this.redisConnection.Dispose();
}
try
{
var config = new ConfigurationOptions
{
AbortOnConnectFail = false,
AllowAdmin = true,
ConnectTimeout = 15000,//改成15s
SyncTimeout = 5000,
//Password = "Pwd",//Redis数据库密码
EndPoints = { redisConnenctionString }// connectionString 为IP:Port 如”192.168.2.110:6379”
};
this.redisConnection = ConnectionMultiplexer.Connect(config);
}
catch (Exception)
{
throw new Exception("Redis服务未启用,请开启该服务,并且请注意端口号,本项目使用的的6319,而且我的是没有设置密码。");
}
}
return this.redisConnection;
} /// <summary>
/// 清除
/// </summary>
public void Clear()
{
foreach (var endPoint in this.GetRedisConnection().GetEndPoints())
{
var server = this.GetRedisConnection().GetServer(endPoint);
foreach (var key in server.Keys())
{
redisConnection.GetDatabase().KeyDelete(key);
}
}
} /// <summary>
/// 判断是否存在
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool Get(string key)
{
return redisConnection.GetDatabase().KeyExists(key);
} /// <summary>
/// 查询
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string GetValue(string key)
{
return redisConnection.GetDatabase().StringGet(key);
} /// <summary>
/// 获取
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="key"></param>
/// <returns></returns>
public TEntity Get<TEntity>(string key)
{
var value = redisConnection.GetDatabase().StringGet(key);
if (value.HasValue)
{
//需要用的反序列化,将Redis存储的Byte[],进行反序列化
return SerializeHelper.Deserialize<TEntity>(value);
}
else
{
return default(TEntity);
}
} /// <summary>
/// 移除
/// </summary>
/// <param name="key"></param>
public void Remove(string key)
{
redisConnection.GetDatabase().KeyDelete(key);
} /// <summary>
/// 设置
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="cacheTime"></param>
public void Set(string key, object value, TimeSpan cacheTime)
{
if (value != null)
{
//序列化,将object值生成RedisValue
redisConnection.GetDatabase().StringSet(key, SerializeHelper.Serialize(value), cacheTime);
}
} /// <summary>
/// 增加/修改
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool SetValue(string key, byte[] value)
{
return redisConnection.GetDatabase().StringSet(key, value, TimeSpan.FromSeconds(120));
} }

(6)修改【appsetting.json】配置文件。


(4)创建一个【UseSwaggerMildd】类,开启并处理Swagger中间件。

  private static readonly ILog log = LogManager.GetLogger(typeof(SwaggerMildd));
public static void UseSwaggerMildd(this IApplicationBuilder app, Func<Stream> streamHtml)
{
if (app == null) throw new ArgumentNullException(nameof(app)); app.UseSwagger();
app.UseSwaggerUI(c =>
{
//根据版本名称倒序 遍历展示
var ApiName = Appsettings.app(new string[] { "Startup", "ApiName" });
typeof(ApiVersions).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
{
c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{ApiName} {version}");
}); c.SwaggerEndpoint($"https://petstore.swagger.io/v2/swagger.json", $"{ApiName} pet"); // 将swagger首页,设置成我们自定义的页面,记得这个字符串的写法:{项目名.index.html}
if (streamHtml.Invoke() == null)
{
var msg = "index.html的属性,必须设置为嵌入的资源";
log.Error(msg);
throw new Exception(msg);
}
c.IndexStream = streamHtml; if (Permissions.IsUseIds4)
{
c.OAuthClientId("blogadminjs");
} // 路径配置,设置为空,表示直接在根域名(localhost:8001)访问该文件,注意localhost:8001/swagger是访问不到的,去launchSettings.json把launchUrl去掉,如果你想换一个路径,直接写名字即可,比如直接写c.RoutePrefix = "doc";
c.RoutePrefix = "";
});
}

(5)在【Startup.cs】中配置中间件,注意顺序。

原文链接:https://www.cnblogs.com/kimiliucn/p/17641252.html

.NET Core基础到实战案例零碎学习笔记的更多相关文章

  1. 深挖计算机基础:MySQL实战45讲学习笔记

    参考极客时间专栏<MySQL实战45讲>学习笔记 一.基础篇(8讲) MySQL实战45讲学习笔记:第一讲 MySQL实战45讲学习笔记:第二讲 MySQL实战45讲学习笔记:第三讲 My ...

  2. 版本控制,svn基础,实战案例,RPM打包

                                                   版本控制,svn基础,实战案例,RPM打包 案例1:Subversion基本操作 案例2:使用Subver ...

  3. Spring实战第八章学习笔记————使用Spring Web Flow

    Spring实战第八章学习笔记----使用Spring Web Flow Spring Web Flow是一个Web框架,它适用于元素按规定流程运行的程序. 其实我们可以使用任何WEB框架写流程化的应 ...

  4. 《SAS编程和数据挖掘商业案例》学习笔记# 19

    继续<SAS编程与数据挖掘商业案例>学习笔记,本文側重数据处理实践.包含:HASH对象.自己定义format.以及功能强大的正則表達式 一:HASH对象 Hash对象又称散列表,是依据关键 ...

  5. #Spring实战第二章学习笔记————装配Bean

    Spring实战第二章学习笔记----装配Bean 创建应用对象之间协作关系的行为通常称为装配(wiring).这也是依赖注入(DI)的本质. Spring配置的可选方案 当描述bean如何被装配时, ...

  6. Spring实战第一章学习笔记

    Spring实战第一章学习笔记 Java开发的简化 为了降低Java开发的复杂性,Spring采取了以下四种策略: 基于POJO的轻量级和最小侵入性编程: 通过依赖注入和面向接口实现松耦合: 基于切面 ...

  7. Docker技术入门与实战 第二版-学习笔记-10-Docker Machine 项目-2-driver

    1>使用的driver 1〉generic 使用带有SSH的现有VM/主机创建机器. 如果你使用的是机器不直接支持的provider,或者希望导入现有主机以允许Docker Machine进行管 ...

  8. Docker技术入门与实战 第二版-学习笔记-8-网络功能network-3-容器访问控制和自定义网桥

    1)容器访问控制 容器的访问控制,主要通过 Linux 上的 iptables防火墙来进行管理和实现. iptables是 Linux 上默认的防火墙软件,在大部分发行版中都自带. 容器访问外部网络 ...

  9. 《SAS编程与数据挖掘商业案例》学习笔记之十六

    <SAS编程与数据挖掘商业案例>学习笔记,本次重点:sas宏变量 内容包含:宏变量.宏函数.宏參数.通配函数.字符函数.计算函数.引用函数.宏语句.宏应用 1.宏触发器: %name-to ...

  10. MySQL实战45讲学习笔记:第三十九讲

    一.本节概况 MySQL实战45讲学习笔记:自增主键为什么不是连续的?(第39讲) 在第 4 篇文章中,我们提到过自增主键,由于自增主键可以让主键索引尽量地保持递增顺序插入,避免了页分裂,因此索引更紧 ...

随机推荐

  1. 2021-04-18:给定一个二维数组matrix,里面的值不是1就是0,上、下、左、右相邻的1认为是一片岛,返回matrix中岛的数量。

    2021-04-18:给定一个二维数组matrix,里面的值不是1就是0,上.下.左.右相邻的1认为是一片岛,返回matrix中岛的数量. 福大大 答案2021-04-18: 并查集. 代码用gola ...

  2. laravel ServiceProvider 服务提供者使用案例

    1. 实例化一个类 2.全局注册这个类 3.在控制器中使用 public function register() { $this->app->singleton('wxminapp', f ...

  3. 记一次,使用python实现一键在爱发电发布带图片的动态

    1.背景 本人喜欢转载一些youtube上的视频到b站上面,然后就会有些观众想要视频的封面,那我总不可能一个一个发吧,太麻烦了.故打算将资源发布到爱发电上面.但是爱发电却没有公开对应的api,只能自己 ...

  4. 【Python笔记】第一章Python基本语法

    嗨你好,我是AllenMi, 这是我学习北京理工大学的<Python语言程序设计>第一张笔记. 写笔记的目的一方面在于记录自己一步一步学习Python的内容, 另一方面也希望能够帮助到他人 ...

  5. springsecurity 认证,授权,注销,动态菜单,记住我和首页定制

    搭建环境: 1.在创建springboot时选择组件web,thymeleaf,spring-security 2.导入静态资源,导入后测试一下环境  认证和授权: 继承类WebSecurityCon ...

  6. 2023最新IntellJ IDEA诺依SpringCloud开发部署文档(保姆级别)

    目录 若依RuoYi v3.6.2部署文档 一.环境构建 二.模块描述 三.部署后端 1.下载到本地. 2.MySQL导入数据. 3.Nacos修改 (1)保证本地Nacos下载安装成功,修改本地Na ...

  7. Python 列表、字典、元组的一些小技巧

    1. 字典排序 我们知道 Python 的内置 dictionary 数据类型是无序的,通过 key 来获取对应的 value.可是有时我们需要对 dictionary 中的 item 进行排序输出, ...

  8. python里class(类)中object是什么意思

    python的class(类)中的object是什么意思? 写object和不写object有什么区别? 示例代码 class Test: name = "libai" class ...

  9. Linq的所有用法(简单化)

    Linq 是一种强大的查询语言,可以过滤.排序和组合各种数据源.下面我们将讨论 Linq 的各种用法. Linq 的基本语法: Linq 可以应用于任何对象集合,以下是一个示例: var number ...

  10. CANoe学习笔记(一):创建第一个仿真工程(基于CAN):点灯

    目录 内容: ①创建两个节点,Switch和Light节点 ②创建两个Panel界面 ③capl代码实现Switch控制Light亮灭 事先准备: 养成良好的习惯,将不同文件放入不同文件夹,创建如下几 ...