LoginSignup
1

More than 3 years have passed since last update.

Blazor(クライアントWebAssembly)で文字列に変数の値を埋め込む方法

Last updated at Posted at 2019-10-13

Blazor以外の場合

C#で文字列に対して単純に変数を埋め込むだけなら$"{変数名}"でいけますが、Listを回して埋め込もうとすると何かしらのライブラリを使用することになります。
で、何がいいのかと「c# テキストテンプレート」などで検索してみるとT4なんてものが引っ掛かりますが、使ってソースコードを生成するとか書いてるのでスルーします。(実はやりたいことが実現できるかもしれないけど、引っかかる使い道が今回の目的とは違うので多分無理なんだと判断しました)
で、asp.netや~coreでよく使うRazorをそもまま使えたらいいのにと思って検索したところ、RazorEngineがありその.NetCore版もあったので使ってみました。

var list = new List<string>
{
    "aaa",
    "bbb",
    "ccc",
};

var srcRazor =
@"## test02
@foreach(var item in @Model.list)
{
<text>
1. @item
</text>
}
";
var cpled = Engine.Razor.RunCompile(srcRazor, "key", null, new { list = list });

と、こんな感じであっさりと

## test02
1. aaa
1. bbb
1. ccc  

と埋め込むことができました。
※.NetCore2.Xの場合はあっさりと動きましたが、.NetCore3.0の場合は途中でスリムにした際に色々と変わってしまったので動きませんが、先のソースコードから動くように書き換えたプロジェクトファイルをソリューションに混ぜて参照すれば解決するので問題ないよね。

Blazorの場合

サーバーサイドで実行する場合はこれでも行けると思いますが、問題はクライアントサイドでの実行です。
今回やりたいことはBlazorのクライアントサイドでテンプレートを登録し、そこに対してサーバーから取得したデータを埋め込むという処理なので、ページ切り替えの際には同じテンプレートを使用したページの場合はデータだけ切り替えてクライアントサイドで出力文字列を生成する必要があります。※もっとも、毎回サーバーへポストして埋め込んでからクライアントへ戻すという処理でもいいのかもしれませんが、それだったらBlazor使う意味無いやんと思ったのであえてクライアントのWebAssembly内で値の埋め込みを行うとしています。
で、コンソールでのサンプルコードが動いたので気をよくしてBlazorのコードに埋め込むと・・・実行時エラーが起きてしまいました。で、頑張ってソースを追いかけたところ、値の埋め込み処理でテンポラリファイルを使用していることが判明しました。ただ、正直何やってるのかよくわからない感じだったのでテンポラリファイルを使用せずに埋め込みできるように変更可能かどうかも判断できず一旦諦めていました。

で、ついさっきもっぺんRazorEngineのオリジナルの方のissuesを見たら新しい話題が追加されていましたissues558。こいつを見ると「もう更新やめたっぽい?代替ってどない?」ってな内容で、それに対するコメントで「#Scriptアルヨ」とあったので試してみました。以下はBlazorのテンプレートのindex.razorの中身を書き換えで確認しています

index.razor
@page "/"
@using ServiceStack.Script


<h1>MarkDownWiki</h1>

<p>@MkUp1</p>

@code
{
    MarkupString MkUp1 { get; set; }


    protected override void OnInitialized()
    {
        var title = "りすとだよ";
        var list = new List<string>
        {
            "aaa",
            "bbb",
            "ccc",
        };
        var context = new ScriptContext().Init();
        var inData = context.RenderScript(
        @"## {{title}}
        {{#each name in list}}
        1. {{name}}
        {{/each}}",
            new Dictionary<string, object> {
                ["title"] = title,
                ["list"] = list ,
            }
            );

        MkUp1 = new MarkupString(Markdig.Markdown.ToHtml(inData));
    }
}

無事値の埋め込みができました。

蛇足

さらっと見てわかるとおり、テンプレートにMarkDownと値の埋め込みテンプレートを使用して出力するもので、感覚的にはwikiクローンっぽいものを出来るかな?と思って色々技術的に調べているところです。このテンプレートにDBから値を埋め込みたいってのは昔やってたブラウザゲームの攻略wikiで別ページのデータを埋め込んで使いまわすのをかなりやりまくっていて、1ページ内にincludexを100以上呼び出すといったやばい作りになっていました。レンタルwikiの管理人へお願いしてincludexのカスタマイズしてもらっていたのでやれた無茶だったんですが、その管理人さん、時々連絡が取れなくなることがあって別のwikiに移動しないとまずいって話が出たときにincludexが使えないところは論外といった感じで移転先に制限がかかってしまっていたのと、ページコメントの負荷がやばくて鯖落ちした時期があったのとでこういうデータの使いまわしがきくいい感じのwikiはつくれないかなぁと漠然と考えていたので気が向いたときにぼちぼちと調べていました。

ついさっき解決したばかりの走り書きなので体裁もきちんとできていませんが、Blazorはまだプレビュー版とはいえ.NetCore3.0がリリースされてから触る人が増えてきたようなので、何かしら同じようなことをしようとして詰まる人が出てくるのでは?と思って取り急ぎでうpしました。

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
1