2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Blazor】Layoutに@rendermodeを追加したときにとInvalidOperationExceptionになる理由

Last updated at Posted at 2024-03-01

タイトルのケースはかなり特定されていますが、エラー原因自体は、異なるRender Mode間の情報受け渡しに関するもので、学びが深かったので記事にしました。

環境

VS2022のBlazor Appテンプレートからプロジェクトを作成します。

Render ModeはWebAssemblyを選択してください。

エラーを再現

実装

  • Layout

ClientプロジェクトにLayout Componentを作成します。

Client/Components/Layout/ClientMainLayout.razor
@inherits LayoutComponentBase

<h1>ClientMainLayout</h1>

@Body
Client/Components/Layout/SpecifiLayout.razor
@inherits LayoutComponentBase
@* 以下の参照をしたいので、DefaultとなるLayoutClientプロジェクトに移動しています。*@
@layout ClientMainLayout
@* そしてWebAssembly Componentとしたい *@
@rendermode InteractiveWebAssembly

<h2>SpecificLayout</h2>

@Body
  • Component

上記のLayoutを参照するPage Componentを生成します。

Client/Pages/Component.razor
@page "/component"
@layout BlazorAppError.Client.Components.Layout.SpecificLayout

<h3>Component</h3>
  • Routes

次に、Mainプロジェクト側のRoutes.razorDefaultLayoutに上記のComponentを指定します。

ちなみに、デフォルトでMainプロジェクトはClientプロジェクトをDependencisに入れているため以下の参照が可能となっています。

Components/Routes.razor
<Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(Client._Imports).Assembly }">
    <Found Context="routeData">
        <RouteView RouteData="routeData" DefaultLayout="typeof(Client.Components.Layout.ClientMainLayout)" />
        <FocusOnNavigate RouteData="routeData" Selector="h1" />
    </Found>
</Router>

実行

RootではClientMainLayout.razorが問題なく反映されていることが分かります。

そこから、/componentに遷移すると、エラーが発生しますね。

An unhandled exception occurred while processing the request.
InvalidOperationException: Cannot pass the parameter 'Body' to component 'SpecificLayout' with rendermode 'InteractiveWebAssemblyRenderMode'. This is because the parameter is of the delegate type 'Microsoft.AspNetCore.Components.RenderFragment', which is arbitrary code and cannot be serialized.

原因

ポイントは2つです。

  • Static ServerとInteractive WebAssemblyのRender Mode@BodyをCascadingしている
  • @BodyはシリアライズできないContent

公式ドキュメントに述べられているケースに該当します。

@Bodyの内容はJsonシリアライズできないため、Static ServerとInteractive WebAssebly間ではやり取りできないということです。上記のエラーにも"is arbitrary code and cannot be serialized"と書いていますね。

対応方法

幸いにも、@Bodyに対して何かを積み重ねる必要がなかったので、@rendermode InteractiveWebAssemblyが必要なComponentを別で生成し、対象のLayoutから呼ぶという方法で回避できました。

エラー再現コードを修正すると以下のようになります。

Client/Components/Layout/SpecificComponent.razor
@rendermode InteractiveWebAssembly

<h2>SpecificLayout</h2>

上記で生成したComponentをLayoutから呼び出す。

Client/Components/Layout/SpecifiLayout.razor
@inherits LayoutComponentBase
@layout ClientMainLayout

<SpecificComponent />

@Body

実行するとエラー無しで想定通りの動きができていますね。

最後に

このエラーに遭遇したときは、Layout Componentに@rendermodeは適用できないのかと諦めていました。

色々試しているうちに、対応方法にたどり着き、暇な時間にドキュメントを読んでいて「これだ!」となった感じです。

Blazorは置く深すぎるので、ドキュメント流し読みも効果ありです!

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?