日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

为什么我的会话状态在ASP.NET Core中不工作了?

發布時間:2023/12/4 asp.net 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 为什么我的会话状态在ASP.NET Core中不工作了? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文:Why isn't my session state working in ASP.NET Core? Session state, GDPR, and non-essential cookies

作者:Andrew Lock

譯文:https://www.cnblogs.com/lwqlun/p/10526380.html

譯者:Lamond Lu

在本篇博客中,我將描述一個關于會話狀態(Session State)的問題, 這個問題我已經被詢問了好幾次了。這個問題的場景如下:

  • 創建一個新的ASP.NET Core應用程序

  • 一個用戶在會話狀態中設置了一個字符串值,例如HttpContext.Session.SetString("theme", "Dark");

  • 在下一次請求中,嘗試從會話中讀取這個自字符串的值HttpContext.Session.GetString("theme");, 但是得到的結果卻是null!

  • “額,這個愚蠢的框架不工作了”(╯°□°)╯︵ ┻━┻

這個問題的原因是ASP.NET Core 2.1中引入的GDPR功能與會話狀態互相影響了。在本篇博客中,我將描述為什么你會看到這種行為,以及一些處理它的方法。

GDPR中ASP.NET Core 2.1中引入的一個特性,如果你使用NET Core 1.x或2.0版本,你將不會遇到這個問題。但是請記住,自2019年6月27起,1.x版本即將失去支持,2.0版本已經不受支持了,因此你應該考慮升級到2.1及以上版本。

說明:

  • 《通用數據保護條例》(General Data Protection Regulation,簡稱GDPR)為歐洲聯盟的條例,前身是歐盟在1995年制定的《計算機數據保護法》。

  • 2018年5月25日,歐洲聯盟出臺《通用數據保護條例》。

ASP.NET Core中的會話狀態

就像我前面所說的,如果你使用的是ASP.NET Core 2.0及以前的版本,你不會遇到這個問題。這里我將借助ASP.NET Core 2.0展示一下預期的行為,以便說明遇到這個問題的人期望的會話狀態行為。然后我將在ASP.NET Core 2.2中創建等效的應用程序,并顯示會話狀態不再起作用了。

什么是會話狀態?

會話狀態是一種可以回溯到ASP.NET(非核心)的功能,你可以使用它為瀏覽站點的用戶存儲和檢索服務器端的值。 會話狀態經常在ASP.NET應用程序中廣泛使用,但經常由于一些原因而出現問題,主要是性能和可伸縮性。

ASP.NET Core中的你應該把會話狀態看作針對每用戶的緩存。 從技術角度來看,ASP.NET Core中的會話狀態的功能需要2個獨立的部分來完成:

  • 一個Cookie。 用來指定每個用戶的唯一ID(Session ID)

  • 一個分布式緩存。用來存儲與每個用戶唯一ID關聯的數據項

在一般的情況下,我會盡量避免使用會話狀態,使用會話狀態可能會有很多陷阱,如果不注意,就會引起一起不必要的問題。例如:

  • 會話是針對每個瀏覽器的,而不是每個登錄用戶的

  • 會話結束的時候,應該刪除會話Cookie,但可能不會

  • 如果會話中沒有任何值,它將會被刪除,并重新生成一個新的會話ID

  • 本文中即將描述的GDPR問題

這里我們講解了什么是會話狀態,以及其工作的原理。在下一節中,我將創建一個小程序,這個小程序會使用會話狀態存儲你訪問過的頁面,然后在首頁上顯示該列表。

在ASP.NET Core 2.0項目中使用會話狀態

為了說明ASP.NET Core 2.0版本和2.1以上版本的行為變化,我將先創建一個ASP.NET Core 2.0項目,因為我的電腦上安裝了許多.NET Core SDK, 這里我將使用2.0 SDK(版本號2.1.202)來構建一個2.0項目模板。

這里我們首先創建一個global.json, 將當前app目錄的SDK版本固定為2.1.202版本。

dotnet new globaljson --sdk-version 2.1.202

然后使用dotnet new命令創建一個新的ASP.NET Core MVC 2.0應用程序

dotnet new mvc --framework netcoreapp2.0

會話狀態默認情況下是沒有啟用的,所以這里你需要先添加必要的服務。我們修改Startup.cs文件ConfigureServices方法來添加會話服務。默認情況下,ASP.NET Core將使用內存來存儲會話信息,這對于測試來說很友好,但是生產環境中可能就需要替換為其他方式。

public void ConfigureServices(IServiceCollection services)
{
? ?services.AddMvc();
? ?services.AddSession(); // add session
}

當然,只添加服務是沒有用的,我們還需要在管道中注冊會話中間件。只有注冊在會話中間件之后的中間件才可以訪問會話狀態,所以你需要將會話中間件放在MVC中間件之前。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
? // ...其他配置
? app.UseSession();
? app.UseMvc(routes =>
? {
? ? ? routes.MapRoute(
? ? ? ? ? name: "default",
? ? ? ? ? template: "{controller=Home}/{action=Index}/{id?}");
? });
}

