zoukankan      html  css  js  c++  java
  • 第十六节:Asp.Net Core中Session的使用、扩展、进程外Session

    一. 简介

       关于Session的原理可参照Asp.Net版本Session的文章,去查阅。

    1. 普通用法

     (1).通过Nuget引入【Microsoft.AspNetCore.Http】程序集,Core Mvc中已经默认引入了,在哪使用using一下即可。

     (2).注入Session相关的服务。

      A:在ConfigureService注册基于服务器内存的Session, services.AddDistributedMemoryCache(); services.AddSession(); 在Configure中进行启用Session,app.UseSession();

        注:一定要在mvc前面进行注入,进程外Session的注入后面介绍。

      B:如果项目中使用了CookiePolicyOptions,一定要将里面true改为false,如: options.CheckConsentNeeded = context => false; 或者配置Session的性质,options.Cookie.IsEssential = true;(表示cookie是必须的),否则chrome中拿不到Session值

     解释:这是个GDRP条例,让用户自己选择使用用cookie,详见 http://www.zhibin.org/archives/667 或 https://www.cnblogs.com/GuZhenYin/p/9154447.html

      C:在控制器中通过 HttpContext.Session 来向Session中读写各种值。

    注册和启用相关的代码:

     1  public void ConfigureServices(IServiceCollection services)
     2  {
     3             services.Configure<CookiePolicyOptions>(options =>
     4             {
     5                 // This lambda determines whether user consent for non-essential cookies is needed for a given request.
     6                 options.CheckConsentNeeded = context => false;       //改为false或者直接注释掉,上面的Session才能正常使用
     7                 options.MinimumSameSitePolicy = SameSiteMode.None;
     8             });
     9             //注册Session服务
    10             //基于内存的Session
    11             services.AddDistributedMemoryCache();
    12             //默认过期时间为20分钟,每次访问都会重置
    13             services.AddSession();
    14 
    15             services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    16   }
    17   public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    18   {
    19             if (env.IsDevelopment())
    20             {
    21                 app.UseDeveloperExceptionPage();
    22             }
    23             else
    24             {
    25                 app.UseExceptionHandler("/Home/Error");
    26             }
    27             app.UseStaticFiles();
    28             app.UseCookiePolicy();
    29             //启用Session管道
    30             app.UseSession();
    31 
    32             app.UseMvc(routes =>
    33             {
    34                 routes.MapRoute(
    35                     name: "default",
    36                     template: "{controller=CoreSession}/{action=Index6}/{id?}");
    37             });
    38   }

    测试代码:

     1       public IActionResult Index()
     2         {
     3             string userName = HttpContext.Session.GetString("userName");
     4             if (string.IsNullOrEmpty(userName))
     5             {
     6                 userName = "ypf";
     7                 HttpContext.Session.SetString("userName", userName);
     8             }
     9             var t1 = HttpContext.Session.GetString("userName");
    10             ViewBag.userName = userName;
    11             return View();
    12         }
    13 
    14         public IActionResult Index2()
    15         {
    16             string userName = HttpContext.Session.GetString("userName");
    17             ViewBag.userName = userName;
    18             return View();
    19         }

    补充Session默认提供的方法:

    2. 全局注册使用

    (1).背景:通常便于管理,我们将Session进行全局统一注入,方便管理。

    (2).步骤:

      A: 在普通用法的前提下,在ConfigureService中进行统一对象的注册, services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

      B:在控制器利用构造函数进行注入。

      C:正常使用即可,案例详见项目的Index3和Index4

    代码分享:

     

     1  public class CoreSessionController : Controller
     2     {
     3         private readonly IHttpContextAccessor httpContextAccessor;
     4 
     5         private ISession MySession => httpContextAccessor.HttpContext.Session;
     6 
     7         public CoreSessionController(IHttpContextAccessor httpContextAccessor)
     8         {
     9             this.httpContextAccessor = httpContextAccessor;
    10         }
    11         #region 02-测试统一注入的用法
    12         /// <summary>
    13         /// 下面是统一注入使用的写法
    14         /// </summary>
    15         /// <returns></returns>
    16 
    17         public IActionResult Index3()
    18         {
    19             string userName = MySession.GetString("userName");
    20             if (string.IsNullOrEmpty(userName))
    21             {
    22                 userName = "ypf";
    23                 MySession.SetString("userName", userName);
    24             }
    25             var t1 = MySession.GetString("userName");
    26             ViewBag.userName = userName;
    27             return View();
    28         }
    29 
    30         public IActionResult Index4()
    31         {
    32             string userName = MySession.GetString("userName");
    33             ViewBag.userName = userName;
    34             return View();
    35         }
    36         #endregion
    37 
    38     }

    二. 高级

    1. Session的扩展

    (1).背景

      我们发现系统默认提供的Session方法,仅能存储byte、string、int类型,很不灵活,我们想能存储任何对象,这个时候就需要我们自行扩展。 对SessionExtensions类进行扩展

    (2).利用Newtonsoft.Json进行扩展

      A. 扩展代码详见SessionExtensions中的Set和Get方法

      B. 案例详见Index5

    (3).利用protobuf-net进行扩展

      A. 通过Nuget安装程序集【protobuf-net】,这是谷歌的一个程序集,序列化和反序列效率更高

      B. 扩展代码详见SessionExtensions中的Set2和Get2方法, 如果写入的是个类,类名上要加 [ProtoContract],属性上要加 [ProtoMember(1)] [ProtoMember(2)]等等, 如:UserInfor2

      C. 案例详见Index6

    扩展代码:

     1   public static class SessionExtensions
     2     {
     3         #region 01-利用Newtonsoft.Json进行扩展
     4         public static void Set<T>(this ISession session, string key, T value)
     5         {
     6             session.SetString(key, JsonConvert.SerializeObject(value));
     7         }
     8 
     9         public static T Get<T>(this ISession session, string key)
    10         {
    11             var value = session.GetString(key);
    12             return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
    13         }
    14         #endregion
    15 
    16         #region 02-利用protobuf-net进行扩展
    17         public static void Set2<T>(this ISession session, string key, T value)
    18         {
    19             using (MemoryStream stream = new MemoryStream())
    20             {
    21                 Serializer.Serialize(stream, value);
    22                 byte[] byteArrary = stream.ToArray();
    23                 session.Set(key, byteArrary);
    24             }
    25         }
    26 
    27         public static T Get2<T>(this ISession session, string key)
    28         {
    29             byte[] byteArray = session.Get(key);
    30             if (byteArray == null)
    31             {
    32                 return default(T);
    33             }
    34             else
    35             {
    36                 using (MemoryStream stream = new MemoryStream(byteArray))
    37                 {
    38                     return Serializer.Deserialize<T>(stream);
    39                 }
    40             }
    41         }
    42         #endregion
    43     }

    类代码:

     1  public class UserInfor1
     2     {
     3         public string id { get; set; }
     4         public string userName { get; set; }
     5     }
     6     [ProtoContract]
     7     public class UserInfor2
     8     {
     9         [ProtoMember(1)]
    10         public string id { get; set; }
    11         [ProtoMember(2)]
    12         public string userName { get; set; }
    13 
    14     }

    测试代码:

     1   #region 03-测试Newtonsoft.Json进行扩展
     2         public IActionResult Index5()
     3         {
     4             UserInfor1 user = HttpContext.Session.Get<UserInfor1>("u1");
     5             if (user == null)
     6             {
     7                 user = new UserInfor1();
     8                 user.id = "001";
     9                 user.userName = "Marren";
    10                 HttpContext.Session.Set<UserInfor1>("u1", user);
    11             }
    12             ViewBag.id = user.id;
    13             ViewBag.userName = user.userName;
    14             return View();
    15         }
    16         #endregion
    17 
    18         #region 04-测试protobuf-net进行扩展
    19         public IActionResult Index6()
    20         {
    21             UserInfor2 user = HttpContext.Session.Get2<UserInfor2>("u2");
    22             if (user == null)
    23             {
    24                 user = new UserInfor2();
    25                 user.id = "001";
    26                 user.userName = "Marren";
    27                 HttpContext.Session.Set2<UserInfor2>("u2", user);
    28             }
    29             ViewBag.id = user.id;
    30             ViewBag.userName = user.userName;
    31             return View();
    32         }
    33         #endregion

    2.Session的性质

    (1). Session的过期时间(多次访问将会被重置,默认过期时间为20分钟)

      如:options.IdleTimeout = TimeSpan.FromMinutes(120);

    (2). 设置为true表示前端js等脚本无法读取cookie,防止了xss攻击(默认是true)

      如:options.Cookie.HttpOnly = true;

    (3). Cookie是必须的(默认是false),可以覆盖上面的cookie策略

      如:options.Cookie.IsEssential = true;

    3. 如何在普通类中使用Session对象?

    (1).说明

      再普通类中如何调用Session,大约有两种思路:以构造函数的注入进去,但是如果这个类不是过滤器,使用的时候就需要实例化,又需要传入对象进去,如CheckLogin类,很麻烦,所以建议用第二种方案,直接吧实例好的Session传入进去,直接使用即可,如CheckLogin2.

    (2). 方案一

      先统一注入, services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();,然后再在控制器中进行构造函数注入,但调用的时候还需要传入进去。

    PS:过滤器中可以直接context.httpContext.Session来设置

    (3). 方案二

      直接把实例好的Session传进去

     1  public class CheckLogin2
     2     {
     3         private ISession MySession { get; set; }
     4 
     5         public CheckLogin2(ISession mySession)
     6         {
     7             MySession = mySession;
     8         }
     9         public bool isLogin()
    10         {
    11             string userName = MySession.GetString("userName");
    12             if (string.IsNullOrEmpty(userName))
    13             {
    14                 return false;
    15             }
    16             return true;
    17         }
    18     }

    三. 进程外Session

       关于进程外Session的好处、解决了什么痛点问题,可以参考Asp.Net 中的进程外Session,去查阅。 (解决了IIS重启Session丢失的问题,解决了Session空间有限容易被挤爆的问题,但不能解决浏览器重启找不到Session的问题!)

      特别说明:基于SQLServer或Redis数据的进程外Session 的数据库方面的配置和前面分布式缓存章节数据库的配置完全相同,去查阅。

    1. 基于SQLServer

     (1). 安装【Microsoft.Extensions.Caching.SqlServer】程序集,如果是Core MVC程序,自带的Microsoft.AspNetCore.App包里已经涵盖了该程序集,无需重复安装。

     (2). 首先要有个目标数据库中(比如CacheDB数据库),然后以管理员身份cmd运行下面指令,会创建一张名叫“AspNetCoreSession”表,相应的Session信息都存在于这张表中。

           【dotnet sql-cache create "Server=localhost;User=sa;Password=123456;Database=CacheDB" dbo AspNetCoreSession】成功后会提示:Table and index were created successfully.

    PS:补充表的结构和含义, 分别是键、值、到期时刻(有问题)、滑动过期时间、绝对过期时间。

    (3). 将原先基于内存的Session代码( services.AddDistributedMemoryCache(); )替换成基于SqlServer的代码,如下:

     1             //01-基于内存的Session
     2             //services.AddDistributedMemoryCache();
     3 
     4             //02-基于SQLServer的Session
     5             services.AddDistributedSqlServerCache(options =>
     6             {
     7                 options.ConnectionString = Configuration["SqlSeverConnectionString"];
     8                 options.SchemaName = "dbo";
     9                 options.TableName = "AspNetCoreSession";
    10             });
    1 {
    2   "Logging": {
    3     "LogLevel": {
    4       "Default": "Warning"
    5     }
    6   },
    7   "AllowedHosts": "*",
    8   "SqlSeverConnectionString": "Server=localhost;User=sa;Password=123456;Database=CacheDB"
    9 }

    (4). 其它的配置都不变,正常使用即可。

    2. 基于Redis

     (1). 安装【Microsoft.Extensions.Caching.StackExchangeRedis】程序集,Core MVC中这个也是不包含的。

     (2). 下载Redis程序,打开redis-server.exe,启动Redis。

     

    (3). 将原先基于内存的Session代码 ( services.AddDistributedMemoryCache(); ) 替换成基于Redis的代码,如下:

                //01-基于内存的Session
                //services.AddDistributedMemoryCache();
    
                //03-基于Redis的Session
                services.AddStackExchangeRedisCache(options =>
                {
                    options.Configuration = "localhost";
                    options.InstanceName = "SampleInstance";
                });

    (4). 其它配置都不变,正常使用即可。

     

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    form 组件
    Django相关
    python日常总结
    django Form 表单 总结与小实例
    django Form验证
    Django ORM OneToOneField
    display:inline与display:block——行内元素显示与块级元素显示
    HTML5之概述
    <a>标签的href属性
    php安全性问题
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/11270816.html
Copyright © 2011-2022 走看看