asp.net core系列 43 Web应用 Session分布式存储(in memory与Redis)

一.概述

  HTTP 是无状态的协议。 默认情况下,HTTP 请求是不保留用户值或应用状态的独立消息。 本文介绍了几种保留请求间用户数据和应用状态的方法。下面以表格形式列出这些存储方式,本篇专讲Session会话状态,计划下篇再讲应用状态。

存储方法

存储机制

Cookie HTTP Cookie(可能包括使用服务器端应用代码存储的数据)
Session 状态 HTTP Cookie 和服务器端应用代码
TempData HTTP Cookie 或Session状态
 查询字符串 HTTP 查询字符串
隐藏字段 HTTP 窗体字段
HttpContext.Items 服务器端应用代码
Cache 服务器端应用代码

依赖关系注入

服务器端应用代码

  1.1 Cookie

    Cookie是服务器产生ID的标签。是识别用户,实现持久会话的最好方式。Cookie分为两类:会话Cookie和持久Cookie。二者唯一区别是设置过期时间。

    (1)会话Cookie是临时的,当用户退出浏览器时,就会被删除。

    (2)持久Cookie生存时间更长,存储在硬盘上,当浏览器退出或计算机重启时它们仍然存在。

    Cookie跨请求存储数据,每次请求都会发送Cookie。Cookie的大小应该保持在最低限度。理想情况下,仅标识符存储在 Cookie 中。大多数浏览器 Cookie 大小限制为 4096 个字节。每个域仅有有限数量的 Cookie 可用,比如IE6.0每个域cookie个数最多为20个。

    下面看Cookie是如何工作的:

分享图片

    (a) 客户端首次Request请求Web站点时,Web服务器对客户端一无所知。

    (b) Web服务器通过Response报文的 Set-Cookie或Set-Cookie2产生标识Cookie id=”34294”,返回给客户端,客户端浏览器会存储该Cookie。

    (c) 当客户端再次Request请求时,带上Cookie,Web服务器就能识别该客户端,实现会话。

 

  1.2 Session (会话)介绍

    Session数据由缓存支持并被视为临时数据Session状态是用户浏览Web应用程序时,存储用户数据的ASP.NET Core方案。Session状态使用应用维护的存储,来保存客户端所有请求的数据ASP.NET Core通过向客户端提供包含Session ID的cookie来维护Session状态,该Session ID随每个请求一起发送到应用程序(Web服务器)。该应用程序使用Session ID来获取Session数据(Session数据存储在Web服务器上)Session会话状态以下主要行为:

         (1) 由于cookie Session是特定于浏览器的,因此不能跨浏览器共享会话。

    (2) 应用在上次请求后保留Session的时间有限。 应用程序可以设置Session超时,或者使用 20 分钟的默认值。

    (3) 建议不使用粘性会话,更好的方法是使用Redis或SQL Server分布式缓存,它不需要粘性会话。

  

  1.3  Session会话选项

    若要替代Session默认值,使用 SessionOptions (services.AddSession)。下面是主要选项,以及示例:

选项 说明
Cookie 确定用于创建 Cookie 的设置。名称默认为.AspNetCore.Session
IdleTimeout 空闲多长时间Session重置。 此设置仅适用于Session内容,不适用于 Cookie。 默认为 20 分钟。
IOTimeout 允许从存储加载会话或者将其提交回存储的最大时长。 此设置可能仅适用于异步操作。 可以使用 InfiniteTimeSpan 禁用超时。 默认值为 1 分钟
     //选项配置
     services.AddSession(options =>
      {
          options.Cookie.Name = ".AdventureWorks.Session";
          options.IdleTimeout = TimeSpan.FromSeconds(10);
      });

 

   1.4 Session设置和获取值

    在 Microsoft.AspNetCore.Session 包中提供中间件来管理Session状态。 若要启用Session中间件,Startup 必须包含如下:

    (1) 任何IDistributedCache内存缓存。该IDistributedCache实现用作Session的后备存储,下面会讲到分布式缓存在 ASP.NET Core 中。

    (2) 对 ConfigureServices 方法中 AddSession 的调用。

    (3) 对 Configure 中 UseSession(); 的调用。

 

