You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor .NET 8中如何从Layout向页面传递对象?

可行的解决方案

1. 利用Cookie传递数据

Cookie是SSR和客户端Blazor都能访问的存储方式,且支持在OnInitializedAsync中操作:

  • SSR布局端:注入IHttpContextAccessor,在OnInitializedAsync中将数据写入Cookie:
    @inject IHttpContextAccessor HttpContextAccessor
    
    @code {
        protected override async Task OnInitializedAsync()
        {
            var userData = new { UserId = "123", Theme = "dark" };
            var jsonData = System.Text.Json.JsonSerializer.Serialize(userData);
            HttpContextAccessor.HttpContext.Response.Cookies.Append(
                "AppUserData", 
                jsonData,
                new CookieOptions { HttpOnly = false, SameSite = SameSiteMode.Strict }
            );
            // 同时设置当前作用域服务的属性
            YourScopedService.SetUserData(userData);
        }
    }
    
  • 客户端页面端:注入IJSRuntime,在OnInitializedAsync中读取Cookie并同步到作用域服务:
    @inject IJSRuntime JSRuntime
    @inject YourScopedService ScopedService
    
    @code {
        protected override async Task OnInitializedAsync()
        {
            var cookieValue = await JSRuntime.InvokeAsync<string>("eval", "document.cookie.split('; ').find(row => row.startsWith('AppUserData='))?.split('=')[1] ?? ''");
            if (!string.IsNullOrEmpty(cookieValue))
            {
                var userData = System.Text.Json.JsonSerializer.Deserialize<UserDataModel>(cookieValue);
                ScopedService.SetUserData(userData);
            }
        }
    }
    
    注意:设置HttpOnly = false才能让客户端JS读取Cookie,若数据敏感,建议加密后存储。

2. 嵌入全局脚本变量

在SSR布局中将数据序列化后嵌入页面的全局JS变量,客户端直接读取:

  • SSR布局端:在页面底部添加脚本块,将数据序列化后赋值给全局变量:
    @inject YourScopedService ScopedService
    
    <!-- 布局内容 -->
    
    <script>
        window.appUserData = @System.Text.Json.JsonSerializer.Serialize(ScopedService.UserData);
    </script>
    
  • 客户端页面端:在OnInitializedAsync中通过IJSRuntime读取全局变量:
    @inject IJSRuntime JSRuntime
    @inject YourScopedService ScopedService
    
    @code {
        protected override async Task OnInitializedAsync()
        {
            var userData = await JSRuntime.InvokeAsync<UserDataModel>("eval", "window.appUserData");
            if (userData != null)
            {
                ScopedService.SetUserData(userData);
            }
        }
    }
    
    此方法无需额外API调用,数据随页面初始加载直接传递,性能较好。

3. 基于Session的API获取

若数据敏感,可将数据存储在服务器Session中,客户端通过API获取:

  • 配置Session:在Program.cs中添加Session支持:
    builder.Services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromMinutes(30);
        options.Cookie.HttpOnly = true;
        options.Cookie.SameSite = SameSiteMode.Strict;
    });
    
    app.UseSession();
    
  • SSR布局端:将数据存入Session:
    @inject IHttpContextAccessor HttpContextAccessor
    @inject YourScopedService ScopedService
    
    @code {
        protected override async Task OnInitializedAsync()
        {
            var userData = ScopedService.UserData;
            var jsonData = System.Text.Json.JsonSerializer.Serialize(userData);
            HttpContextAccessor.HttpContext.Session.SetString("AppUserData", jsonData);
        }
    }
    
  • 添加API端点:在服务器项目中创建最小API,用于获取Session数据:
    app.MapGet("/api/userdata", (HttpContext context) =>
    {
        var jsonData = context.Session.GetString("AppUserData");
        if (string.IsNullOrEmpty(jsonData))
            return Results.NotFound();
        var userData = System.Text.Json.JsonSerializer.Deserialize<UserDataModel>(jsonData);
        return Results.Ok(userData);
    });
    
  • 客户端页面端:在OnInitializedAsync中调用API获取数据:
    @inject HttpClient HttpClient
    @inject YourScopedService ScopedService
    
    @code {
        protected override async Task OnInitializedAsync()
        {
            try
            {
                var userData = await HttpClient.GetFromJsonAsync<UserDataModel>("/api/userdata");
                if (userData != null)
                {
                    ScopedService.SetUserData(userData);
                }
            }
            catch (HttpRequestException)
            {
                // 处理异常
            }
        }
    }
    
    此方法适合敏感数据,因为数据不会暴露在客户端,仅通过API传递。

4. 封装Cookie的自定义作用域服务

创建一个封装Cookie读写的作用域服务,让SSR和客户端共享同一套数据访问逻辑:

public class UserDataService
{
    private readonly IHttpContextAccessor? _httpContextAccessor;
    private readonly IJSRuntime? _jsRuntime;
    private UserDataModel? _cachedData;

    public UserDataService(IHttpContextAccessor? httpContextAccessor, IJSRuntime? jsRuntime)
    {
        _httpContextAccessor = httpContextAccessor;
        _jsRuntime = jsRuntime;
    }

    public async Task<UserDataModel?> GetUserDataAsync()
    {
        if (_cachedData != null)
            return _cachedData;

        if (_httpContextAccessor != null && _httpContextAccessor.HttpContext != null)
        {
            // SSR环境:从Cookie读取
            var cookieValue = _httpContextAccessor.HttpContext.Request.Cookies["AppUserData"];
            if (!string.IsNullOrEmpty(cookieValue))
            {
                _cachedData = System.Text.Json.JsonSerializer.Deserialize<UserDataModel>(cookieValue);
            }
        }
        else if (_jsRuntime != null)
        {
            // 客户端环境:从Cookie读取
            var cookieValue = await _jsRuntime.InvokeAsync<string>("eval", "document.cookie.split('; ').find(row => row.startsWith('AppUserData='))?.split('=')[1] ?? ''");
            if (!string.IsNullOrEmpty(cookieValue))
            {
                _cachedData = System.Text.Json.JsonSerializer.Deserialize<UserDataModel>(cookieValue);
            }
        }

        return _cachedData;
    }

    public async Task SetUserDataAsync(UserDataModel data)
    {
        _cachedData = data;
        var jsonData = System.Text.Json.JsonSerializer.Serialize(data);

        if (_httpContextAccessor != null && _httpContextAccessor.HttpContext != null)
        {
            // SSR环境:写入Cookie
            _httpContextAccessor.HttpContext.Response.Cookies.Append(
                "AppUserData",
                jsonData,
                new CookieOptions { HttpOnly = false, SameSite = SameSiteMode.Strict, Expires = DateTimeOffset.Now.AddDays(1) }
            );
        }
        else if (_jsRuntime != null)
        {
            // 客户端环境:写入Cookie
            await _jsRuntime.InvokeVoidAsync("eval", $"document.cookie = 'AppUserData={jsonData}; path=/; SameSite=Strict; expires={DateTimeOffset.Now.AddDays(1).ToString("R")}'");
        }
    }
}

然后在Program.cs中注册服务:

builder.Services.AddScoped<UserDataService>();
builder.Services.AddHttpContextAccessor();

这样不管是SSR布局还是客户端页面,直接注入UserDataService调用Get/Set方法即可,无需关心当前渲染模式,数据自动通过Cookie同步。


内容的提问来源于stack exchange,提问作者michaeld

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 20:21:05