対象読者
C#とWebシステムの基礎的な知識がある方を対象とします。C#の基本文法などの解説は割愛します。
ComponentOne for Blazorとは
「ComponentOne」は、グレープシティ株式会社が販売する業務アプリケーション向けの.NET環境用コンポーネントセットです。これまでもMicrosoftのテクノロジーに適応して開発されてきましたが、バージョン2020J v3では、ASP.NET Core Blazor(以下Blazor)を用いたアプリケーション開発にも対応しました。
Blazorとは、.NET環境で対話型のWeb UIを構築するためのフレームワークです。JavaScriptの代わりにC#言語を使用して、SPA(Single Page Application)を実現できます。Blazor自体については、「ASP.NET Core Blazorチュートリアル」を参照してください。
ComponentOne 2020J v3に含まれる「ComponentOne for Blazor」は、BlazorによるWebアプリケーション開発のための限定したコンポーネントセットです。業務システムに要求されるデータグリッド、チャート、入力といったユーザーインタフェースを、Blazor WebAssemblyとBlazor Serverアプリケーションに付加することができます。
ComponentOne Enterprise 2020J v3
バージョン2020J v3では、Blazor対応だけではなく、2020年11月にリリースされた.NETの最新バージョンである「.NET 5」フレームワークに対応しています。以前から提供されてきたデータグリッドコントロール「FlexGrid」や、チャートコントロール「FlexChart」などで、.NET 5をサポートしています。詳細については、グレープシティのページでご確認ください。
ComponentOne for Blazorのコンポーネント
ComponentOne for Blazorでは、FlexGrid、FlexChartだけでなく、次のようなコントロールが提供されています。
Blazorで利用可能なコントロール
- グリッド&データ管理:FlexGrid、ListView、DataPager
- データ可視化:FlexChart、FlexPie、TreeMap
- 入力&編集:ComboBox、AutoComplete、NumericBox、TimeEditor、DatePicker、DateTimePicker
- スケジュール:Calendar
これらのコントロールを組み込むことで、複雑な業務アプリケーションであっても、容易にBlazorで実現可能です。ComponentOne for Blazorには、数多くのサンプルが収録され、各種ドキュメントもWebサイトで公開されています。開発にあたってのハードルも高くないでしょう。
ComponentOne for Blazorを使ったBlazorアプリ
本記事では、ComponentOne for Blazorで提供されるコントロールのうち、FlexGridとFlexChartを使ったBlazorアプリケーション(Blazor WebAssembly App)を作成します。
グリッドコンポーネント「FlexGrid」
FlexGridは、多彩な表現ができるグリッドコンポーネントで、その歴史の始まりは、1996年のVisual Basic用VBXアドインまで遡ることができます。ComponentOne for BlazorのFlexGridでも、データバインディングや書式設定などの機能を柔軟なAPIを使って開発ができ、シンプルな記述で高機能なデータ表示が可能です。ExcelライクなUIも実現しています。
チャートコンポーネント「FlexChart」
柔軟にデータの視覚化できるチャートコンポーネントであるFlexChartも、始まりはデスクトップ向けのコントロールで、FlexGridと共に発展しました。ComponentOne for BlazorのFlexChartでも、縦横の棒グラフを始め、折れ線、面、円、ステップ、散布図、バブルチャートなどを表示できます。
コンポーネントのインストール
ComponentOne for Blazorを利用するにあたって、最初にインストールが必要です。インストーラーを実行すると、次の画面が表示されます。
ここで、Blazor Editionにチェックを入れて、続行をクリックします。コンポーネントのインストールが完了した後は、ライセンスメニューからライセンス認証を行います。
FlexGridでオープンデータを表示する(ローカルWeb APIの作成まで)
FlexGridを利用して、次のようなページを作成します。
新型コロナウイルス関連のオープンデータとして「COVID-19 Japan Web API」で提供されている都道府県毎の感染者数を利用しています。
プロジェクトの新規作成
Visual Studioを起動して、新しいプロジェクトの作成を選択し、プロジェクトテンプレートとして、Blazor WebAssemblyアプリを選択します。プロジェクト名(BlazorAppCovid19)を設定した後、次の追加情報ダイアログでは、ターゲットフレームワークを.NET5.0にして、「ASP.NET Coreでホストされた」に必ずチェックを入れます。
「ASP.NET Coreでホストされた」にチェックを入れると、生成されるソリューションには、Blazorアプリ単体(BlazorAppCovid19.Client)、ASP.NET Core(BlazorAppCovid19.Server)、さらにソリューション全体で共有するクラスを定義するプロジェクト(BlazorAppCovid19.Shared)と、3つのプロジェクトが生成されます。
今回は外部サイトのWebAPIを利用しますが、その場合、同一生成元ポリシー(Same-Origin Policy)という考え方に基づき、ブラウザ上で動作するプログラムでは、異なるサイトのアクセスが制約されることがあります。これはセキュリティ攻撃を防止するためのもので、回避するにはサイト側でアクセスを許可する設定(CORS、Cross-Origin Resource Sharingと呼ばれる仕組み)が必要となります。
そのため、Blazorアプリ単体で直接アクセスするのではなく、ローカルでASP.NET CoreのWeb APIサーバーを作成し(ASP.NET Core hosted)、ASP.NET Coreで外部WebAPIを参照するようにします。ASP.NET Coreのプログラムでは、外部サイトのアクセスに制限はありません。Blazorアプリは、ローカルのWeb APIを通じて、外部サイトとアクセスする形になります。
なお今回のソリューションファイルのうち、編集、追加するファイルは以下の通りです。
BlazorAppCovid19.Client
- \wwwroot\index.html:トップページ(編集)
- \Shared\NavMenu.razor:各ページに遷移するメニュー(編集)
- \Pages\PrefecturesSum.razor:都道府県毎の累計グリッド表示(新規)
- \Pages\Chart.razor:東京都の日別感染者数グラフ表示(新規)
BlazorAppCovid19.Server
- \Controllers\Covid19Controller.cs:Web API(コントローラー)クラス(新規)
BlazorAppCovid19.Shared
- \Covid19.cs:共有オブジェクトの定義(新規)
プロジェクトにパッケージを組み込む
プロジェクトのひな形が作成できたところで、プロジェクトにFlexGrid、FlexChartのパッケージをNuGetを使って組み込みます。Visual Studioのソリューションエクスプローラーで、先頭のソリューションを選択して右クリックし、表示されたメニューから[ソリューションのNuGet パッケージの管理]を選びます。そして参照タブをクリックし、「C1.Blazor.Grid.Ja」を検索します。右ペインのプロジェクトで、ClientとServerにチェックして、インストールボタンをクリックします。同様に、「C1.Blazor.Chart.Ja」もインストールします。
次に、プロジェクトのwwwrootフォルダにある、index.htmlを開き、<head>タグ内にCSSファイルと、<body>タグ内の最後にJavaScriptファイルのURLを追加します。
~略~ <link rel="stylesheet" href="/_content/C1.Blazor.Core/styles.css" /> <link rel="stylesheet" href="/_content/C1.Blazor.Grid/styles.css" /> <link rel="stylesheet" href="/_content/C1.Blazor.ListView/styles.css" /> <link rel="stylesheet" href="/_content/C1.Blazor.Input/styles.css" /> </head> ~略~ <script src="/_content/C1.Blazor.Core/scripts.js"></script> <script src="/_content/C1.Blazor.Input/scripts.js"></script> <script src="/_content/C1.Blazor.Grid/scripts.js"></script> <script src="/_content/C1.Blazor.Chart/scripts.js"></script> </body> ~略~
FlexGridで表示するオブジェクトの定義
今度は、FlexGridで表示するデータを準備します。FlexGridのデータソースとしては、配列やListオブジェクトを設定することができます。ここでは、都道府県毎の累計数を示すエンティティクラスPrefectureListを定義しました。陽性率などは、プロパティを使って計算した値を返すようにしています。
~略~ // 都道府県毎の累計 public class PrefectureList { public string Name_ja { get; set; } // 都道府県 public int Population { get; set; } // 人口 public int Cases { get; set; } // 陽性者数 public int Deaths { get; set; } // 死亡者数 public int Pcr { get; set; } // 検査数 public int Hospitalize { get; set; } // 入院患者数 public int Severe { get; set; } // 重症者数 // 陽性率 public float Positive_rate => Cases * 100f / Pcr; // 死亡率 public float Deaths_rate => Deaths * 100f / Cases; // 人口10万人あたりの陽性者数 public float CasesHt => Cases * 100000f / Population; } ~略~
このクラスを定義するファイルは、Blazorアプリ単体とASP.NET Coreサーバーで共通して利用できるように作成します。ソリューションエクスプローラーで、プロジェクト名.Sharedフォルダを選択して、右クリックして表示されるメニューから、[追加]-[新しい項目]を選びます。次にクラスを選択し、ファイル名(本記事ではCovid19.cs)を入力して追加します。
ローカルのWeb APIを作成する
次は、このPrefectureListの配列をJSONデータとして返すWeb APIを作成しましょう。ASP.NET Coreサーバープロジェクトに処理を追加します。大部分は、ひな形のフレームワーク(ASP.NET Core Web API)でまかなえますので、追加するコードは多くありません。
ソリューションエクスプローラーで、プロジェクト名.ServerにあるControllersフォルダを選択して、右クリックして表示されるメニューから、[追加]-[コントローラー]を選びます。
次の画面では、APIコントローラー-空を選択して、追加ボタンをクリックします。さらにファイル名(Covid19Controller.cs)を入力して、追加ボタンをクリックします。追加されるファイルは、ControllerBaseクラスを継承した、Web APIのコントローラークラスです。クラスの内容を次のように変更します。
~略~ [ApiController] [Route("api/[controller]")] public class Covid19Controller : ControllerBase { static readonly HttpClient Client = new HttpClient(); // 外部APIのJSONデータ参照用クラス private class Prefecture { ~略~ } ~略~ [Route("Prefectures")] public IEnumerable<PrefectureList> GetPrefectures() { // JSONデータをPrefectureオブジェクトの配列に変換する(1) var prefecture = Client.GetFromJsonAsync<Prefecture[]>( "https://covid19-japan-web-api.now.sh/api/v1/prefectures").Result; var list = new List<PrefectureList>(); foreach (Prefecture p in prefecture) { // PrefectureListオブジェクトに変換する(2) list.Add(new PrefectureList { Name_ja = p.name_ja, Pcr = p.pcr, Cases = p.cases, Deaths = p.deaths, Hospitalize = p.hospitalize, Severe = p.severe, Population = p.population }); } return list; } } ~略~
都道府県毎の感染者数APIからは、次のようなJSONデータが返却されるので、GetFromJsonAsyncメソッドを使って、いったんC#のオブジェクト(Prefecture[])に変換します(1)。
[ { "id":1, "name_ja":"北海道", "name_en":"Hokkaido", "lat":43.46722222, "lng":142.8277778, "population":5248552, "last_updated":{ ~略~ }, "cases":18674, "deaths":647, "pcr":361220, "hospitalize":798, "severe":13, "discharge":17229, "symptom_confirming":0 }, ~略~
その後に必要なデータのみを参照して、PrefectureListオブジェクトに変換します(2)。
Prefectureクラスは、一時的にJSONデータを保持するためのエンティティクラスで、Visual Studioの機能を利用して作成可能です。このAPIのURLをブラウザ等でアクセスし、得られたJSONデータをコピーします。そして、Visual Studioの編集メニューから、[形式を選択して貼り付け]-[JSONをクラスとして貼り付ける]を選ぶと、JSONデータの内容に応じたエンティティクラスが自動で生成できます。
なお、コントローラークラスのメソッドのルーティングは、Route属性で指定しています。GetPrefecturesメソッドは、[https://localhost:44383/]api/covid19/prefecturesというURLで呼び出されるようになります。またこのメソッドでは、単にListオブジェクトを返しているだけですが、これだけでJSON文字列を返すWeb APIとなります。
FlexGridでオープンデータを表示する(ページの作成から)
FlexGridを表示するページの作成
最後にFlexGridで表示するRazorページを追加しましょう。
@page "/prefecturessum" ~略~ <FlexGrid Class="custom" ItemsSource="prefectures" DefaultColumnWidth="GridLength.Star" AutoGenerateColumns="false" ColumnHeaderStyle="@("font-weight:bold;")"> <FlexGridColumns> <GridColumn Binding="Name_ja" Header="都道府県" HorizontalAlignment="C1HorizontalAlignment.Center"></GridColumn> <GridColumn Binding="Cases" Format="N0" Header="陽性" HorizontalAlignment="C1HorizontalAlignment.Right"></GridColumn> <GridColumn Binding="CasesHt" Format="N1" Header="10万人" HorizontalAlignment="C1HorizontalAlignment.Right"></GridColumn> ~略~ </FlexGridColumns> </FlexGrid> ~略~ @code { // 都道府県毎の累計 private PrefectureList[] prefectures; protected override async Task OnInitializedAsync() { // ASP.NET Core Web APIからJSONデータを取得する prefectures = await Http.GetFromJsonAsync<PrefectureList[]>("api/covid19/prefectures"); } }
FlexGridは、Blazorコンポーネントになっており、最低限データソースをItemsSource属性に設定するだけで表示が可能です。ここでは、<FlexGridColumns>タグで、各項目の名称や書式を設定しています。
FlexGridのデータソースは、PrefectureListオブジェクトの配列とし、先ほど作成したAPIからGetFromJsonAsyncメソッドで取得しています。
FlexGridでの表示は、単なるテーブルに見えますが、項目名をクリックすることで、その項目をキーとしたソートが可能です。またセルをクリックすることで、編集可能になります。値を変更すると、PrefectureListクラスで定義された式に応じて、陽性率や死亡率が動的に再計算されることがわかります。
FlexChartでオープンデータをグラフ表示する
次は、FlexChartを使ってみましょう。こちらも、データソースの準備に関しては、FlexGridと同じ流れになります。なお元のデータとして、新型コロナウイルス感染症対策推進室で公開されている日毎の感染者数を利用します。
データソースの準備
FlexChartで表示するデータのエンティティクラスとして、次のように定義しました。
// 日毎の陽性者数 public class NewCases { public DateTime Date { get; set; } // 日付 public int Cases { get; set; } // 新規陽性者数 public float Avg7 { get; set; } // 7日間移動平均(新規陽性者) }
このJSONデータを返すWebAPIは、先ほどのCovid19Controllersクラスに、新しいメソッド(GetNewCases)を追加して作成します。
~略~ // 外部APIのJSONデータ参照用クラス private class JapanAll { ~略~ } [Route("newcases/{pref}")] public IEnumerable<NewCases> GetNewCases(string pref) { // 日毎の累計数 var japanall = Client.GetFromJsonAsync<JapanAll>( $"https://opendata.corona.go.jp/api/Covid19JapanAll?dataName={pref}").Result; // 日毎の陽性者数 var list = new List<NewCases>(); // 日毎の累計数から新規、平均の陽性者を計算する for (int i = 0; i < japanall.itemList.Count - 7; i++) { list.Add(new NewCases { Date = japanall.itemList[i].date, // 前日との累計差が新規陽性者数(1) Cases = japanall.itemList[i].npatients - japanall.itemList[i + 1].npatients, // 過去7日の累計差から7日間移動平均を求める(2) Avg7 = (float)Math.Round((japanall.itemList[i].npatients - japanall.itemList[i + 7].npatients) / 7f, 1, MidpointRounding.AwayFromZero) }); } return list; }
追加したGetNewCasesメソッドでは、前述のGetPrefecturesメソッドと同様に、外部のWeb APIから返却されるJSONデータを、いったんC#のオブジェクト(JapanAll[])に変換しています。このAPIでのJSONデータは次のようになっていて、itemListプロパティに、時系列の昇順で陽性者の累計数が入っています。
{ ~略~ "itemList":[ { "date":"2021-02-18", "name_jp":"東京都", "npatients":"108782" }, { "date":"2021-02-17", "name_jp":"東京都", "npatients":"108337" }, ~略~
データには日毎の累計数しかないので、前日と7日前の累計を利用して、新規陽性者数(1)と、新規陽性者数の7日間移動平均(2)を計算して、NewCasesオブジェクトに変換しています。
Route属性の{pref}は、都道府県名を指定するパラメータです。例えば、/api/covid19/newcases/東京都とアクセスした場合、prefには「東京都」の文字列が設定されます。
FlexChartを表示するページの作成
FlexChartを表示するページは、次のようなコードになります。
<FlexChart Class="chart" HeaderContent="日毎の陽性者数" HeaderStyle="font-size:20px" LegendPosition="Position.Top" LegendStyle="font-size:16px" BindingX="Date" ItemsSource="itemssource"> <SeriesCollection> <Series Name="陽性者数" ChartType="ChartType.Column" Binding="Cases" /> <Series Name="7日間移動平均" ChartType="ChartType.Line" Binding="Avg7" /> </SeriesCollection> <AxisCollection> <Axis AxisType="AxisType.X" Position="Position.Bottom" MajorGrid="true" /> <Axis AxisType="AxisType.Y" Position="Position.Left" MajorGrid="true" Min="0" Max="2500" /> </AxisCollection> </FlexChart> @code { // 日毎の陽性者数 private NewCases[] itemssource; protected override async Task OnInitializedAsync() { // ASP.NET Core Web APIからJSONデータを取得する itemssource = await Http.GetFromJsonAsync<NewCases[]>( "/api/covid19/newcases/東京都"); } }
FlexGrid同様、FlexChartもBlazorコンポーネントになっています。データソースをItemsSource属性、X軸に設定するプロパティをBindingX属性で指定します。
また、Y軸に表示するデータ系列は、SeriesCollectionタグで指定します。データ系列を複数個指定することも可能で、今回は陽性者数と、7日間移動平均の2つを設定しています。各データ系列は、Seriesタグを使って、名前や対応するプロパティ、グラフの種類などを設定します。グラフ種類で指定している値の意味は、ChartType.Columnが縦の棒グラフ、ChartType.Lineは折れ線グラフを示します。
AxisCollectionタグは、縦軸(Y軸)、横軸(X軸)の設定です。こちらも複数の軸の指定が可能です。各軸は、Axisタグを使って、表示位置や値の範囲などを設定します。MajorGrid属性は、軸のグリッド線の表示指定です。
最後に
本記事では、「ComponentOne for Blazor」に同梱されるFlexGrid、FlexChartを利用したBlazorアプリケーションの開発手順を紹介しました。FlexGrid、FlexChart以外にも、業務アプリを効率的に開発できるコントロールがそろっています。ComponentOneは、Blazorであっても、業務システム開発には欠かせない定番ライブラリとなることは間違いないでしょう。