二. Session存储 in memory

  在 ASP.NET Core中,分布式缓存无论使用in memory、SQL Server、Redis都需要应用程序使用IDistributedCache接口与缓存进行交互。Session存储在in memory中,称为”分布式内存缓存”(AddDistributedMemoryCache)。是框架提供的IDistributedCache实现。注意:分布式内存缓存不是实际的分布式缓存,该缓存是存储在运行应用程序的服务器上。

   运用场景一般用在开发或测试中。也可以用在生产环境下,但必须是内存消耗不高并且应用程序是单个节点(没有Web分发负载)。

 

  2.1 Startup文件配置session

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
           //..
            services.AddDistributedMemoryCache();
            services.AddHttpContextAccessor();
            services.AddSession(options =>
            {
                //空闲10秒后,session自动清空
                options.IdleTimeout = TimeSpan.FromSeconds(10);
                options.Cookie.HttpOnly = true; });
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app,IHostingEnvironment env)
    {
       //..
       //顺序很重要,必须放在UseMvc之前。配置后HttpContext.Session可用
 app.UseSession();
        app.UseMvc();
    }
}

 

  2.2 使用属性 HttpContext.Session 从 Razor Pages PageModel 类或 MVC 控制器类访问会话状态。

  public class HomeController : Controller
    {
        private readonly IHttpContextAccessor _accessor;
        public HomeController( IHttpContextAccessor httpContextAccessor)
        {
            this._accessor = httpContextAccessor;
        }

        public IActionResult Index()
        {
            HttpContext.Session.SetString("SessionTest","Ben Rules!");
            return View();
        }
        
        public IActionResult Privacy()
        {
            ViewData["SessionTest"] = _accessor.HttpContext.Session.GetString("SessionTest");
            return View();
        }
    }

     先运行index页设置Session后,再运行Privacy页读取该Session。如下图:Session会话设置和获取值成功,再查看浏览器中的Cookies名称默认为.AspNetCore.Session。

分享图片

    

  2.3 Session数据序列化

    必须对所有Session数据进行序列化以启用分布式缓存方案,即使是在使用in memory缓存的时候。对于字符串和数据序列化以由ISession 扩展方法实现了。对于复杂类型,添加以下扩展方法以设置和获取可序列化的对象。

public static class SessionExtensions
{
    public static void Set<T>(this ISession session,string key,T value)
    {
        session.SetString(key,JsonConvert.SerializeObject(value));
    }

    public static T Get<T>(this ISession session,string key)
    {
        var value = session.GetString(key);

        return value == null ? default(T) : 
            JsonConvert.DeserializeObject<T>(value);
    }
}
    //以下示例演示如何使用扩展方法设置和获取可序列化的对象:
    HttpContext.Session.Set<DateTime>(SessionKeyTime,currentTime);

 

三.Session存储Redis

  Redis缓存比SQL Server缓存提供更高的吞吐量和更低的延迟。这里不在演示SQL Server存储,如果要用SQL Serverd存储,建议为分布式缓存提供专用的SQL Server实例(与应用程序的数据库实例分开)。

   3.1 Redis服务器

    关于redis的安装,这里不在介绍。

#启动redis服务成功
[[email protected] bin]# ./redis-server redis.conf

#启动redis客户端测试成功
[[email protected] bin]# ./redis-cli -h 172.168.18.200  -a 123456
127.0.0.1:6379> set msg "hello"
OK
127.0.0.1:6379> get msg
"hello"

   

  3.2 asp.net core应用端

    (1)演示项目是基于上面的in memory案例,先安装redis中间件。

    PM> Install-Package Microsoft.Extensions.Caching.Redis

    (2)将in memory改为redis存储,代码改动如下:

            //services.AddDistributedMemoryCache();
            services.AddDistributedRedisCache(options =>
            {
                options.Configuration = "172.168.18.200:6379,allowAdmin=true,password=123456,defaultdatabase=0";
            });
            services.AddHttpContextAccessor();
            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromSeconds(10);
                options.Cookie.HttpOnly = true;
            });
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    (3)设置和获取Session

      在HomeController类中,设置和获取Session,代码不变,可参考上面2.2。运行index页后,再运行Privacy页,Session会话设置和获取值成功,再使用redis工具查看已存储到了redis服务中(空闲10秒后,redis存储的session将自动清空)如下图所示:

分享图片

 

  参考资料

    ASP.NET Core 中的会话和应用状态

    Redis可视化管理

       分布式缓存在 ASP.NET Core 中

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


