====== Blazor ====== ===== 便利ツール ===== テーブル作成\\ * [[https://divtable.com/generator/|DIV TABLE生成サイト]] * [[https://tabletag.net/ja/|TABLEタグ生成サイト]] ===== Tips ===== ==== 初回アクセスページ ==== === Blazor Server === Pages フォルダにある「_Host.cshtml」ファイルとなる。 === Blazor WebAssembly === wwwroot フォルダにある「index.html」ファイルとなる。 ==== UIフレームワーク ==== >MatBlazor が一番有名な UI フレームワークなのですが、GitHub のスターがより多い「Ant Design Blazor」となる。 >[[https://blazor-master.com/blazor-ui-framework/|【無料】Blazor 対応の「使える」UI フレームワーク5選]] https://ant.design/components/overview/ === AntDesign 採用例 === * [[https://zenn.dev/okazuki/articles/and-blazor-lab|Blazor で HTML と CSS で画面作りたくないよぉ… AntDesign 編]] * [[https://mebee.info/2022/02/02/post-55944/|ASP.NET core 6 Blazor Server AntDesignを使用する]] === BlazorStrap 採用例 === == Blazor Server Side へのインストール方法 == * リリース版 https://blazorstrap.io/VNext/V5 * 最新プレビュー版 https://github.com/chanan/BlazorStrap/releases - nuget から BlazorStrap と BlazorStrap.V5 の2つのパッケージをダウンロードします。 - _host.cshtml を次のように変更します。 - 追加されていることを確認 (YourAssemblyName)の部分は書き換える - - - 追加 の最後に - - \\ V5.2.100-Preview3 でblazorstrap.jsを削除 - _Program.cs に追加 - using BlazorStrap; - builder.Services.AddBlazorStrap(); - _Imports.razor に追加 - @using BlazorStrap.V5 - MainLayout.razor の class="page"の最後に下記を追加 - ==== NuGet参照したフレームワークの場所「_content」==== NuGet参照したUIフレームワークの「BlazorStrap」など 以下の命名則の URL で、これらの静的 Web アセットを参照できる。 - "_content/"で始まり、 - 続けて、パッケージの名前、 - 最後に、アセットファイルのファイル名 NuGetのパッケージキャッシュフォルダは、デフォルトは「%userprofile%\.nuget\packages」 * [[https://devadjust.exblog.jp/28159915/|"Razor Class Library" パッケージについて]] * [[https://forum.radzen.com/t/where-can-i-find-the-content-folder/4991|_content フォルダーはどこにありますか]] ==== スタートアップページの設定 ==== Blazor アプリケーションのスタートアップ ページは Index.razor です。\\ これを Login.razor に変更したい場合、下記のようにします。 - Index.razorから「@page "/"」 を削除します。 - Login.razor に「@page "/"」 を追加します。 [[https://stackoverflow.com/questions/56876631/setting-a-startup-page-in-blazor|Setting a startup page in Blazor - stackoverflow]] ==== アイコン使用 ==== === Bootstrap Icons === 1,800以上のアイコンが使用できる。\\ https://icons.getbootstrap.com/ 本家からはnpmのみで、NuGetによるインストールは用意されていない。 [[https://github.com/windperson/BlazorBootstrapIconsdDemo|Using Bootstrap Icons in ASP.NET Core Blazor project]] == 任意のサイズ == font-size と color を使用して、アイコンの外観を変更\\ https://bootstrap-guide.com/extend/icons/bootstrap-icons === FontAwesome === Web系の開発でアイコン表示などによく使われている。 現時点で、Font Awesome 6が最新である。 === Open Iconic === .NET 7までは、「Open Iconic v1.1.1」のアイコン223種類が使用できる。.NET 8から除外された。\\ https://www.nsbasic.com/app/OpenIconic.html >Open Iconicは223ものアイコンをOSSとして公開されているアイコンフォントです。EOTやWOFF、OTFだけでなく、PNG、SVGなどのフォーマットも用意されています。また、マルチカラー化や用意された複数サイズのフォントを利用してRWDに対応する、等も可能のようです。シンプルで汎用性の高そうなデザインですね。ライセンスはMIT、フォントはOFLとして公開されています。 >[[http://kachibito.net/useful-resource/open-iconic|オープンソースとして公開されているアイコンフォントのセット・「Open Iconic」]] ナビゲーションのホームアイコン ==== Razorコンポーネントのライフサイクル ==== [[https://blazor-master.com/component-lifecycle/|【Blazor】Razorコンポーネントのライフサイクルを解説する]] 実行の順番 ^メソッド名^呼び出し^補足^ |SetParametersAsync|パラメーターが設定されるタイミング| | |OnInitialized(Async)|コンポーネントが初期化されるタイミング| | |OnParametersSet(Async)|コンポーネントが初期化されるタイミングと、受け取るパラメータが更新されたタイミング| |OnAfterRender(Async)|コンポーネントがレンダリングされたあと|初回実行のときは、引数の firstRender が true となる| |ShouldRender|コンポーネントがレンダリングされるたび|true を返すとレンダリングを続行する| |StateHasChanged|レンダリングしたい任意のタイミング|コストが高いので不必要に呼び出さないこと| === OnParametersSet(Async)について === Navigation.NavigateToで別ページに画面遷移させた時でもOnParametersSetAsyncが動作する。 Navigation.NavigateToで別ページに画面遷移させた時に例外エラー、原因として OnParametersSetAsync処理内で発生していた。 NavigateTo前に_isNextPageフラグをTrueにセットして使用して回避させた。 protected override async Task OnParametersSetAsync() { // 別ページに画面遷移する場合は何もしない。 if (_isNextPage) return; ==== Razorコンポーネントのステート ==== [[https://www.misuzilla.org/Blog/2020/12/25/BlazorComponentLifecycle|Blazor のコンポーネントのステートについて]] ステートの変更通知はどのようなタイミングで発生するのかですが、おおまかに下記の3パターンで発生します。 - StateHasChanged メソッドを明示的に呼び出したとき - イベント発火時 (@bind や @onclick とか) - Parameter が変わったとき 2つ目と3つ目は暗黙的に StateHasChanged を呼び出している。\\ StateHasChanged はステートが変更されたことを通知するメソッドです。このメソッドを呼び出すと再レンダリング候補としてマークされます。 ==== コードビハインド ==== razorファイルの中にHTML要素とバインドするC#コードを合わせた記載はやめて、razorコンポーネントとC#コードを分離して記載する。\\ [[https://qiita.com/nobu17/items/b7dc78db7beb1d833dc8|Blazorでコードビハインドでロジックとビューを分離して記述する]] ロジックとビューを分離することで、下記のようなメリットなどが得られます。 * ロジックに対するUnitTestの記載が可能 * 基底のコンポーネントクラスの作成などによる共通処理の作成 === 方法 === raozrファイルと対になるようにcsのファイルを作成するだけです。\\ Counter.razor Counter.razor.cs(追加) コード側のクラスには、partialキーワードを付けます。\\ 例 public partial class Counter ==== 最大長(maxlength)を設定する方法 ==== BlazorのInputコンポーネントに maxLength が見つからない。 >これらの組み込みコンポーネントは、レンダリングされた出力に HTML 属性を渡します。したがって、例で行ったのとまったく同じように、HTML 属性を指定するだけでかまいません >[[https://stackoverflow.com/questions/67511973/how-to-set-textarea-input-max-length-in-blazor|How to set textarea/input max length in Blazor - stackoverflow]] 組み込み専用の属性がないだけで、HTML 属性はそのまま指定すれば機能する。 ==== ボタンにフォーカスを設定する方法 ==== === UIフレームワーク未使用 === 有名なUIフレームワークでも、Buttonのフォーカスが用意されていないことがあるので、その場合に標準機能で代替する。 @code { public ElementReference? ControlButton { get; set; } = default!; protected override async Task OnAfterRenderAsync(bool firstRender) { if (ControlButton != null) await ControlButton.Value.FocusAsync(); } } === BlazorStrap使用 === ※BlazorStrap/5.2.100-Preview3b が必要\\ https://github.com/chanan/BlazorStrap/issues/599 Click me @code { public ElementReference? ControlButton { get; set; } = default!; protected override async Task OnAfterRenderAsync(bool firstRender) { if (ControlButton != null && ControlButton.Element != null) await ControlButton.Element.Value.FocusAsync(); } } ==== BSInputGroupを中央寄せにする方法 ==== BSInputGroupでdisplay:flex となっているため、style属性で"display:block に書き換えてから中央寄せ(text-align: center)とする。
バーコード
手動選択
==== Boostrap 5による変更点 ==== bootstrap5では中東の言語で主流である右書きに対応したことからleft→start、right→endという概念の変更が導入されました。\\ これにより、ml-〇 → ms-〇にmr-〇 → me-〇 というようにクラス名が変更になりました。 [[https://nao-tokyo.jp/%E6%8A%80%E8%A1%93%E6%83%85%E5%A0%B1/changing-name-of-class-at-bootstrap5/|【bootstrap5】classのml、plとmr、prの名称が変更]] ====HTMLタグを出力する ==== MarkupStringオブジェクトにキャストすることでタグの内容を出力できます。

@((MarkupString)messageText)

@code { string messageText; void ButtonClick() { messageText = "

見出しです

My Button Clicked

"; } }
* [[https://www.ipentec.com/document/csharp-blazor-application-output-html-tag|BlazorアプリケーションでHTMLタグを出力する]] * [[https://stackoverflow.com/questions/50604366/is-there-an-equivalent-to-html-raw-in-blazor|Is there an equivalent to Html.Raw in Blazor? - stackoverflow]] ==== 最上位のCSSを定義 ==== フォントサイズなど、bootstrap.css で定義されたサイズが優先されてしまう場合、important.css にてCSSを定義することにより優先させるようにする。 画面サイズによりフォントサイズを変更する。 .font-adjust { font-size: 16px !important; } @media (min-width: 760px) { .font-adjust { font-size: calc(16px + ((1vw - 7.6px)*(16/4.4))) !important; } } @media (min-width: 1200px) { .font-adjust { font-size: 32px !important; } } * [[https://style.potepan.com/articles/22667.html#i-2|【HTML】フォントサイズの指定方法・単位・変わらない時の対処法まとめ]] ==== テキストボックスのEnterキーでサブミットさせる ==== IsSubmit="true" を付けることで、Enterキーでサブミットさせることが出来る。 ==== bindとonchangeの併用は不可 ==== onchange を追加すると、Model.Procedure に値がセットされなくなる。 [[https://ryuichi111std.hatenablog.com/entry/2019/05/12/132636|bindとonchangeの併用は不可]] === 対応 === onchange イベント処理内で値をセットする。 private void OnProcejureChange(ChangeEventArgs e) { Model.Procedure = e.Value.ToString() ?? ""; } ==== MainLayout コンポーネント側にデータを反映させる ==== カスケーディングを使用してパラメーターを渡す。 >カスケードとは、もともと「連なった小さな滝」という意味があります。 >Blazor では滝が流れるイメージで、上位の階層から下位の階層にパラメーターを渡すことができる仕組みがあります。 >これが「カスケーディングパラメーター」です。 * [[https://blazor-master.com/cascading-parameter/|【Blazor】カスケーディングを使ってパラメーターを渡す方法]] * [[https://www.appsloveworld.com/blazor/100/2/is-there-any-way-to-communicate-to-main-layout-of-blazor-pages|[SOLVED]-IS THERE ANY WAY TO COMMUNICATE TO MAIN LAYOUT OF BLAZOR PAGES-BLAZOR]] ==== クライアントのIPアドレスの取得 ==== BlazorServerではサーバーで動作しているので、クライアントのIPアドレスを取得するにはクライアントから情報を取得する。\\ MainLayoutの子コンポーネント側に表示させるため、カスケーディングを使用してパラメーターを渡す方式にした。 [[https://qiita.com/takaOG/items/375d67397ddc3dc77fc9|BlazorServerでクライアントのIPアドレスを全ページで共有する]] ==== クエリパラメーターのセットと取得 ==== === 単独変数 === var parameter = new Dictionary { { "CPCode", value }, { "TermID", Layout.Info.IPAddress } }; var newuri = Navigation.GetUriWithQueryParameters("./Machine", parameter); Navigation.NavigateTo(newuri, false); [Parameter, SupplyParameterFromQuery] public string? CPCode { get; set; } [Parameter, SupplyParameterFromQuery] public string? TermID { get; set; } === 複数変数 === var readOnlyDictionary = new Dictionary { ["film"] = 1, ["film"] = 2, }; var uri = Navigation.GetUriWithQueryParameters(readOnlyDictionary); // http://localhost:5000/MovieComparer?film=1&film=2&film=3 [Parameter, SupplyParameterFromQuery(Name = "film")] public string[]? Films { get; set; } === 参照 === * [[https://www.variablenotfound.com/2021/11/generacion-de-rutas-con-parametros-de.html|Generación de rutas con parámetros de query string en Blazor 6]] * [[https://jonhilton.net/blazor-deep-linking/|Use the Query String to pass an array of selected values between Blazor Pages]] ==== セッションの扱い(状態管理) ==== [[https://learn.microsoft.com/ja-jp/aspnet/core/blazor/state-management?view=aspnetcore-7.0&pivots=server|ASP.NET Core Blazor 状態管理]] === コンポーネント内でデータを保存し、読み込む === ブラウザー ストレージのデータの読み込みまたは保存が必要なすべてのコンポーネントで、@inject ディレクティブを使用して、次のいずれかのインスタンスを挿入します。 * ProtectedSessionStorage * ProtectedLocalStorage [[https://zenn.dev/yoshi1220/articles/8f4783ade9c06d|BlazorでWeb Storageを利用して一時的にデータを保存する方法]] === メモリ内状態コンテナー サービス === 入れ子になったコンポーネントと入れ子になっていないコンポーネントでは、登録済みのメモリ内状態コンテナーを使用してデータへのアクセスを共有できます。 == Scopeについて == ^メソッド^内容^ |AddTransient()|インジェクション毎にインスタンスを生成| |AddScoped()|リクエスト毎にインスタンスを生成| |AddSingleton()|アプリケーション内で1つのインスタンスを生成| builder.Services.AddScoped(); * [[https://zenn.dev/yoshi1220/articles/22b99b1e3717e3|BlazorにおけるDIのScopeについて]] * [[https://morioh.com/p/3c50299e2c4d|.netコアのAddScopedとAddTransientとAddSingletonの違い]] ==== injectの記載方法 ==== ディレクティブ記法でオブジェクトをインジェクトします。 @inject 【インジェクトするオブジェクトの型】 【インジェクトする変数名】 @inject StateService Service 上記の書き方以外にコードブックにて[Inject]属性を付与する記法があります。 今後コードビハインドで記述するならこっちの方が分かりやすいです。 [Inject] private StateService Service { get; set; } = default!; ==== 物理パスの取得 ==== Blazor Serverの場合、Directory.GetCurrentDirectory() を使用すればいい。 string rootpath = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "wwwroot"); * [[https://stackoverflow.com/questions/68183250/how-can-i-find-the-physical-path-of-wwwroot-in-a-blazor-app-razor-page-without|How can I find the physical path of wwwroot, in a Blazor app razor page without a controller?]] * [[https://www.c-sharpcorner.com/article/how-to-create-pdf-using-itextsharp-in-blazor/|How To Create PDF Using iTextSharp In Blazor]] ==== Web APIを追加 ==== Blazor ServerにWeb APIを追加する。 サンプル - Controllerフォルダを作成 - 右クリックメニューから[追加]の[コントローラー]をクリックする - 共通のAPIにある「読み取り/書き込みアクションがある API コントローラー」を選択して[追加]ボタンをクリックする - ValuesController.cs を追加する 下記コードをapp.Run()より前に、該当するところに追加する。 // Add MVC Controllers builder.Services.AddControllers(); app.MapRazorPages(); app.MapControllers(); Urlにてapiの後にコントローラー名を入れてアクセスすれば、値が返ってくる。 https://localhost:7072/api/Values === 参照 === * [[https://chanmingman.wordpress.com/2020/07/12/add-web-api-controller-to-blazor-project-asp-net/|Add Web API controller to Blazor project ASP.NET]] * [[https://stackoverflow.com/questions/75242436/how-to-add-controller-endpoints-to-razor-server-in-asp-net-core-7-0-vs2022|How to add controller endpoints to Razor Server in ASP.NET Core 7.0 / VS2022 - stackoverflow]] * [[https://stackoverflow.com/questions/74691624/net-7-and-useendpoints|.NET 7 and UseEndPoints() - stackoverflow]] ==== HttpClientの使用 ==== 「@Inject HttpClient httpClient」を使用すると下記エラーが発生する。 >Unhandled Promise Rejection: Error: System.InvalidOperationException: Cannot provide a value for property 'Http' on type . There is no registered service of type 'System.Net.Http.HttpClient'. * [[https://stackoverflow.com/questions/55220269/server-side-blazor-does-not-provide-httpclient-for-injection|Server-side Blazor does not provide HttpClient for injection - stackoverflow]] Injectを使用しないで、new HttpClient() とする。 ==== ボタンクリックイベントでSUBMIT処理 ==== ボタンクリックイベントでは、F1キーを入力させたようにしたいため、IsSubmit(type="submit")を使わないで制御したい。 メニューボタンをクリックしたら、入力値にF1キーをセットしてSUBMIT処理を呼ぶ。 public void OnMenuClick() { MatchViewModel Model = new(); Model.Input1 = Const.INPUT_KEY_F1; EditContext e = new(Model); OnSubmit(e); } ==== カスタムコンポーネントのbind-value ==== bind-value を指定したたけでは、"does not have a property matching the name 'ValueChanged'"エラーとなり動作しない。\\ そのため、ParameterにValueChangedを定義する。 @code { public string InputValue = "Example"; }

Welcome to Blazor Application, @Value

@code { [Parameter] public string? Value { get; set; } [Parameter] public EventCallback ValueChanged { get; set; } private async Task OnInputChange(ChangeEventArgs args ) { Value = (string?)args.Value; await ValueChanged.InvokeAsync(Value); } }
[[https://www.syncfusion.com/faq/blazor/components/how-do-you-use-bind-value-and-bind-valueevent-on-a-custom-component|How do you use bind-value and bind-value:event on a custom component?]] ==== カスタムコンポーネントで親コンポーネントの処理を実行 ==== カスタムコンポーネントのOnClickCallbackパラメータに親側の実行処理を記載する。\\ カスタムコンポーネント側のボタンをクリックすると親側の処理が実行される。 // イベント処理をラムダ式で書いた場合 await OnClickCallback.InvokeAsync()> @code { [Parameter] public EventCallback OnClickCallback { get; set; } } [[https://blazor-master.com/blazor-event-callback/|【Blazor】EventCallbackで子コンポーネントからイベントを受け取る方法]] ==== Javascriptとの連携 ==== * [[https://qiita.com/Cable08/items/6d81e1cf2df9067123cf|【Blazor】JavascriptからC#(.Net)のstaticもしくはインスタンスメソッドを呼び出す。]] * [[https://stackoverflow.com/questions/66385844/call-a-c-sharp-non-static-method-from-a-static-method-in-blazor-invoked-by-javas|Call a C# non static method from a static method in Blazor invoked by Javascript DotNet.invokeMethodAsync - stackoverflow]] * [[https://imaginet.com/2021/guide-blazor-javascript-interop/|Guide to Blazor JavaScript Interop]] ==== BlazorとjQueryの連携 ==== * [[https://gavilan.blog/2020/05/18/using-events-with-javascript-and-jquery-in-blazor-initializing-libraries/|Blazor での JavaScript および jQuery でのイベントの使用 – ライブラリの初期化]] * [[https://thesassway.com/how-to-use-jquery-in-blazor/|How to Use jQuery in Blazor]] * [[https://stackoverflow.com/questions/54274629/how-to-use-jquery-ui-from-blazor-component|How to use jQuery UI from Blazor component - stackoverflow]] * [[https://www.codeproject.com/Tips/5290232/Blazor-datepicker-Component-using-JQuery|Blazor datepicker Component using JQuery]] * [[https://github.com/dotnet/aspnetcore/issues/13732|understand the onchange listener to trigger the setter on javascript #13732]] * [[https://stackoverflow.com/questions/58777642/blazor-fire-onchange-event-when-chosen-drop-down-value-changes|Blazor fire onchange event when Chosen drop down value changes - stackoverflow]] 下記のようにすれば、onchangeイベントを呼ぶことが出来る。この方法だと DotNet.invokeMethodAsync を使わずに済む。 $("#justAnotherInputBox").on('change', function () { var myElement = $(this)[0]; var event = new Event('change'); myElement.dispatchEvent(event); console.log("Change"); }); private void OnChange(ChangeEventArgs e) { if (_comboTree != null || e.Value != null) { Console.WriteLine(e.Value); } } === @ref 属性による弊害 === inputタグに @ref 属性を付けて、 @ref="CurrentElement" として、JQuery Pluginである ComboTree に渡していた。これで問題なく表示して動作していたが、同じ画面を再度表示しようとした際に this._input.addClass や this._input.wrap で例外エラーが発生してしまう。どうも追加するinputタグが見つけれない状態 _comboTree = await _jsClass.InvokeAsync("createComboTree", CurrentElement, options); createComboTree(element, Options) { this.combo = $(element).comboTree(Options); @ref 属性ではなく、一般的なid属性の使用に切り替えることで例外エラーが発生しなくなった。 _comboTree = await _jsClass.InvokeAsync("createComboTree", "#" + ElementId, options); ==== ログ出力にlog4netを使用する ==== [[https://code-maze.com/aspnetcore-structured-logging-log4net/|Structured Logging in ASP.NET Core With log4net]] ==== デバッグ詳細 ==== an unhandled exception on the current circuit のエラーの場合、詳細エラーを出力 https://stackoverflow.com/questions/57514541/how-to-turn-on-circuitoptions-detailederrors { "DetailedErrors": true, // turns on CircuitOptions.DetailedErrors "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information", "Microsoft.AspNetCore.SignalR": "Debug" // turns on SignalR debugging } }, "AllowedHosts": "*" } ==== ブラウザのキャッシュ回避 ==== Blazorには、ASP.NET Coreにあった「asp-append-version="true"」 が見当たらない。\\ [[https://pg-himajin.com/dotnet/razor-pages/browser-cache-update/|Razor Pagesでファイル更新時にブラウザキャッシュを更新する方法]] よって、ファイルバージョンを付けて回避している。 @code { private string Version = "v=" + FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion + ""; } ==== WebSocketプロトコルを使用する ==== [サーバーの役割] ページで、[Web サーバー (IIS)] を展開し、[Web サーバー]、[アプリケーション開発] の順に展開し、[WebSocket プロトコル] を選択して、インストールする。 >Blazor Server は、WebSocket では通信できない環境であっても、Long Polling 方式に動作を切り替えて、動作継続します。 >[[https://qiita.com/jsakamoto/items/4f7bfbbb3e3ba2f31614|WebSocket で通信できない環境では Blazor Server は動作しないのか?]] ※WebSocketを使用した場合、IISログファイルに通信ログが残らなくなる。 ===== 参照 ===== * [[https://blogs.jp.infragistics.com/entry/2020/12/10/150516|Blazor プロジェクトの構成を、Blazor WebAssembly と Blazor Server を比較しながら確認する - ASP.NET Core Blazor で始めるフロントエンド 開発(入門編)- ①]] * [[https://mebee.info/2022/02/01/post-54987/|ASP.NET core 6 BlazorでUIフレームワーク「MatBlazor」を使用する]] * [[https://atmarkit.itmedia.co.jp/fdotnet/rapidmaster/rapidmaster_03/rapidmaster_03.html|C# Razor構文 基礎文法 総まとめ]] * [[https://blazor-master.com/component-lifecycle/|【Blazor】Razorコンポーネントのライフサイクルを解説する]]