Blazor项目适配Storyblok SDK:无cshtml渲染组件问题求助
解决Storyblok SDK在Blazor项目里没法渲染组件的问题
问题根因
你碰到的问题本质是:这款Storyblok SDK是给Razor Pages设计的,它依赖ASP.NET Core的视图执行器(executor.ExecuteAsync)去查找并渲染.cshtml视图文件,但Blazor用的是.razor组件,两者渲染机制完全不同,所以才会抛出找不到Page视图的异常。
可行修复方案
1. 自定义视图执行器,替换SDK的渲染逻辑
得重写SDK里负责渲染的部分,让它别再找.cshtml视图,改成渲染Blazor组件:
- 先建一个自定义执行器类,替换SDK默认的视图执行器。这个类要能接收Storyblok返回的数据,解析出要渲染的Blazor组件类型。
- 用Blazor的
RenderComponentAsync方法动态渲染组件,把Storyblok的数据当参数传进去。 - 修改SDK中间件的逻辑,让它调用你自定义的执行器,而不是原来的
executor.ExecuteAsync。
示例代码思路:
// 自定义执行器 public class BlazorComponentExecutor { private readonly IComponentRenderMode _renderMode; private readonly IServiceProvider _serviceProvider; public BlazorComponentExecutor(IServiceProvider serviceProvider, IComponentRenderMode renderMode) { _serviceProvider = serviceProvider; _renderMode = renderMode; } public async Task ExecuteAsync(ActionContext actionContext, object storyblokResult) { // 从storyblokResult里提取组件名称,比如"Page" var componentName = ExtractComponentName(storyblokResult); // 根据组件名称找到对应的Blazor组件类型 var componentType = Type.GetType($"你的项目命名空间.Components.{componentName}, 你的项目命名空间"); if (componentType == null) { throw new InvalidOperationException($"Blazor组件 {componentName} 没找到"); } // 组装组件参数,把Storyblok的数据传进去 var parameters = new ParameterViewBuilder() .Add("StoryData", storyblokResult) .Build(); // 渲染组件并输出到响应 var httpContext = actionContext.HttpContext; var renderer = _serviceProvider.GetRequiredService<IRenderer>(); var htmlContent = await renderer.RenderComponentAsync(componentType, _renderMode, parameters); httpContext.Response.ContentType = "text/html"; await htmlContent.WriteToAsync(httpContext.Response.BodyWriter); } private string ExtractComponentName(object storyblokResult) { // 这里根据Storyblok返回的数据结构提取组件名称,比如从story.content.component字段拿 // 示例:假设storyblokResult是动态对象 dynamic story = storyblokResult; return story.content.component; } }
2. 把SDK输出转成Blazor组件的数据源
要是不想改SDK源码,可以在中间件之后做拦截:
- 让SDK返回原始的Storyblok数据,别让它尝试渲染视图。
- 在Blazor的路由页面(比如
Pages/StoryblokPage.razor)里,获取SDK返回的数据,然后根据数据动态渲染对应的Blazor组件。
示例Blazor页面:
@page "/storyblok/{slug}" @inject HttpClient Http @if (_storyData != null) { @foreach (var component in _storyData.content.components) { @RenderComponent(component) } } @code { [Parameter] public string Slug { get; set; } private dynamic _storyData; protected override async Task OnInitializedAsync() { // 调用SDK获取原始数据,这里假设SDK暴露了获取数据的API _storyData = await Http.GetFromJsonAsync<dynamic>($"/api/storyblok/{Slug}"); } private RenderFragment RenderComponent(dynamic component) { return component.component switch { "Page" => builder => { builder.OpenComponent<PageComponent>(0); builder.AddAttribute(1, "Data", component); builder.CloseComponent(); }, "Hero" => builder => { builder.OpenComponent<HeroComponent>(0); builder.AddAttribute(1, "Data", component); builder.CloseComponent(); }, // 其他组件映射 _ => builder => builder.AddContent(0, $"未知组件: {component.component}") }; } }
3. 查SDK有没有Blazor适配版本
有些开源SDK会有Blazor适配分支,你可以去看该SDK的GitHub仓库,看看有没有Blazor相关的分支、Issue或者PR,有没有其他开发者已经解决了这个问题。要是没有,也可以提个Issue让官方支持Blazor,或者自己写适配代码提交PR。
注意事项
- Blazor服务器端和WebAssembly端的渲染机制不一样,自定义执行器的时候要区分
ServerComponentRenderMode和WebAssemblyComponentRenderMode。 - 要保证Storyblok返回的组件名称和你的Blazor组件名称对应上,不然还是会找不到组件。
内容的提问来源于stack exchange,提问作者Mike Hagendoorn
相关产品推荐
相关产品推荐