對于這個簡單的例子,我將使用會話密鑰"actions"來存儲并讀取一個字符串類型的會話值,這個會話值中會保存你訪問過的所有頁面。當你在不同的頁面間瀏覽時,我們會將你訪問過的頁面以分號分隔的形式保存在"actions"會話值中?,F在我們更新HomeController的代碼:

public class HomeController : Controller
{
? ?public IActionResult Index()
? {
? ? ? ?RecordInSession("Home");
? ? ? ?return View();
? }

? ?public IActionResult About()
? {
? ? ? ?RecordInSession("About");
? ? ? ?return View();
? }

? ?private void RecordInSession(string action)
? {
? ? ? ?var paths = HttpContext.Session.GetString("actions") ?? string.Empty;
? ? ? ?HttpContext.Session.SetString("actions", paths + ";" + action);
? }
}

注意:Session.GetString(key)Microsoft.AspNetCore.Http命名空間中的一個擴展方法。

最后,我們修改Index.cshtml頁面的代碼如下,在頁面中顯示當前"actions"的會話值

@using Microsoft.AspNetCore.Http
@{
? ViewData["Title"] = "Home Page";
}

<div>
? @Context.Session.GetString("actions")
</div>

如果你現在運行應用程序并瀏覽幾次,你將看到會話頁面訪問歷史列表的構建。 在下面的示例中,我訪問了主頁三次,關于頁面兩次:

如果查看當前頁面關聯的Cookie信息,你就會看到一個名為.AspNetCore.Session的Cookie, 它的值就是一個加密會話ID, 如果你刪除這個Cookie, 你將會看到"actions"的值被重置,頁面訪問歷史列表丟失。

這種會話狀態的行為就是大部分人所期望的,所以這里沒有問題。但是當你使用ASP.NET Core 2.1/2.2版本創建相同項目之后,情況就不一樣了。

在ASP.NET Core 2.2項目中使用會話狀態

為了創建ASP.NET Core 2.2應用程序,我使用了幾乎相同的行為,但這次我沒有固定SDK。 我安裝了ASP.NET Core 2.2 SDK(2.2.102),因此以下命令會生成一個ASP.NET Core 2.2 MVC應用程序:

dotnet new mvc

這里你依然需要顯示注冊會話服務,并啟用會話中間件,這一部分代碼和前面一模一樣。

與以前的版本相比,較新的2.2模板已經簡化,因此為了保持一致性,我從2.0應用程序復制了HomeController。 我還復制了Index.chtml,About.chtml和Contact.cshtml視圖文件。 最后,我更新了Layout.cshtml,為標題中的About和Contact頁面添加了鏈接。

這2個應用程序,除了使用的ASP.NET Core版本不一樣,其他的部分基本都是一樣的。然而這次運行的時候,當你瀏覽一些頁面之后,首頁只會顯示你訪問過首頁,而不會顯示你訪問過其他頁面。

不要點擊隱私政策的橫幅 - 后面你將馬上知道原因


現在如果你去查看一下你的Cookies, 你會發現加密會話ID.AspNetCore.Session不存在。


一切都顯然配置正確,并且會話本身似乎也在工作(因為可以在Index.cshtml中成功檢索HomeController.Index中設置的值)。 但當頁面重新加載,或者在導航之間跳轉的時候,沒有保存會話狀態。

那么為什么會話狀態在ASP.NET Core 2.0中正常工作, 在ASP.NET Core 2.1/2.2中反而沒有正常工作了呢?


到底發生了什么?GDPR

問題的原因,是因為ASP.NET Core 2.1版本之后,引入了一些新功能。為了幫助開發人員遵守2018年生效的GDPR規則,ASP.NET Core 2.1版本引入了一些擴展點,以及模板的更新。


針對這些新功能的官方文檔寫的都很詳細,這里我只做簡單總結:

  • 同意Cookie對話框 - 默認情況下,在用戶點擊同意對話框之前,ASP.NET Core不會將“非必要”的cookies寫入響應中

  • Cookie可以被設置為必要或者非必要的 - 無論用戶是否同意,必要的Cookies都會發送給瀏覽器,非必要的Cookies需要得到用戶的同意

  • 會話Cookie被認為是非必要的 - 因此,在用戶同意之前,無法跨導航或頁面重新加載跟蹤會話。

  • 臨時數據(Temp Data)是非必要的 - ASP.NET Core 2.0以上版本中,臨時數據提供器使用Cookie來存儲數據項,所以在用戶同意之前,臨時數據功能是不可用的

所以問題是我們需要用戶同意使用Cookie。 如果單擊隱私橫幅上的“Accept”,則ASP.NET Core可以編寫會話cookie,并恢復預期的功能。

如何在ASP.NET Core 2.1及以上版本中使用會話狀態

