次の方法で共有


すてきな ASP.NET

Text Template Transformation Toolkit と ASP.NET MVC

K. Scott Allen

Microsoft Visual Studio には、T4 (Text Template Transformation Toolkit) というコード生成エンジンが含まれています。おそらく皆さんは、T4 が機能していることに気付かずに、Visual Studio で T4 テンプレートを既に使用されています。今回のコラムでは、T4 テンプレートの基本概要と、このテクノロジが ASP.NET MVC でどのように使用されるかについて説明します。また、MVC フレームワークを使った日常業務を強化するために、T4 テンプレートをカスタマイズする方法についても説明します。

このテンプレート ツールキットの基本となる考え方は、入力ファイルを解析して、出力ファイルに変換することです。入力ファイルはテンプレート ファイル、つまり .tt ファイル拡張子が付いたテキスト ファイルです。出力ファイルにもテキストが含まれます。このテキストは、C# コード、Visual Basic コード、Web フォーム コード、マークアップなど、生成を希望するあらゆる形式にすることができます。

T4 の動作を確認する最も簡単な方法は、Visual Studio で新しいプロジェクトを作成することです。このコラムでは C# コードを生成するため、C# コードにコンパイルされる任意のプロジェクトの種類を使用できます。プロジェクトを開いたら、そのプロジェクトを右クリックして、[追加] をポイントし、[新しい項目] をクリックします。[新しい項目の追加] ダイアログ ボックスで [テキスト ファイル] をクリックし (Visual Studio 2008 には T4 専用の項目テンプレートがありませんが、Visual Studio 2010 には存在します)、ファイルに Simple.tt という名前を付けます (.tt 拡張子を使用するようにしてください)。ファイルがプロジェクトに読み込まれると、ソリューション エクスプローラーの Simple.tt の直下に Simple.cs ファイルが表示されます (図 1 参照)。

図 1 T4 テンプレートをサポートする C# ファイル

image: C# File Behind a T4 Template

Simple.tt と Simple.cs はどちらも、起動時は空のファイルです。Simple.tt ファイルを右クリックして [プロパティ] をクリックすると、Visual Studio によって、ファイルのカスタム ツールとして TextTemplatingFileGenerator が割り当てられていることがわかります (図 2 参照)。このジェネレーターが、テンプレート ファイルから C# コードを収容したファイルに変換する T4 エンジンです。

図 2 T4 テンプレートのプロパティ

image: Properties of the T4 Template

テンプレートでなんらかの処理を実行できるようにするには、次のコードを追加します。

<#@ template language="c#v3.5" #>
<#@ assembly name="System.Web.Mvc.DLL" #>
<#@ import namespace="System.Web.Mvc" #>

public class Test
{
<# for(int i = 0; i < 5; i++) { #> 
  public int Prop<#= i #> { get; set; }
<# } #>
}

コードは、いくつかのディレクティブから始まります。ディレクティブでは、テンプレートのプログラミング言語を指定でき、コードで必要な名前空間とアセンブリを "テンプレート" に含めることができます。間違えないでいただきたいのですが、ここでお話しているのは、プロジェクト自体のコードではなく、テンプレート内のコードを実行するのに必要な設定についてです。ディレクティブを使って、出力ファイルの拡張子を指定することもできます。既定の設定は C# ですが、前述のとおり、Visual Basic コード、XML、HTML など、任意のテキスト ファイルを生成できます。

今回使用しているディレクティブでは、Microsoft .NET Framework 3.5 に付属する C# コンパイラを使用するよう、テンプレート エンジンに指示しています。また、ASP.NET MVC アセンブリを参照して、System.Web.Mvc 名前空間をスコープに含めることも指示しています。MVC のアセンブリと名前空間は、今回のテンプレートの単純なコードに実際に必要なわけではなく、例としてテンプレートに収めました。

ディレクティブの次にあり、<# と #> で区切られていないテキストは出力ファイルにそのまま挿入されます。<# と #> の間にあるテキストは C# コードです。テンプレート エンジンはこのコードを解析して、その結果を実行用クラス (最終的には、Microsoft.VisualStudio.TextTemplating アセンブリの TextTransformation クラスから派生するクラス) に追加します。このプロセスは、.aspx ファイル内のコードとマークアップを、最終的に System.Web.UI.Page から派生するクラスに追加する、ASP.NET のビュー エンジンのプロセスによく似ています。Web フォームのビュー エンジンを使用して MVC ビューを記述したことがあれば、このテンプレートも問題なく作成できると感じるでしょう。.aspx ファイルでは、C# コードを使用して HTML を生成できます。今回の .tt ファイルでは、C# コードを使用して C# コードを生成します。

Simple.tt に含まれているコードからは、Simple.tt.cs に次のような C# 出力が生成されます。

public class Test
{
  public int Prop0 { get; set; }
  public int Prop1 { get; set; }
  public int Prop2 { get; set; }
  public int Prop3 { get; set; }
  public int Prop4 { get; set; }
}

もちろん、Test クラスはまったく意味がなく、つまらないものですが、T4 テンプレートに内在する可能性について、いくつかアイデアが浮かぶと思います。テンプレート内で C# コードを記述することから、データベースに接続できます。ファイル システムからデータを読み取ることができます。XML を解析できます。.NET クラスを使用して、環境内のどこかにあるメタデータに接続してその内容を読み取ることができます。こうしたメタデータは、データベース スキーマや別のアセンブリ内の型のように、クラスの生成に使用できる情報です。生成されるクラスは、現在のプロジェクトの一部になるため、現在のアセンブリにコンパイルして、アプリケーション内で使用できます。

T4 の編集

Visual Studio で T4 テンプレートを編集するときは、IDE の言語サービス (IntelliSense や構文の強調表示) の支援を受けることができません。これには 2 つの解決策があります。1 つは、Clarius Consulting から入手できる Visual T4 Editor (https://visualstudiogallery.msdn.microsoft.com/40a887aa-f3be-40ec-a85d-37044b239591、英語) です。もう 1 つは、tangible engineering から入手できる tangible T4 Editor (t4-editor.tangible-engineering.com、英語) です。

T4 テンプレートのしくみの基本を理解したところで、MVC フレームワークが T4 テンプレートをどのように使用するかについて見ていくことにしましょう。

ASP.NET MVC における T4

ASP.NET MVC プロジェクトでは、"Add View (ビューの追加)" や "Add Controller (コントローラーの追加)" 機能を使用するたびに、T4 テンプレートを使用しています。これらのテンプレートは、Visual Studio をインストールした Common7\IDE\ItemTemplates\CSharp\Web\MVC 2\CodeTemplates フォルダーにあります。このテンプレートには Visual Basic バージョンもありますが、このパスについては、読者の皆様のフォルダー名推測の演習とします。

それぞれのテンプレート自体は、T4 の価値と機能に関する優れたお手本になります。たとえば、次の CodeTemplates の AddView サブフォルダーに含まれる List.tt からの抜粋をご覧ください。

if(!String.IsNullOrEmpty(mvcViewDataTypeGenericString)) {
  Dictionary<string, string> properties = 
    new Dictionary<string, string>();
  FilterProperties(mvcHost.ViewDataType, properties);
#>