ASP.NET Core MVC 的 Session 使用方式

在寫網站的時候,一定會碰到使用 Session 的情況。而 ASP.NET Core MVC 使用的方式比較不同,以下將會說明。

前置作業

在使用 Session 之前,首先要透過 NuGet 安裝 Microsoft.AspNetCore.Session 套件,這樣 Session 物件才有 GetStringGetInt32 這兩個擴充方法可用。

之後在 Startup.cs 加修改下列函式:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    //setup session
    //add package "Microsoft.AspNetCore.Session" first
    services.AddDistributedMemoryCache();

    services.AddSession(options =>
    {
        // Set a short timeout for easy testing.
        options.IdleTimeout = TimeSpan.FromSeconds(10);
        options.Cookie.HttpOnly = true;
    });
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    //setup session
    app.UseSession();

    app.UseStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

開始使用 Session

在 ASP.NET Core MVC 中,Session 物件在 HttpContext.Session 底下,它有 GetString、GetInt32、SetString 及 SetInt32 這四個擴充方法可以用,這邊示範如何將字串存在 Session 中:

private string sessionKey = "session_key";
public IActionResult SetSession()
{
    HttpContext.Session.SetString(sessionKey, "Peter");
    return Content("OK");
}

public IActionResult GetSession()
{
    string content = string.Empty;
    if(HttpContext.Session.Keys.Contains(sessionKey))
    {
        content = HttpContext.Session.GetString(sessionKey);
    }

    return Content(content);
}

如果要存一般的物件,官方文件有提供下列方法:

using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;

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);
    }
}

但官方提供的做法是將物件轉為 JSON 字串後再存進去,如果是遇到 value type 的變數,恐怕會有問題,於是我又找了其它方式,也就是將變數轉為 byte array 後再存進去,方法如下:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;

namespace SessionDemoSite.Modules
{
    public static class SessionExtensions
    {
        public static void SetValue(this ISession session, string key, object obj)
        {
            if (obj != null)
            {
                BinaryFormatter bf = new BinaryFormatter();
                MemoryStream ms = new MemoryStream();
                bf.Serialize(ms, obj);
                session.Set(key, ms.ToArray());
            }
        }

        public static T GetValue<T>(this ISession session, string key)
        {
            byte[] arrBytes = session.Get(key);

            MemoryStream memStream = new MemoryStream();
            BinaryFormatter binForm = new BinaryFormatter();
            memStream.Write(arrBytes, 0, arrBytes.Length);
            memStream.Seek(0, SeekOrigin.Begin);
            T obj = (T)binForm.Deserialize(memStream);
            return obj;
        }
    }
}

上述的做法,不管是一般物件或是 value type 的變數,都可以順利的存在 Session 底下。

另外,前陣子在網路看到這篇:Session 有毒,所以呢。很好奇在 ASP.NET Core MVC 有沒有一樣的問題,所以查了一下官方的文件,要讓 Session 使用非同步的方式處理,只要在使用前先呼叫 HttpContext.Session.LoadAsync 即可。

參考資料

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s