要将 ASP.NET Core 中的会话存储在 Redis 中,可以按照以下步骤进行操作:
安装必要的 NuGet 包:
首先,确保你已经安装了 Microsoft.Extensions.Caching.StackExchangeRedis 包,这是与 Redis 集成的主要包。
在 Visual Studio 中,你可以使用 NuGet 包管理器控制台执行以下命令:
Install-Package Microsoft.Extensions.Caching.StackExchangeRedis
配置 Redis 连接:
在你的 ASP.NET Core 应用程序的 Startup.cs 文件中,使用 AddStackExchangeRedisCache 方法配置 Redis 连接。在 ConfigureServices 方法中添加以下代码:
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "your_redis_connection_string";
options.InstanceName = "your_instance_name";
});
请将 "your_redis_connection_string" 替换为你的 Redis 连接字符串,并将 "your_instance_name" 替换为你的 Redis 实例名称。
配置会话中间件:
在 Startup.cs 的 ConfigureServices 方法中,使用 AddSession 方法配置会话中间件,并在 Configure 方法中启用它:
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(30); // 设置会话超时时间
});
使用会话中间件:
在 Startup.cs 的 Configure 方法中,在调用 app.UseRouting() 之前添加以下代码来启用会话中间件:
app.UseSession();
在控制器或视图中使用会话:
现在,你可以在控制器或视图中使用会话来存储和检索数据。例如:
// 存储数据到会话
HttpContext.Session.SetString("Key", "Value");
// 从会话中检索数据
var value = HttpContext.Session.GetString("Key");
通过这种方式,你可以将会话数据存储在 Redis 中,而不是默认的内存中。
请确保根据你的应用程序的需求进行适当的配置和安全措施,以确保 Redis 连接的安全性和可靠性。

ASP.NET Core 缓存 Caching 提供了包括但不限于以下几种存储方式:
内存缓存:https://xoyozo.net/Blog/Details/aspnetcore-memory-cache
SQL Server 缓存:https://xoyozo.net/Blog/Details/aspnetcore-sql-cache
Redis 缓存:https://xoyozo.net/Blog/Details/aspnetcore-redis-cache
MySQL 缓存:https://xoyozo.net/Blog/Details/aspnetcore-mysql-cache
本文介绍内存缓存
Memory Caching
1.新建一个 ASP.NET Core 项目,选择 Web 应用程序,将身份验证 改为 不进行身份验证。
2.添加引用
Install-Package Microsoft.Extensions.Caching.Memory
3.使用
在 Startup.cs 中 ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
// Add framework services.
services.AddMvc();
}
然后在
public class HomeController : Controller
{
private IMemoryCache _memoryCache;
public HomeController(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
public IActionResult Index()
{
string cacheKey = "key";
string result;
if (!_memoryCache.TryGetValue(cacheKey, out result))
{
result = $"LineZero{DateTime.Now}";
_memoryCache.Set(cacheKey, result);
}
ViewBag.Cache = result;
return View();
}
}
这里是简单使用,直接设置缓存。
我们还可以加上过期时间,以及移除缓存,还可以在移除时回掉方法。
过期时间支持相对和绝对。
下面是详细的各种用法。
public IActionResult Index()
{
string cacheKey = "key";
string result;
if (!_memoryCache.TryGetValue(cacheKey, out result))
{
result = $"LineZero{DateTime.Now}";
_memoryCache.Set(cacheKey, result);
//设置相对过期时间2分钟
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromMinutes(2)));
//设置绝对过期时间2分钟
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(2)));
//移除缓存
_memoryCache.Remove(cacheKey);
//缓存优先级 (程序压力大时,会根据优先级自动回收)
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.SetPriority(CacheItemPriority.NeverRemove));
//缓存回调 10秒过期会回调
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromSeconds(10))
.RegisterPostEvictionCallback((key, value, reason, substate) =>
{
Console.WriteLine($"键{key}值{value}改变,因为{reason}");
}));
//缓存回调 根据Token过期
var cts = new CancellationTokenSource();
_memoryCache.Set(cacheKey, result, new MemoryCacheEntryOptions()
.AddExpirationToken(new CancellationChangeToken(cts.Token))
.RegisterPostEvictionCallback((key, value, reason, substate) =>
{
Console.WriteLine($"键{key}值{value}改变,因为{reason}");
}));
cts.Cancel();
}
ViewBag.Cache = result;
return View();
}
Distributed Cache Tag Helper
在 ASP.NET Core MVC 中有一个 Distributed Cache 我们可以使用。
我们直接在页面上增加 distributed-cache 标签即可。
<distributed-cache name="mycache" expires-after="TimeSpan.FromSeconds(10)">
<p>缓存项10秒过期-LineZero</p>
@DateTime.Now
</distributed-cache>
<distributed-cache name="mycachenew" expires-sliding="TimeSpan.FromSeconds(10)">
<p>缓存项有人访问就不会过期,无人访问10秒过期-LineZero</p>
@DateTime.Now
</distributed-cache>
这样就能缓存标签内的内容。
An unhandled exception occurred while processing the request.
InvalidOperationException: RenderBody has not been called for the page at '/Areas/Admin/Views/Shared/_Layout.cshtml'. To ignore call IgnoreBody().
Microsoft.AspNetCore.Mvc.Razor.RazorPage.EnsureRenderedBodyOrSections()
解决方法一:
在 return; 前执行 IgnoreBody();
解决方法二:
不要在 @RenderBody() 之前执行 return;