在开发中,有时候生成验证码的场景目前还是存在的,本篇演示不依赖第三方组件,生成随机验证码图片。 先添加验证码接口 public interface ICaptcha { /// &lt;summary&gt; /// 生成随机验证码 /// &lt;/summary&gt; /// &lt;para
后端技术 .net code 官方文档 https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/file-uploads?view=aspnetcore-3.1 上传方式:multipart/form-data 其他参数:Name,Versio
在上一篇文章中,我们比较出单表插入9999行数据,Freesql &gt;&#160;Dapper &gt; EfCore。在本文中,我们来看看级联插入 构建9999行数据 List&lt;Entity&gt; datas = new List&lt;Entity&gt;(); for (int i
需求:导入9999行数据时Dapper, Ef core, Freesql&#160;谁的性能更优,是如何执行的,级联增加谁性能更佳。 确认方法:sql server&#160;的 sys.dm_exec_query_stats SELECT TOP 1000 (select [text] from
资料整理 1.sp-api介绍:https://developer.amazonservices.com/ 2.github文档:https://github.com/amzn/selling-partner-api-docs 3.github代码:https://github.com/amzn/s
最近时间在整SM2算法,在网上看到不少代码,基本都是使用BouncyCastle库,现在这个版本算比较好的拿来分享给大家。 首先引入包&#160;Portable.BouncyCastle 完整代码见Gitee:https://gitee.com/Karl_Albright/CryptoHelper
在上文中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发、订阅和处理的流程。这种实现太简单了,百十行代码就展示了一个基本工作原理。然而,要将这样的解决方案运用到实际生产环境,还有很长的路要走。今天,我们就研究一下在事件处理器中,对象生命周期的管理问题。事实上,不仅仅是在事件处理器
上文已经介绍了Identity Service的实现过程。今天我们继续,实现一个简单的Weather API和一个基于Ocelot的API网关。 回顾 《Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(一)》 Weather API Weather
最近我为我自己的应用开发框架Apworks设计了一套案例应用程序,并以Apache 2.0开源,开源地址是:https://github.com/daxnet/apworks-examples,目的是为了让大家更为方便地学习和使用.NET Core、最新的前端开发框架Angular,以及Apwork
HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务端接口的耦合度。很多当今流行的RESTful API开发框架,包括Spring REST,也都默认支
在前面两篇文章中,我详细介绍了基本事件系统的实现,包括事件派发和订阅、通过事件处理器执行上下文来解决对象生命周期问题,以及一个基于RabbitMQ的事件总线的实现。接下来对于事件驱动型架构的讨论,就需要结合一个实际的架构案例来进行分析。在领域驱动设计的讨论范畴,CQRS架构本身就是事件驱动的,因此,
HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单、统一的形式,在API中引入超链接特性,使得API的可发现性(discoverable)更强,并具有自描述的特点。使用了HAL的API会更容易地被第三方开源库所调用,并且使用起来也很方便
何时使用领域驱动设计?其实当你的应用程序架构设计是面向业务的时候,你已经开始使用领域驱动设计了。领域驱动设计既不是架构风格(Architecture Style),也不是架构模式(Architecture Pattern),它也不是一种软件开发方法论,所以,是否应该使用领域驱动设计,以及什么时候使用
《在ASP.NET Core中使用Apworks快速开发数据服务》一文中,我介绍了如何使用Apworks框架的数据服务来快速构建用于查询和管理数据模型的RESTful API,通过该文的介绍,你会看到,使用Apworks框架开发数据服务是何等简单快捷,提供的功能也非常多,比如对Hypermedia的
在上一讲中,我们已经完成了一个完整的案例,在这个案例中,我们可以通过Angular单页面应用(SPA)进行登录,然后通过后端的Ocelot API网关整合IdentityServer4完成身份认证。在本讲中,我们会讨论在当前这种架构的应用程序中,如何完成用户授权。 回顾 《Angular SPA基于
Keycloak是一个功能强大的开源身份和访问管理系统,提供了一整套解决方案,包括用户认证、单点登录(SSO)、身份联合、用户注册、用户管理、角色映射、多因素认证和访问控制等。它广泛应用于企业和云服务,可以简化和统一不同应用程序和服务的安全管理,支持自托管或云部署,适用于需要安全、灵活且易于扩展的用
3月7日,微软发布了Visual Studio 2017 RTM,与之一起发布的还有.NET Core Runtime 1.1.0以及.NET Core SDK 1.0.0,尽管这些并不是最新版,但也已经从preview版本升级到了正式版。所以,在安装Visual Studio 2017时如果启用了
在上文中,我介绍了如何在Ocelot中使用自定义的中间件来修改下游服务的response body。今天,我们再扩展一下设计,让我们自己设计的中间件变得更为通用,使其能够应用在不同的Route上。比如,我们可以设计一个通用的替换response body的中间件,然后将其应用在多个Route上。 O
不少关注我博客的朋友都知道我在2009年左右开发过一个名为Apworks的企业级应用程序开发框架,旨在为分布式企业系统软件开发提供面向领域驱动(DDD)的框架级别的解决方案,并对多种系统架构风格提供支持。这个框架的开发和维护我坚持了很久,一直到2015年,我都一直在不停地重构这个项目。目前这个项目在
好吧,这个题目我也想了很久,不知道如何用最简单的几个字来概括这篇文章,原本打算取名《Angular单页面应用基于Ocelot API网关与IdentityServer4ʺSP.NET Identity实现身份认证与授权》,然而如你所见,这样的名字实在是太长了。所以,我不得不缩写“单页面应用”几个字