はじめに
.NET Framework向けのWebフレームワークにはいくつかの選択肢がありますが、これからの開発であれば、まずASP.NET MVCの利用を考えるべきでしょう。ASP.NET MVCとは、ビューとデータロジックが明確に分離された.NET Framework製のWebフレームワークです。昨今は、Webフロントサイドの技術が次々と登場し、フロント界隈が目まぐるしく変わっています。それでもなお、ASP.NET MVCは業務Webアプリケーションのフレームワークとして柔軟に対応し、第一線で選択されています。その理由は、先に述べたように、ビューとデータロジックの分離により、さまざまなフロントサイドの技術と柔軟に組み合わせられる点にあるでしょう。また、ASP.NET MVCのIDEであるVisual Studioがフロントサイドの開発を強力にサポートしていることも、強みの一つです。
しかし、標準の機能だけでは十分にWebアプリケーションの要件を満たせない場合があります。本稿の主題でもある表はその最もたるものではないでしょうか。限られたHTMLのみで、並べ替え、フィルター、大量の行やセル、複雑な帳票の画面の実装に困憊している人も少なくないのではないでしょうか。
本連載で紹介する「SpreadJS」は、HTML5のCanvas上にExcelのような表を高速に描画し、エクセルのようにデータや表の操作が可能な高機能なJavaScriptライブラリです。SpreadJSは、クライアントサイドのライブラリなので、サーバーサイドのWebフレームワークの選択に制限はありませんが、本稿では、著者おすすめのASP.NET MVC上での導入方法を説明します。
はじめにASP.NETの現状とそれぞれの技術について説明します。その後、SpreadJS + Visual Studio 2015 + TypeScript + ASP.NET MVCでつくるWeb業務アプリケーション開発に足を踏み入れましょう。
対象読者
- Web業務アプリケーション開発者
- ASP.NET Web Forms、ASP.NET MVC開発者
- SPREAD for ASP.NET利用者
必要な環境
- Visual Studio Community 2015 Update3
3つのASP.NET
現在、Microsoftが提供する.NET Framework向けのWebフレームワークには、主に次の3つがあります。()内は、Web APIフレームワークについての補足です。
- ASP.NET Web Forms
- ASP.NET MVC(と、ASP.NET Web API)
- ASP.NET Core(Web APIとしての機能を含む)
業務Webアプリケーションとして、無難に選択するならばASP.NET MVC、条件が合えばASP.NET Coreを推奨します。
ASP.NET Web Forms
ASP.NET Web Formsは、サーバーサイドとフロントサイドを包括して開発するWebフレームワークです。まるでデスクトップアプリケーションのように開発できることが売りで、今では一枚岩のようと言われています。このASP.NET Web Formsを生かせるのは、「既存資産の活用」のメリットが勝つ場合に限ります。それでも、今後の対応を考えると大きな負債になりえますので、採択には十分な検証が必要です。また、SpreadJSのような昨今登場するフロントサイドのライブラリと組み合わせるには厳しいでしょう。
ASP.NET MVCと ASP.NET Web API
ASP.NET MVCは冒頭でも述べた通り、ビューとデータロジックが明確に分離されたWebフレームワークです。分離により、昨今のgulpやTypeScript、AngularJS等といったフロントサイド技術との組み合わせが得意です。また、ASP.NET Web APIを併用してデータをJSON形式でやりとりすることで、フロントサイドとの連携が可能です。SpreadJSでの開発においても、スプレッドシートにデータを表示する際や、編集したデータを更新する際にASP.NET Web APIを使います。
ASP.NET Core
ASP.NET Coreは、2016年6月に1.0がリリースされた全く新しいASP.NETです。先の2つのフレームワークがWindowsのIIS上で動作する一方、こちらはクロスプラットフォームに対応しています。ASP.NET MVCと同じView・Controllerに分けるアーキテクチャですが、クロスプラットフォーム化のために一から作り直しているため、ASP.NET MVCより洗練されたWebフレームワークです。その点ではASP.NET MVC開発者にとっては馴染みやすいといえます。
注意したい点は、HTTP関連のライブラリが刷新されているため、今までの慣れが通じない箇所がある点です。成熟度の違いから、ASP.NET MVCにはあるが、ASP.NET Coreにはない機能もあります。また、リリースされてから日が浅いので日本語のドキュメントが少ないです。
これらの状況を踏まえ、今業務Webアプリケーションに推奨するのはASP.NET MVC、先鋭的に選択できるならばASP.NET Coreです。
TypeScriptとVisual Studio
JavaScript開発の効率を劇的に向上させてくれるのがTypeScriptです。TypeScriptとは、コンパイルするとJavaScriptのコードを出力するAltJSの一つです。動的型付けのJavaScriptと違って静的型付けであるため、バグの発生率を抑えることができます。既存のJavaScriptライブラリを参照する際は、静的型付け言語のメリットを活かしてTypeScriptの型定義ファイルを参照します。多くの場合は、コンパイルを行うビルドツールやタスクランナーを導入します。
SpreadJSにおいては、TypeScript型定義ファイルが含まれているため、TypeScriptでの開発が可能です。また、ビルドはVisual Studioのサポートにより、プロジェクトのビルド時に行うことができます。
Visual Studioは、TypeScriptをはじめnpm、gulp、AngularJS、Sass等、さまざまなOSSライブラリのサポートが進んでいます。フロントサイド開発の際は、まずは、Visual Studio Galleryで拡張機能を検索することを推奨します。
SpreadJSとは
これまでにも少し話はしていますが、SpreadJSは、ブラウザのHTML5 Canvas上にスプレッドシートを描画するJavaScriptのライブラリです。そのため、大量の行データを高速に描画することが可能です。開発者は、セルのデザインや、数式、データのバインド等すべての操作をJavaScript(またはTypeScript)で記述します。
これらのデザインや書式の設定は、全てJavaScriptのコードで書く必要はありません。
SpreadJSの情報はJSON形式のデータとして出力でき、描画の際にそれを読み込むことができます。または、ExcelIO機能により、デザイン済みのExcelファイルの読み込みもできます。
その他、Excelファイルのエクスポート、CSVファイルのインポート/エクスポート、PDFとして出力/印刷に対応しています。
SpreadJSの公式サイトに、基本機能/チュートリアル/クライアントExcelIO/パフォーマンスのデモがありますのでご参照ください。
SPREAD for ASP.NETを利用している方へ
ASP.NET Web Forms向けとして、スプレッドシートを開発するためのライブラリ「SPREAD for ASP.NET」があります。
もし、ASP.NET Web Formsのプロジェクトにスプレッドシートを組み込む場合は、ASP.NET MVCプロジェクトへ移行し、SpreadJSの選択を推奨します。今後の機能追加や高いパフォーマンスが期待できます。
Spread for ASP.NETの経験があれば、SpreadJSの学習コストは高くありません。JavaScriptのAPIや、セル、行、数式等の概念はほぼ同じです。これは、過去にSPREAD for ASP.NETの経験がある著者が実際に感じたことです。
ASP.NET MVC、TypeScript、Visual Studio 2015で Hello, world
ここでは、サンプルとして、下の図のような表を出力するWebアプリケーションを作成します。
前期と後期を比較する表を出力します。サーバー側にHTTPリクエストを送信し、取得したJSON形式のデータを図のようにスプレッドシートに出力します。
サンプルでSpreadJSと共に使用している技術要素は次の通りです。それぞれの種類とサンプルにおける主な役割をまとめました。
技術要素 | 種類 | サンプルにおける主な役割 |
---|---|---|
ASP.NET MVC | Webフレームワーク | ページを表示します。 |
ASP.NET Web API | Web APIフレームワーク | サンプルデータをJSON形式で返すAPIを実装します。 |
TypeScript | AltJS | SpreadJSの実装をTypeScriptで記述します。 |
jQuery | JavaScriptライブラリ | HTTPリクエストを送信します。 |
ここで挙げている要素は、SpreadJSの開発に必須というわけではありません。例えば、TypeScriptではなくJavaScriptによる開発もできますし、SpreadJSはjQuery非依存なので、HTTPリクエストはSuperAgent等の他のライブラリを使うこともできます。この他、TypeScriptや他のライブラリを参照するために、npmやgulp、webpackといったツールの導入も一つの方法でしょう。
これらの組み合わせは一例ですので、SpreadJSとの併用のサンプルとしてご参照ください。
参考
本稿では手順を掲載しておりませんが、jQueryを使用せずに、SuperAgentとwebpackで構成したサンプル(「サンプルファイル(参考:jQueryを使わずに実装したもの)」)も添付しています。このサンプルを使用する場合は、WebPack Task Runner拡張機能をインストールすることを推奨します。
それでは、サンプルの実装手順を追ってみます。随時サンプルファイルをご参照下さい。
SpreadJS トライアル版を入手する
サンプルにはSpreadJSライブラリは含まれておりません。ご利用いただく場合には、別途SpreadJSのトライアル版(または製品版)をダウンロードする必要があります。ダウンロードした後、サンプル内のREADME.mdに従ってファイルを配置してください。
トライアル版を入手するには、SpreadJSのサイトの「無料評価版をダウンロード」から「トライアル版」のページにアクセスし、ライブラリをダウンロードします。ダウンロードしたzipファイルを展開し、さらに「spreadjs/spreadsheets.zip」を展開します。今回のサンプルで使用するファイルは次の通りです。
ファイルパス | 説明 |
---|---|
css/gc.spread.sheets.excel2016colorful.9.20161.0.css | スプレッドシートのテーマ(Excel2016テーマ) |
definition/GC.Spread.Sheets.d.ts | SpreadJSのTypeScript型定義ファイル。TypeScriptで記述する場合に必要です。 |
scripts/gc.spread.sheets.all.9.20161.0.min.js | SpreadJSの本体ライブラリ |
scripts/resources/ja/gc.spread.sheets.resources.ja.9.20161.0.min.js | SpreadJSを日本語で表示するためのリソース |
次の手順にて、これらのファイルをASP.NET MVCのプロジェクトに追加します。
ASP.NET MVCのプロジェクトを作成しSpreadJSを組み込む
ASP.NET MVCのプロジェクトを作成し、先ほど入手したSpreadJSのライブラリを配置し参照します。
ASP.NET MVCのプロジェクトを作成する
Visual Studio 2015を開き、メニューから[ファイル]―[新規作成]―[新しいプロジェクト]を選択し、左の欄では[テンプレート]―[Visual C#]―[Web]を選択、右の欄では[ASP.NET Webアプリケーション]を選択します。[名前]に任意の値を入力し[OK]を選択します。
表示されるダイアログにて、ASP.NET 4.6テンプレートの[Empty]を選択し、下の欄にて「MVC」と「Web API」にチェックを入れ、[OK]を選択します。
ページとWeb APIを用意する
スプレッドシートを表示するためのページをASP.NET MVCで用意し、データを取得するためのAPIをASP.NET Web APIで用意します。
[ソリューションエクスプローラー]から、[Controllers]フォルダを右クリックし、コンテキストメニューから[追加]―[コントローラー]を選択し、ダイアログにて[MVC5コントローラー – 空]―[追加]をクリックします。[コントローラー名]は「HomeController」とします。
追加されたHomeController.csのIndexメソッドを右クリックし、コンテキストメニューから[ビューを追加]を選択し、そのまま[追加]をクリックします。これで、「/(ルートURL)」で表示されるページの用意ができました。
追加されたView/Home/Index.cshtmlファイルに次のようにコードを記述します。
@{ ViewBag.Title = "SpreadJS サンプル"; } <h2>SpreadJS サンプル</h2> @* この要素にスプレッドシートを出力します *@ <div id="spread-container" style="width:100%; height:400px;"></div> @section scripts { <script src="~/ts/app.js"></script> }
コード中の「ts/app.js」は、後述の手順で用意します。
次に、ASP.NET Web APIコントローラーを追加して「api/data」のURLでアクセスできるAPIを用意します。
[Models]フォルダの配下に「ComparisonData」(前期後期を比較したデータという意味です)という名前でクラスを作成します。サンプルファイルを参照し、いくつかのプロパティを定義します。
namespace MySpreadJSSample.Models { public class ComparisonData { public string Item1 { get; set; } public string Item2 { get; set; } public decimal Previous { get; set; } public decimal Current { get; set; } } }
namespaceは、実際のプロジェクトに合わせて変更してください。
[ソリューションエクスプローラー]から、[Controllers]フォルダを右クリックし、コンテキストメニューから[追加]―[コントローラー]を選択し、ダイアログにて[Web API 2 コントローラー – 空]―[追加]をクリックします。[コントローラー名]は「ComparisonDataController」とします。サンプルデータを返す実装を記述します。これで、「api/data」でデータを取得するAPIの用意ができました。
using MySpreadJSSample.Models; using System.Collections.Generic; using System.Web.Http; namespace MySpreadJSSample.Controllers { public class ComparisonDataController : ApiController { [Route("api/data")] public IHttpActionResult GetAll() { var data = new List<ComparisonData>() { new ComparisonData() { Item1 = "現金", Item2 = "小口現金", Previous = 43288, Current = 75680 }, new ComparisonData() { Item1 = "現金", Item2 = "工場小口現金", Previous = 61065, Current = 102659 }, //省略 }; return Ok(data); } }
SpreadJSのライブラリを追加する
最初の手順で入手したSpreadJSのファイルを、プロジェクトに配置します。配置する場所は次の表の通りです。
SpreadJSのファイルパス | プロジェクトに配置する場所 |
---|---|
css/gc.spread.sheets.excel2016colorful.9.20161.0.css | Contentフォルダ配下 |
definition/GC.Spread.Sheets.d.ts | Scripts/typingsフォルダ配下(Scriptsフォルダ配下にtypingsフォルダを作成します) |
scripts/gc.spread.sheets.all.9.20161.0.min.js | Scriptsフォルダ配下 |
scripts/resources/ja/gc.spread.sheets.resources.ja.9.20161.0.min.js | Scriptsフォルダ配下 |
追加した後、「Views/Shared/_Layout.cshtml」にて、次のようにコードを追加し(置換ではなく)、SpreadJSライブラリへの参照を追加します。
<link href="~/Content/gc.spread.sheets.excel2016colorful.9.20161.0.css" rel="stylesheet" /> <meta name="spreadjs culture" content="ja-jp" />
2行目は、SpreadJSを日本語表示するための設定です。
<script src="~/Scripts/gc.spread.sheets.all.9.20161.0.min.js"></script> <script src="~/Scripts/gc.spread.sheets.resources.ja.9.20161.0.min.js"></script> @RenderSection(name: "scripts", required: false)
@RenderSectionは、Views/Home/Index.cshtml にてスクリプトを記述するために必要です。
TypeScriptファイルを追加する
SpreadJSにデータの表示やスタイルの設定を、TypeScriptで実装します。
プロジェクトルートに「ts」フォルダを作成します。作成した「ts」フォルダを右クリックし、コンテキストメニューから[追加]―[新しい項目]を選択します。表示されるダイアログの右上の欄にて、「typescript」を入力し、「TypeScript JSON 構成ファイル」を選択して追加します。同じようにして、「TypeScript ファイル」を「app.ts」という名前で追加します。
「tsconfig.json」はTypeScriptのコンパイルの設定ファイルです。ここでは、編集せず、デフォルトのままとします。
jQueryのTypeScript型定義ファイルを追加する
「app.ts」にてjQueryの処理を記述するため、jQueryのTypeScript型定義ファイルをNuGetよりインストールします。これにより、jQueryの各種APIに対して型情報が使えるようになります。
「パッケージマネージャーコンソール」にて、次のようにコマンドを実行します。パッケージマネージャーコンソールが表示されていない場合は、メニューの[表示]―[その他のウィンドウ]―[パッケージマネージャーコンソール]をクリックし表示します。
install-package jQuery.TypeScript.DefinitelyTyped
インストールが完了すると、次の図のようにファイルが追加されます。
SpreadJSの実装をTypeScriptで記述する
まずは、「ts/app.ts」ファイルに次のような簡単なコードを記述し、初期状態のスプレッドシートを出力してみましょう。F5キーよりプロジェクトをデバッグ実行します。
/// <reference path="../scripts/typings/jquery/jquery.d.ts" /> /// <reference path="../scripts/typings/gc.spread.sheets.d.ts" /> window.onload = function () { //#SS要素にスプレッドシートを設定します。シートの数は、1つとします。 //初期化 http://demo.grapecity.com/spread/spreadjs/tutorialsample/#/samples/initializeSpread let spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 1 }); }
ブラウザが起動し、次の図のように空のスプレッドシートが出力されます。この時点で、Excelのように自由に値の入力ができます。
また、プロジェクト配下に「ts/app.ts」をコンパイルした「ts/app.js」が生成されていることを確認できます。
それでは、具体的なSpreadJSの実装を行いましょう。次のコードを参照し、「ts/app.ts」にコピーし、再度ソリューションのリビルドを行い、F5キーよりデバッグ実行します(これまでの手順の設定ではリビルドを行わないと再度コンパイルが行われません)。
/// <reference path="../scripts/typings/jquery/jquery.d.ts" /> /// <reference path="../scripts/typings/gc.spread.sheets.d.ts" /> window.onload = function () { //#SS要素にスプレッドシートを設定します。シートの数は、1つとします。 //初期化 http://demo.grapecity.com/spread/spreadjs/tutorialsample/#/samples/initializeSpread let spread = new GC.Spread.Sheets.Workbook(document.getElementById("spread-container"), { sheetCount: 1 }); //ユーザーから数式入力の許可します spread.options.allowUserEditFormula = true; let sheet = spread.getSheet(0); sheet.suspendPaint(); mySpread.setup(sheet); // api/data からJSONデータを取得し、スプレッドシートにバインドします。 $.getJSON("/api/data", function (response) { let data = response; mySpread.setupDataRows(sheet, data.length); mySpread.bind(sheet, data); sheet.resumePaint(); }); } module mySpread { let rowIndexFirstDataRow = 0; let columnIndexStart = 0; let columnIndex = { Item1: 0, Item2: 1, Previous: 2, Current: 3, IncreaseDecrease: 4, IncreaseDecreasePercentage: 5 }; /** * シートにデータをバインドします * @param sheet */ export function bind(sheet: GC.Spread.Sheets.Worksheet, data: any) { sheet.setDataSource(data); } /** * シート全体の情報を設定します * @param sheet */ export function setup(sheet: GC.Spread.Sheets.Worksheet) { //行の高さ、列の自動生成を設定します sheet.autoGenerateColumns = false; sheet.defaults.rowHeight = 25; sheet.getDefaultStyle().vAlign = GC.Spread.Sheets.VerticalAlign.center; //列の情報を設定します let columnInfo = [ { name: "Item1", displayName: "項目1", size: 100 }, { name: "Item2", displayName: "項目2", size: 100 }, { name: "Previous", displayName: "前期", size: 100, formatter: "#,##0" }, { name: "Current", displayName: "当期", size: 100, formatter: "#,##0" }, { name: "IncreaseDecrease", displayName: "増減額", size: 100, formatter: "#,##0" }, { name: "IncreaseDecreasePercentage", displayName: "増減率", size: 150, formatter: "0.00%" } ]; //このcolumnInfoのnameは、sheet.setDataSource(data);でJSONデータをバインドさせるために、JSONのプロパティ名と一致する必要があります。 sheet.bindColumns(columnInfo); } /** * シートにデータ行の情報を設定します * @param sheet * @param dataRowCount */ export function setupDataRows(sheet: GC.Spread.Sheets.Worksheet, dataRowCount: number) { //フィルターの設定 http://docs.grapecity.com/help/spread-js-9/#filter.html { let range = { row: 0, col: 0, rowCount: dataRowCount, colCount: Object.keys(columnIndex).length } as GC.Spread.Sheets.Range; let filter = new GC.Spread.Sheets.Filter.HideRowFilter(range); filter.filterButtonVisible(); sheet.rowFilter(filter); } //データバールールの設定 http://docs.grapecity.com/help/spread-js-9/#databarrule.html //バーの長さは、設定範囲の相対的なデータサイズを表します。 { //前期 let range = { row: rowIndexFirstDataRow, col: columnIndex.Previous, rowCount: dataRowCount, colCount: 1 } as GC.Spread.Sheets.Range; let dataBarRule = new GC.Spread.Sheets.ConditionalFormatting.DataBarRule( GC.Spread.Sheets.ConditionalFormatting.ScaleValueType.lowestValue, 0, GC.Spread.Sheets.ConditionalFormatting.ScaleValueType.highestValue, null, "orange", [range]); sheet.conditionalFormats.addRule(dataBarRule); } { //当期 let range = { row: rowIndexFirstDataRow, col: columnIndex.Current, rowCount: dataRowCount, colCount: 1 } as GC.Spread.Sheets.Range; let dataBarRule = new GC.Spread.Sheets.ConditionalFormatting.DataBarRule( GC.Spread.Sheets.ConditionalFormatting.ScaleValueType.lowestValue, 0, GC.Spread.Sheets.ConditionalFormatting.ScaleValueType.highestValue, null, "pink", [range]); sheet.conditionalFormats.addRule(dataBarRule); } { //増減率 let range = { row: rowIndexFirstDataRow, col: columnIndex.IncreaseDecreasePercentage, rowCount: dataRowCount, colCount: 1 } as GC.Spread.Sheets.Range; let dataBarRule = new GC.Spread.Sheets.ConditionalFormatting.DataBarRule( GC.Spread.Sheets.ConditionalFormatting.ScaleValueType.lowestValue, 0, GC.Spread.Sheets.ConditionalFormatting.ScaleValueType.highestValue, null, "#FFDEAD", [range]); dataBarRule.showBorder(true); dataBarRule.borderColor("#FFA07A"); dataBarRule.useNegativeBorderColor(true); dataBarRule.negativeFillColor("#E6E6FA"); dataBarRule.negativeBorderColor("#B0C4DE"); dataBarRule.axisPosition(GC.Spread.Sheets.ConditionalFormatting.DataBarAxisPosition.cellMidPoint); sheet.conditionalFormats.addRule(dataBarRule); } //アイコンルールの設定 http://docs.grapecity.com/help/spread-js-9/#iconrule.html { let range = { row: rowIndexFirstDataRow, col: columnIndex.IncreaseDecrease, rowCount: dataRowCount, colCount: 1 } as GC.Spread.Sheets.Range; //アイコンルールを作成します //IconSetType.ThreeArrowsColored は、赤い↓、黄色い→、緑の↑ の三種類のアイコンを表します。 let iconSetRule = new GC.Spread.Sheets.ConditionalFormatting.IconSetRule( GC.Spread.Sheets.ConditionalFormatting.IconSetType.threeArrowsColored, [range]); let iconCriteria = iconSetRule.iconCriteria(); iconCriteria[0] = new GC.Spread.Sheets.ConditionalFormatting.IconCriterion(false, GC.Spread.Sheets.ConditionalFormatting.IconValueType.number, -1); iconCriteria[1] = new GC.Spread.Sheets.ConditionalFormatting.IconCriterion(true, GC.Spread.Sheets.ConditionalFormatting.IconValueType.number, 1); //アイコンとデータの両方を表示するかどうかを設定します iconSetRule.showIconOnly(false); sheet.conditionalFormats.addRule(iconSetRule); } //数式設定 //配列数式について http://demo.grapecity.com/spread/spreadjs/tutorialsample/#/samples/basicArrayFormula { //増減額(前期ー当期) sheet.setArrayFormula(rowIndexFirstDataRow, columnIndex.IncreaseDecrease, dataRowCount, 1, "D1:D" + dataRowCount + "-C1:C" + dataRowCount); //増減率 sheet.setArrayFormula(rowIndexFirstDataRow, columnIndex.IncreaseDecreasePercentage, dataRowCount, 1, "E1:E" + dataRowCount + "/C1:C" + dataRowCount); } } }
備考
コメント中のURLは、該当機能に対するSpreadJSのオンラインヘルプのURLです。チュートリアルデモにおいても、サンプルコードと共に詳しく解説されています。
ブラウザが起動し、次のようにスプレッドシートにデータが表示されることを確認します。
SpreadJSとASP.NET MVCのサンプルは、公式サイトにもありますのでご参照ください。こちらでは、ADO.NET Entity Data Modelを使用したデータのCRUDが実装されています。
おわりに
第1回は、ASP.NETを取り巻く現状を確認し、SpreadJS + Visual Studio 2015 + TypeScript + ASP.NET MVCでつくるWeb業務アプリケーション開発の第一歩を進めました。
次回は、SpreadJSの機能に着目します。