首先在项目根目录中创建目录 Areas。
在 Areas 中添加区域,以“Admin”、“Console”两个区域为例:
VS 提醒在 Startup.cs 的 Configure() 方法中添加 app.UseMvc,此与 app.UseEndpoints 冲突,我们改为在 app.UseEndpoints 中添加 MapControllerRoute(放在 default 之前):
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "MyArea",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
给区域的控制器添加属性,如:
[Area("Admin")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}

打开 appsettings.json,添加一项配置(如下方示例中的“SiteOptions”项)
* 注意,如需配置开发环境与生产环境不同的值,可单独在 appsettings.Development.json 文件中配置不同项,格式层次须一致;
C# 中习惯用强类型的方式来操作对象,那么在项目根目录添加类(类名以 SiteOptions为例),格式与 appsettings.json 中保持一致:
public class SiteOptions
{
public ERPOptions ERP { get; set; }
public WeixinOpenOptions WeixinOpen { get; set; }
public WeixinMPOptions WeixinMP { get; set; }
public SMSOptions SMS { get; set; }
public AliyunOSSOptions AliyunOSS { get; set; }
/// <summary>
/// 单个文件上传的最大大小(MB)
/// </summary>
public int MaxSizeOfSigleFile_MB { get; set; }
/// <summary>
/// 单个文件上传的最大大小(字节)
/// </summary>
public int MaxSizeOfSigleFile_B => MaxSizeOfSigleFile_MB * 1024 * 1024;
public class ERPOptions
{
public int ChannelId { get; set; }
public string AppKey { get; set; }
}
public class WeixinOpenOptions
{
public string AppId { get; set; }
public string AppSecret { get; set; }
}
public class WeixinMPOptions
{
public string AppId { get; set; }
public string AppSecret { get; set; }
}
public class SMSOptions
{
public string AppKey { get; set; }
}
public class AliyunOSSOptions
{
public string Endpoint { get; set; }
public string AccessKeyId { get; set; }
public string AccessKeySecret { get; set; }
public string BucketName { get; set; }
/// <summary>
/// 格式://域名/
/// </summary>
public string CdnUrl { get; set; }
}
}
在 Startup 中注入 IConfiguration,并在 ConfigureServices() 方法中添加服务(注意使用 GetSection() 映射到自命名的“SiteOptions”项)
在控制器中使用:
在控制器类中键入“ctor”,并按两次 Tab 键,创建构造函数
在构造函数中注入“IOptions”,并在 Action 中使用
using Microsoft.Extensions.Options;
public class TestController : Controller
{
private readonly IOptions<SiteOptions> options;
public TestController(IOptions<SiteOptions> options)
{
this.options = options;
}
public IActionResult Index()
{
return View(options.Value.ERP.ChannelId.ToString());
}
}
在视图中使用:
@using Microsoft.Extensions.Options
@inject IOptions<SiteOptions> options
@options.Value.ERP.ChannelId