根據你正在構建的程序,你可以使用多種選項。哪一個最適合你取決于你的使用場景,但是請注意,這些功能是為了幫助開發人員遵守GDPR而添加的。

如果你不在歐洲國家,或者你認為GDPR對自己沒有什么影響,最好請閱讀一下https://andrewlock.net/session-state-gdpr-and-non-essential-cookies/ - GDPR可能依然適用于你

這里主要的可選項如下:

  • 在用戶同意Cookie之前,接受該會話狀態可能不可用。

  • 在用戶同意Cookie之前,禁用需要會話狀態的功能。

  • 禁用Cookie同意功能

  • 將會話Cookie標記為必要的

  • 我將在下面詳細介紹每個選項,請記住考慮你的選擇可能會影響你是否遵守GDPR!

    接受當前的行為

    “最簡單”的選擇就是接受現有的行為。 ASP.NET Core中的會話狀態通常只應用于臨時數據,因此你的應用程序需要能夠處理會話狀態不可用的情況。

    這取決于你使用會話的目的,可能可以實現或可能不能實現,但這是使用現有模板的最簡單方法,并且將你接觸GDPR問題方面風險降到了最低。

    禁用需要會話的功能

    第二種選擇和第一種選擇類似,應為你需要保持現有的行為。區別在于第一種選項會將會話簡單的視為緩存,因此你始終需要假設會話值是可以讀取和保存的。而第二種選項略有不同,因為你需要明確知道系統中哪些部分是需要會話狀態的,并在用戶同意Cookie之前,禁用它們。

    例如, 你可以需要一個會話狀態保存當前頁面選擇的主題。如果用戶沒有同意Cookie, 那么你只需要隱藏主題選擇的功能。只要用戶同意,再將它顯示出來。

    這感覺就像是針對選擇一的改進,因為它主要改善了用戶體驗。如果你不考慮哪些功能是需要會話的,用戶可能會產生一些疑惑。例如,如果你使用選項一,用戶在切換主題的時候,程序永遠不會記住它們的選擇,這就很讓人沮喪。

    禁用Cookie同意功能

    如果你確定不需要Cookie同意功能,你也可以很容易的禁用它。 默認模板在Startup.ConfigureServices中顯式啟用了Cookie同意功能。

    public void ConfigureServices(IServiceCollection services)
    {
    ? ?services.Configure<CookiePolicyOptions>(options =>
    ? {
    ? ? ? ?options.CheckConsentNeeded = context => true;
    ? ? ? ?options.MinimumSameSitePolicy = SameSiteMode.None;
    ? });

    ? ?services.AddSession(); // added to enable session
    ? ?services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    這里CheckConsentNeeded屬性是一個標記,它用于檢查是否應將非必要的cookie寫入響應。 如果函數返回true(如上所述,模板中的默認值),則跳過非必要的cookie。 將此更改為false并且會話狀態將起作用,而不需要用戶明確同意cookie。

    標記會話Cookie是必要的

    完全禁用cookie同意功能可能會對你的應用程序造成一定的負擔。 如果是這種情況,你可以將會話cookie標記為必要。

    services.AddSession的重載方法,允許你傳入一個會話配置對象。你可以使用它設置會話的超時時間,以及自定義會話Cookie。為了將會話Cookie標記為必要的,我們需要顯式配置IsEssential的值是true。

    public void ConfigureServices(IServiceCollection services)
    {
    ? ?services.Configure<CookiePolicyOptions>(options =>
    ? {
    ? ? ? ?options.CheckConsentNeeded = context => true;
    ? ? ? ?options.MinimumSameSitePolicy = SameSiteMode.None;
    ? });

    ? ?services.AddSession(opts =>
    ? {
    ? ? ? ?opts.Cookie.IsEssential = true;
    ? });
    ? ?services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    使用這種方法,雖然應用程序依然會顯示Cookie同意橫幅,并且在點擊之前不會寫入非必要的Cookie。 但會議狀態將在用戶同意Cookie之前立即生效,因為它被認為是必要的。

    總結

    在這篇文章中,我描述了一個曾經多次被問過問題。開發人員發現他們的會話狀態沒有正確保存。 這通常是由于ASP.NET Core 2.1中引入的Cookie同意和非必要cookie的GDPR功能引起的。

    我展示了一個問題的實例,以及它在2.0 app和2.2 app之間的區別。 我描述了會話狀態如何依賴于默認情況下被認為是非必要的會話Cookie,因此在用戶同意Cookie之前不會寫入響應。

    最后,我描述了處理這種行為的四種方法:

    • 什么也不做,接受它

    • 禁用依賴會話狀態的功能,直到同意為止

    • 取消同意要求

    • 標記會話Cookie為必要的Cookie。


    哪種選擇最適合你將取決于你正在構建的應用程序,以及你對GDPR和類似法規的認識。


    總結

    以上是生活随笔為你收集整理的为什么我的会话状态在ASP.NET Core中不工作了?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。