在Blazor服务器端创建和读取Cookie

问题描述

在Blazor服务器端创建和读取Cookie的最简单方法是什么。
似乎所有的解决方案都适用于Blazor Web组装,并且每当我使用那些Response.Cookies.Append(“”)和Request.Cookies []选项时,这些解决方案都将不起作用。

解决方法

执行HTTP Post / Get,以便您实际上可以修改响应cookie。回调通常是通过WebSocket调用的,因此已经发送了响应(包括cookie),因此您无法进行修改。

,

我找到了使用本地存储解决Blazor服务器端Cookie问题的好方法。

首先,使用以下命令获取NuGet Blazored LocalStorage:Install-Package Blazored.LocalStorage。我必须更新我的System.Text.Json,可从https://www.nuget.org/packages/System.Text.Json/

将以下内容添加到Startup.cs中:

public void ConfigureServices(IServiceCollection services)
{
    services.AddBlazoredLocalStorage();   // local storage
    services.AddBlazoredLocalStorage(config =>
        config.JsonSerializerOptions.WriteIndented = true);  // local storage
}

在您的Razor页面上(我使用Index.razor进行测试):

@page "/"
@inject Blazored.LocalStorage.ILocalStorageService localStorage

<button @onclick="HandleSubmit">Create Cookie</button>  @* Create your cookie *@

@code{
    public async Task HandleSubmit()
    {
        await localStorage.SetItemAsync("cookieName","Jason Bourne");
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        var cookieContent = await localStorage.GetItemAsync<string>("cookieName");

        if (cookieContent == null)
        {
            Console.WriteLine("Cookie is blank");
        }
        else
        {
            Console.WriteLine("We have a cookie with contents: " + cookieContent);
        }
    }
}
,

wwwroot/index.html(Blazor WebAssembly)或Pages/_Host.cshtml(Blazor Server)中,编写以下javascript代码:

  <script>
    window.WriteCookie = {

        WriteCookie: function (name,value,days) {

            var expires;
            if (days) {
                var date = new Date();
                date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                expires = "; expires=" + date.toGMTString();
            }
            else {
                expires = "";
            }
            document.cookie = name + "=" + value + expires + "; path=/";
        }
    }
    window.ReadCookie = {
        ReadCookie: function (cname) {
        var name = cname + "=";
        var decodedCookie = decodeURIComponent(document.cookie);
        var ca = decodedCookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0) {
                return c.substring(name.length,c.length);
            }
        }
        return "";
    }
}
</script>

然后,将以下示例代码写入Razor组件(.razor):

@inject IJSRuntime JsRuntime;
<button class="btn" @onclick="WriteCookies">
    Write Cookie
</button>
<button class="btn" @onclick="ReadCookies">
    Read Cookie
</button>

<p>The cookie is @myCookieValue</p>
@code {
    public string myCookieValue { get; set; } = "";
    protected async Task WriteCookies()
    {

        await JsRuntime.InvokeAsync<object>("WriteCookie.WriteCookie","cookieName","cookieValue",DateTime.Now.AddMinutes(1));

    }
    protected async Task ReadCookies()
    {

        myCookieValue= await JsRuntime.InvokeAsync<string>("ReadCookie.ReadCookie","cookieName");

    }

}
,

我尝试了基于 Blazored.LocalStorage 的方法以及此处提供的实验包

https://docs.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-3.1&pivots=server

而且,我必须说它们非常相似,但它们有一个不方便之处:LocalStorage 变量只能从 OnAfterRenderAsync 或 OnInitializedAsync 中读取(InvalidOperationException:此时无法发出 JavaScript 互操作调用。等等...)。

就我而言,我需要从 OnParametersSetAsync 访问 LocalStorage,所以我使用了一个像这样的简单控制器:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;

namespace MyNamespace.Controllers
{
    [Route("[controller]/[action]")]
    public class CookieController : Controller
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

        public CookieController(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        [HttpGet]
        public IActionResult Write(string key,string value,string redirectUri)
        {
            CookieOptions options = new CookieOptions
            {
                Expires = DateTime.Now.AddDays(30)
            };

            _httpContextAccessor.HttpContext.Response.Cookies.Append(key,options);

            return LocalRedirect(redirectUri);

        }

    }

}

在 Startup.cs 中,我添加了 services.AddSingleton<IHttpContextAccessor,HttpContextAccessor>();

并且,在组件内部:

@inject IHttpContextAccessor HttpContextAccessor

@code
{

    private string cookieContent;
    protected override async Task OnParametersSetAsync() 
    {
        ...
        cookieContent= HttpContextAccessor.HttpContext.Request.Cookies["myCookie"];
    }
}