* 本文凡使用变量 httpContextAccessor 或 _httpContextAccessor 的地方都需要需要注入 Microsoft.AspNetCore.Http.IHttpContextAccessor
* 在视图(view)中应以 ViewContext 类引出
获取当前页面网址:
using Microsoft.AspNetCore.Http.Extensions;
string url = Request.GetDisplayUrl();
获取当前访问的域名和端口:
获取来源:
Request.GetTypedHeaders().Referer
判断 Scheme 是否为 https:
Request.IsHttps
获取客户端IP和端口、服务器IP和端口:
获取浏览器用户代理(UserAgent):
httpContextAccessor.HttpContext.Request.Headers[HeaderNames.UserAgent];
获取当前请求的唯一标识:
httpContextAccessor.HttpContext.TraceIdentifier
返回结果:80000564-0002-f700-b63f-84710c7967bb
用途:可作为生成随机数的种子。
获取客户端IP地址:
httpContextAccessor.HttpContext.Connection.RemoteIpAddress
获取当前项目根目录磁盘路径:
AppContext.BaseDirectory // 以“\”结尾
注意:此路径到项目根目录,而非网站根目录,网站根目录请自行追加,默认为 wwwroot\
编码/解码:(参数和返回值均为 string?)
using System.Net;
WebUtility.HtmlEncode(myString)
WebUtility.HtmlDecode(myString)
WebUtility.UrlEncode(myString)
WebUtility.UrlDecode(myString)
更多:https://xoyozo.net/Blog/Index/Core

本文环境:CentOS 7、nginx 1.16、ASP.NET Core 3.0
安装 nginx,可以使用宝塔面板。
创建网站,保证网站静态页面能够正常访问。
必要时配置 SSL 证书。
安装 ASP.NET Core 运行时:
安装说明见:https://dotnet.microsoft.com/download,切换到 Linux,选择 Install .NET Core Runtime
选择操作系统,按页面说明安装即可。
发布一个 ASP.NET Core 项目到网站目录,运行应用程序:
dotnet 应用的程序集文件名.dll
必须先 cd 到项目所在目录再执行,否则“Content root path”不会指向网站根目录,从而导致无法访问静态文件。
观察到端口为 5000(默认),该 Url 用于下一步设置反向代理。
配置 nginx 反向代理:(使用宝塔面板时建议使用面板中提供的“反向代理”功能)
location / { proxy_pass http://localhost:5000; }
查看官方详细说明:使用 Nginx 在 Linux 上托管 ASP.NET Core

当 MySQL 中使用 tinyint(1) 作为布尔值类型时,ASP.NET Core DBFirst 创建模型时会将其定义为 sbyte,运行时会抛出异常:
InvalidCastException: Unable to cast object of type 'System.Boolean' to type 'System.SByte'.
我们可以在数据库连接字符串中加入 TreatTinyAsBoolean=false 来实现不抛出异常,但程序中赋值和判断该字段时还是会比较麻烦。
因此我更倾向于将数据库中该字段类型改为 bit(1)。
2019.11.28 注:这回遇到 tinyint(1) 映射到了 C# 的 bool,而 bit(1) 却映射到了 ulong。具体什么原因未作排查,反正哪个最终为 bool 就选哪个吧。

本文使用 Pomelo 提供的 Pomelo.EntityFrameworkCore.MySql,如使用 MySql.Data.EntityFrameworkCore 请移步。
对比 MySql.Data.EntityFrameworkCore 与 Pomelo.EntityFrameworkCore.MySql
本文以 Visual Studio 2019、ASP.NET Core 3.0 开发环境为例。
新建 ASP.NET Core Web 应用程序。
安装 NuGet 包:
Microsoft.EntityFrameworkCore.Tools
Pomelo.EntityFrameworkCore.MySql(3.0.0 预发行版以上)
根据已有数据库创建数据模型。在 NuGet 的程序包管理(Package Manager)控制台中(PowerShell)执行命令:
Scaffold-DbContext "server=数据库服务器;uid=数据库用户名;pwd=数据库密码;database=数据库名;" Pomelo.EntityFrameworkCore.MySql -OutputDir Data -Force
.Net Core CLi:
dotnet ef dbcontext scaffold "server=数据库服务器;uid=数据库用户名;pwd=数据库密码;database=数据库名;" Pomelo.EntityFrameworkCore.MySql -o Data -f
搞定。
补充:其它数据库提供程序请参考:https://docs.microsoft.com/zh-cn/ef/core/providers/
代码参数说明:
-OutputDir (-o) *** 实体文件所存放的文件目录
-ContextDir *** DbContext文件存放的目录
-Context *** DbContext文件名
-Schemas *** 需要生成实体数据的数据表所在的模式
-Tables(-t) *** 需要生成实体数据的数据表的集合
-DataAnnotations
-UseDatabaseNames 直接使用数据库中的表名和列名(某些版本不支持)
-Force (-f) 强制执行,重写已经存在的实体文件
更多高级用法请参考官方文档。
