.NET Core 6 Blazor Server中POST后作用域类注入控制器问题
问题解答
1. 控制器获取独立ITestClass实例的原因
Scoped服务在Blazor Server和MVC控制器中的作用域边界完全不同:
- Blazor Server的Scoped服务绑定到客户端电路(Circuit):每个用户的浏览器连接会创建一个独立电路,电路内所有组件共享同一个ITestClass实例,这也是PageB修改值后Index页面能正常读取的原因。
- MVC控制器的Scoped服务绑定到单个HTTP请求:你通过表单发起的POST是一个独立的HTTP请求,不属于Blazor的电路上下文,因此会创建全新的ITestClass实例,自然看不到PageB中设置的值。
- 控制器修改值后返回
Redirect,会触发新的HTTP请求加载Index页面,此时若页面刷新则会重新创建Blazor电路,之前修改的值也会丢失。
2. 刷新Index页面重置值的原因
Blazor Server中,页面刷新会终止当前客户端电路并创建全新的电路实例。由于Scoped服务是电路级别的,新电路会重新初始化ITestClass,导致之前设置的状态被重置。
3. 启动时输出两次"Created"的原因
这是Blazor Server默认启用预渲染导致的:
- 预渲染阶段:服务器先渲染页面的静态版本,此时会创建第一个ITestClass实例(第一次输出"Created")。
- 交互式初始化:客户端建立SignalR连接后,会创建新的Blazor电路,再次实例化ITestClass(第二次输出"Created")。
解决方案建议
若要在Blazor组件和MVC控制器之间共享用户专属状态,可参考以下方案:
- 使用Session存储:将状态保存到Session中,组件和控制器通过Session读写数据。需先在
Program.cs中配置Session服务:builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(30); options.Cookie.HttpOnly = true; }); // 中间件添加app.UseSession(); - 替换表单为Blazor HttpClient调用:避免传统HTTP请求脱离电路上下文,通过HttpClient传递状态参数,而非依赖Scoped实例共享:
<!-- PageB中替换表单为Blazor按钮 --> <button @onclick="CallController">Controller</button> @code { [Inject] HttpClient Http { get; set; } private async Task CallController() { // 传递当前状态作为请求参数 var content = new StringContent(TestClass.Name, System.Text.Encoding.UTF8, "application/json"); await Http.PostAsync("/api/test", content); NavigationManager.NavigateTo("/"); } } - 使用客户端存储:通过
LocalStorage或SessionStorage持久化状态,刷新页面也不会丢失,但需注意敏感数据的安全性。
内容的提问来源于stack exchange,提问作者plaguebreath
相关产品推荐
相关产品推荐

