ASP.NET

ASP.NET Web フォームから ASP.NET Web API を使った MVC パターンへの移行

Peter Vogel

 

最近 ASP.NET MVC に大きな注目が集まりがちですが、ASP.NET Web フォームとその関連コントロールを使用すれば、開発者は優れた対話型のユーザー インターフェイスを短時間で生成できるため、多くの ASP.NET Web フォーム アプリケーションが利用されています。ただし、ASP.NET Web フォームでは、テスト駆動開発 (TDD) を可能にする、モデル - ビュー - コントローラー (MVC: Model-View-Controller) パターンとモデル - ビュー - ビューモデル (MVVM: Model-View-ViewModel) パターンの実装がサポートされません。

ASP.NET Web API (以下「Web API」) は、分離コード ファイルから Web API コントローラーにコードを移行することによって、ASP.NET Web フォーム アプリケーションを MVC パターンにビルドまたはリファクタリングする方法を提供します。このプロセスにより、ASP.NET アプリケーションから Asynchronous JavaScript and XML (AJAX) を利用できるようにもなります。AJAX を使用し、ロジックをクライアントに移動してサーバーとのやり取りを減らすことによって、応答性の高い UI を作成でき、アプリケーションのスケーラビリティを向上できます。これが可能になるのは、Web API が HTTP プロトコルを活用し、(規約によるコーディングによって) いくつかの低レベルのタスクを自動的に処理するためです。今回目的とする ASP.NET の Web API パラダイムは、ブラウザーに送信するマークアップの初期セットを ASP.NET で生成し、スタンドアロンのテスト可能なコントローラーに対する AJAX 呼び出しを使って、ユーザーとのすべての対話を処理できるようにすることです。

Web フォーム アプリケーションが一連の AJAX 呼び出しを使ってサーバーと対話できるようにするインフラストラクチャをセットアップするのは難しくありません。ただし、Web フォーム アプリケーションのコード ファイル内のコードを、Web API コントローラーで機能するようにリファクタリングするのは簡単ではありません。コントローラーから発生するさまざまなイベント、自動生成されるサーバー側検証、およびビューステートの使用を断念する必要があります。ただし、このような機能を使用しないで済むような回避策がいくつかあります。

Web API インフラストラクチャの追加

ASP.NET プロジェクトで Web API を使用するには、(NuGet Microsoft ASP.NET Web API パッケージを追加後) プロジェクトを右クリックし、[追加]、[新しいアイテム]、[Web API Controller Class] の順にクリックするだけです。ダイアログ ボックスに Web API Controller Class が見当たらない場合は、NuGet Microsoft ASP.NET Web API パッケージがインストールされていて、目的のプログラミング言語の項目で Web フォームを選択していることを確認してください。ただし、この方法でコントローラーを追加すると、作成されるクラスに多くの既定のコードが含まれるため、不要なコードを後で削除する必要が生じます。単純に通常のクラス ファイルを追加し、System.Web.Http.ApiController から継承するクラスを含めてもかまいません。ASP.NET ルーティング インフラストラクチャで機能させるには、クラス名の末尾に文字列 "Controller" を付けなければなりません。

今回の例では、次のように Customer という Web API コントローラーを作成します。

public class CustomerController : ApiController
{

Web API コントローラーでは規約によるコーディングが数多くサポートされています。たとえば、フォームをサーバーにポストバックするときに必ず呼び出されるメソッドが必要であれば、"Post" というメソッドまたは "Post" で始まる名前のメソッドを用意するだけです (その結果、サーバーにポストバックされるページは HTTP POST 動詞を使ってサーバーに送信されます。つまり、Web API は要求の HTTP 動詞を基にメソッドを選択します)。このようなメソッド名が社内のコーディング規約に違反する場合は、サーバーにデータをポストするときに使用するメソッドに HttpPost 属性でフラグを付けることができます。次のコードは、Customer コントローラー内に HTTP ポストを処理する UpdateCustomer メソッドを作成しています。

public class CustomerController : ApiController
{
  [HttpPost]
  public void UpdateCustomer()
  {

ポスト メソッドは、1 つしかパラメーターを受け取りません (複数のパラメーターを受け取るポスト メソッドは無視されます)。ポスト メソッドに送信できる最もシンプルなデータは、ポストの本文に含まれる等号で始まる単一値 (例、"=ALFKI") です。以下の例のようにポスト メソッドの 1 つのパラメーターが FromBody 属性で装飾されていると、Web API はこのデータをそのパラメーターに自動的にマップします。

[HttpPost]
public HttpResponseMessage UpdateCustomer([FromBody] string CustID)
{

もちろん、このままではほとんど役に立ちません。たとえば、Web フォームのデータのように、複数の値をポストバックする場合は、Web フォームの値を保持するクラスを定義する必要があります。つまり、データ転送オブジェクト (DTO) を定義する必要があります。ここで Web API コーディング規約の標準が役に立ちます。開発者は、Web フォームのコントロールに関連付けられた名前に対応する名前のプロパティを含むクラスを定義するだけです。Web API がこの DTO プロパティに Web フォームのデータを自動的に設定します。

Web API コントローラーにポストバックできるデータの例として、テキスト ボックス を 3 つ、RequiredFieldValidator を 1 つ、およびボタンを 1 つ備えたシンプルなサンプル Web フォームを用意します (図 1 参照)。

図 1 基本サンプル Web フォーム

<form id="form1" runat="server">
<p>
  Company Id: <asp:TextBox ID="CustomerID"
    ClientIDMode="Static" runat="server">
    </asp:TextBox> <br/>
  Company Name: <asp:TextBox ID="CompanyName"
    ClientIDMode="Static" runat="server">
    </asp:TextBox>
  <asp:RequiredFieldValidator ID="RequiredFieldValidator1"
    runat="server" ControlToValidate="CompanyName"
    Display="Dynamic"
    ErrorMessage="Company Name must be provided">
  </asp:RequiredFieldValidator><br/>
  City: <asp:TextBox ID="City"
    ClientIDMode="Static" runat="server"> 
    </asp:TextBox><br/>
</p>
<p>
  <asp:Button ID="PostButton" runat="server" Text="Update" />
</p>
</form>

ポスト メソッドがこの Web フォームのテキスト ボックスのデータを受け取るようにするには、次のようにテキスト ボックスの ID プロパティと一致する名前のプロパティを含むクラスを作成します (Web API は、Web フォームに含まれていても一致するプロパティがないコントロールは無視します)。

public class CustomerDTO
{
  public string CustomerID { get; set; }
  public string CompanyName { get; set; }
  public string City { get; set; }
}

このような標準では対応できない (Web API のバインド機能を超える) DTO を必要とする複雑な Web フォームの場合は、Web フォームのコントロールのデータを DTO プロパティにマップする独自のモデル バインダーを作成できます。リファクタリングを行う場合、Web フォームのコードが既に ASP.NET コントロールの名前を操作している (DTO に同じ名前のプロパティがある) ときは、このコードを Web API コントローラーに移行する際に必要な作業が少なくなります。

Web フォームのルーティング

Web API を ASPX Web フォーム処理サイクルに統合する次の手順では、フォームのポストバックをコントローラーにリダイレクトするルーティングの規則をアプリケーションの Global.asax ファイルの Application_Start イベントで指定します。ルーティングの規則は、その規則を適用する URL と要求を処理するコントローラーを指定するテンプレートで構成されます。このテンプレートでは、Web API が使用する値 (コントローラーのメソッドに渡す値など) を検索する URL 内の場所も指定します。

ここでは、いくつか標準の手法もありますが、これは無視してもかまいません。標準ルーティング規則はほぼすべての URL に対応付けることができるため、規則を適用するつもりのない URL に適用されると、予期しない結果につながることがあります。これを避けるためにマイクロソフトが推奨するベスト プラクティスでは、他の場所で使用する URL と競合しないように、Web API を関連付ける URL は文字列 "api" で始めるようにします。この "api" は何か役立つ機能を実行するわけでなく、単に URL に付加されるだけです。

まとめると、Application_Start イベントに含める汎用化したルーティング規則は次のようになります (このコードをサポートするには、System.Web.Routing と System.Web.Http の両方に対する using ステートメントを Global.asax に追加する必要があります)。

RouteTable.Routes.MapHttpRoute(
  "API Default",
  "api/{controller}/{id}",
  new { id = RouteParameter.Optional })
);

このルーティングではテンプレートの 2 番目のパラメーターからコントローラーを抽出するため、URL がコントローラーに密接に関連付けられることになります。コントローラー名を変更すると、この URL を使用するすべてのクライアントが機能を停止します (テンプレートによって URL でマップするパラメーターは "id" よりも意味のある名前にすることもお勧めします)。テンプレート内にコントローラー名を必要としないもっと明確なルーティング規則を用意し、コントローラー名を MapHttpRoute メソッドの 3 番目のパラメーターに既定で指定することをお勧めします。今回のルーティング規則のテンプレートをもっと明確にすることによって、Web API コントローラーで使用する URL の特殊なプレフィックスの必要性がなくなり、ルーティング規則の結果に驚くことはほとんどなくなります。

今回のルーティング規則は次のコードのようになります。ここでは "CustomerManagement" (サーバー名とサイト名を繋げた名前) で始まる URL のみに適用される CustomerManagementPost というルートを作成します。

RouteTable.Routes.MapHttpRoute(
  "CustomerManagementPost",
  "CustomerManagement",
  new { Controller = "Customer" },
  new { httpMethod = new HttpMethodConstraint("Post") }
);

この規則は、たとえば、www.phivs.com/CustomerManagement のような URL のみに適用されることになります。既定では、この URL は Customer コントローラーに結び付けられます。ルートが意図どおりにのみ使用されることを確認するためだけに、4 番目のパラメーターを使用して、データが HTTP POST として送り返されるときのみこのルートが使用されることを指定しています。

コントローラーへのリファクタリング

既存の Web フォームをリファクタリングしている場合は、次の手順として Web フォームを取得し、フォームのデータを Web フォーム自体にポストバックするのではなく、新しく定義したルートにポストします。これが既存のコードへの最初の変更点です (ここまでは既存の処理をそのまま残し、コードを追加してきました)。変更後の form タグは次のようになります。

<form id="form1" runat="server" action="CustomerManagement"
   method="post" enctype="application/x-www-form-urlencoded">

ここでの主な変更点は、ルートで指定された URL ("CustomerManagement") を使用するように form タグの action 属性を設定することです。method 属性と enctype 属性は、ブラウザー間の互換性を確保するために設定しています。ページがコントローラーにポストバックされるとき、Web API は自動的にポスト メソッドを呼び出します。このとき、Web API はポスト メソッドに渡すクラスのインスタンスを作成し、Web フォームのデータを DTO のプロパティにマップ後、この DTO をポスト メソッドに渡します。

ここまでの準備をすべて終えたら、DTO 内のデータを操作するコードをコントローラーのポスト メソッドに記述できるようになります。以下のコードは、Web フォームから渡されたデータを使用して、Northwind データベースに基づくモデルの対応する Entity Framework のエンティティ オブジェクトを更新します。

[HttpPost]
public void UpdateCustomer(CustomerDTO custDTO)
{
  Northwind ne = new Northwind();
  Customer cust = (from c in ne.Customers
                   where c.CustomerID == custDTO.CustomerID
                   select c).SingleOrDefault();
  if (cust != null)
  {
    cust.CompanyName = custDTO.CompanyName;
  }
  ne.SaveChanges();

処理の完了時にはなんらかのデータをクライアントに送り返す必要があります。最初は、単にユーザーにリダイレクトするように構成した HttpResponseMessage オブジェクトをサイト内の別の ASPX ページに返すようにします (後でこれを拡張するようにリファクタリングします)。まず、HttpResponseMessage を返すようにポスト メソッドを変更する必要があります。

[HttpPost]
public HttpResponseMessage UpdateCustomer(CustomerDTO custDTO)

次に、クライアントにリダイレクト応答を返すコードをメソッドの末尾に追加します。

HttpResponseMessage rsp = new HttpResponseMessage();
  rsp.StatusCode = HttpStatusCode.Redirect;
  rsp.Headers.Location = new Uri("RecordSaved.aspx", UriKind.Relative);
  return rsp;
}

実際の作業はここからです。次の作業を行います。

  • ASPX コード ファイルに含まれていたすべてのコードを新しいコントローラー メソッドに移動します。
  • 検証コントロールによって実行されるサーバー側の検証を追加します。
  • ページによって発生するイベントのコードをデタッチします。

これらは簡単な作業ではありません。ただし、ページを引き続き AJAX 対応にすることによってこのプロセスを簡単にするオプションがいくつかあります。このようなオプションの 1 つにより、実際コントローラーにコードを移動できない場合 (または後で移動する場合)、Web フォーム内にコードを残すことができます。

既存の Web フォームをリファクタリングするこの時点で、MVC パターンに移行したことになりますが、AJAX パラダイムには移行していません。ページは依然として従来の要求/応答サイクルを使用しており、ページのポストバックは取り除かれていません。そこで、次は純粋に AJAX 対応のページを作成します。

AJAX への移行

要求/応答サイクルを取り除く最初の手順として、クライアント側の関数を呼び出すようにボタンの OnClientClick プロパティを設定することで、プロセスに JavaScript を挿入します。今回の例では、ボタンから UpdateCustomer という JavaScript 関数を呼び出しています。

<asp:Button ID="PostButton" runat="server" Text="Update"
  OnClientClick="return UpdateCustomer();" />

この関数では、ユーザーがボタンをクリックすることによってトリガーされるポストバックをインターセプトして、サービスのメソッドへの AJAX 呼び出しに置き換えます。OnClientClick で return キーワードを使用し、UpdateCustomer が false を返すようにすると、ボタンによってトリガーされるポストバックが抑制されます。インターセプト関数では、ASP.NET が提供する Page_ClientValidate 関数を呼び出すことによって、ASP.NET 検証コントロールが生成するクライアント側の検証コードも呼び出します (検証コントロールのクライアント側コードを呼び出していると、リファクタリングのプロセスで検証コントロールのサーバー側の検証を作り直す必要がなくなります)。

既存の Web フォームをリファクタリングしている場合は、これでルートを使用する form タグの action 属性を削除できるようになります。action 属性を削除すると、Web フォームのコードを Web API コントローラーに移行する際に、ハイブリッド型の段階的アプローチを実装できます。コントローラーに (まだ) 移行しないコードについては、引き続き Web フォーム自体にポストバックさせることができます。たとえば、インターセプト関数で、Web フォームのどこに変更が加えられたかをチェックし、ポストバックを継続させるように、インターセプト関数から true を返します。ページ上にポストバックのトリガーとなるコントロールが複数ある場合、Web API コントローラーで処理するコントロールを選択して、これに対応するインターセプト関数を作成することができます。したがって、リファクタリングする際にハイブリッド型のアプローチ (Web フォームに一部のコードを残す) または段階的なアプローチ (時間をかけて徐々にコードを移行する) を実行できます。

UpdateMethod では、以前にポストバックを行っていたページに対して Web API サービスを呼び出すことが必要になります。プロジェクトとページに jQuery (今回は jQuery 1.8.3 を使用) を追加することにより、post 関数を使用して Web API サービスを呼び出します。jQuery の serialize 関数は、フォームを一連の名前と値のペアに変換します。このペアが、Web API によって CustomerDTO オブジェクトのプロパティ名にマップされます。この呼び出しを次のように UpdateCustomer 関数に統合し、クライアント側にエラーがなかった場合のみポストバックが行われるようにします。

function UpdateCustomer() {
  if (Page_ClientValidate()){
    $.post('CustomerManagement', $('#form1').serialize())
    .success(function () {
      // Do something to tell the user that all went well.
    })
    .error(function (data, msg, detail) {
      alert(data + '\n' + msg + '\n' + detail)
    });
  }
  return false;
}

フォームをシリアライズすると多くのデータがコントローラーに送信されますが、送信する必要のないデータ (ViewState など) もあります。必要なデータだけを送信する方法は、後半で説明します。

最後 (少なくとも今回のサンプルでは) に、ユーザーが現在のページで操作を続けられるようにコントローラーのポスト メソッドの最後の部分を書き直します。新しいバージョンのポスト メソッドでは、次のように HttpResponseMessage クラスを使用して HTTP OK ステータスを返します。

...
  ne.SaveChanges();
  HttpResponseMessage rsp = new HttpResponseMessage();
  rsp.StatusCode = HttpStatusCode.OK;
  return rsp;
}

ワークフロー処理

ここで、細かい処理をどこで行うかを決める必要があります。前述のように、ユーザーを別のページに誘導する場合は、コントローラー内で処理できます。ただし、コントローラーからクライアントに OK メッセージを返すだけの場合は、追加の処理はクライアントで実行することになります。たとえば、サーバー側での処理結果を Web フォームに表示するラベルを追加するとします。

更新ステータス: <asp:Label ID="Messages" runat="server" Text=""></asp:Label>

AJAX 呼び出しの success メソッドでは、AJAX 呼び出しのステータスでラベルを更新することになります。

success: function (data, status) {
  $("#Messages").text(status); 
},

Web フォームのサーバー側コードにとっては、ポストされるページの処理の一環として、ユーザーにページを返す前にページ上のコントロールを更新するのは一般的ではありません。そのためには、サービスのポスト メソッドからデータを返し、JavaScript 関数でページを更新する必要があります。

まず、HttpResponseMessage オブジェクトの Content プロパティを設定して、返すデータを保持します。フォームからポスト メソッドにデータを渡すために作成した DTO が使用できる状態なので、この DTO を使ってデータをクライアントに送り返すことができます。ただし、DTO クラスに Serializable 属性を付けて Web API で使用できるようにする必要があります (実際、DTO に Serializable 属性を付けると、DTO のプロパティのバッキング フィールドがシリアライズされ、DTO のクライアント側で操作するための一時的な名前を付けてクライアントに送信されます)。

次のコードは DTO の City プロパティを更新し、JSON オブジェクトとしてフォーマットして HttpResponseMessage Content プロパティに移動します (このコードを機能させるためには System.Net.Http.Headers に対する using ステートメントをコントローラーに追加する必要があります)。

HttpResponseMessage rsp = new HttpResponseMessage();
rsp.StatusCode = HttpStatusCode.OK;
custDTO.City = cust.City;
rsp.Content = new ObjectContent<CustomerDTO>(custDTO,
              new JsonMediaTypeFormatter(),
              new MediaTypeWithQualityHeaderValue("application/json"));

最後に、インターセプト関数を拡張して、success メソッドでデータをフォームに移動します。

.success(function (data, status) {
  $("#Messages").text(status);
  if (status == "success") {
    $("#City").val(data.City);
  }
})

もちろん、このコードでは ASP.NET ViewState は更新されません。後でこのページが ASP.NET の通常の形式でポストバックされると、City TextBox で TextChanged イベントが発生することになります。Web フォームのサーバー側にこのイベントに結び付けられているコードがあると、意図しない結果が生じることがあります。段階的移行を行っている場合、またはハイブリッド型のアプローチを使用している場合は、このことをテストしておく必要があります。今回のパラダイムを完全に実装したバージョンでは、Web フォームを最初に表示した以降はフォームをサーバーにポストバックしないため、このことは問題になりません。

イベントの置き換え

前述のように、ASP.NET サーバー側イベントは使用しないで公開する予定です。ただし、代わりにサーバーへのポストバックをトリガーする等価な JavaScript イベントをキャプチャし、サーバー側のイベントと同じことを行えるサービスのメソッドを呼び出すことができます。段階的なリファクタリング プロセスではこのイベントを使用し、適切なタイミングで (または必要と感じたときに) これらのイベントを移行できます。

たとえば、ページ上に現在表示されている顧客を削除するための削除ボタンがあり、初期の移行ではページのコード ファイルにこの機能を残して、削除ボタンによってページをサーバーにポストバックできます。削除機能を移行する準備が整ったら、まず、削除ボタンのクライアント側 onclick イベントをインターセプトする関数を追加します。今回の例では、クライアント側のイベントを操作する方法として、JavaScript のイベントに接続する方法を選択しました。

<asp:Button ID="DeleteButton" runat="server" Text="Delete"  />
<script type="text/javascript">
  $(function () {
    $("#DeleteButton").click(function () { return DeleteCustomer() });
  })

DeleteCustomer 関数では、ページ全体をシリアライズするのではなく、サーバー側の delete メソッドに必要なデータ (CustomerID) のみ送信します。サービスへの要求に使用する 1 つのパラメーターを URL に埋め込むことができるので、適切なコントローラー メソッドを選択するために別の標準 HTTP 動詞 (DELETE) を使用できるようになります (HTTP 動詞の詳細については、bit.ly/92iEnV を参照してください)。

jQuery ajax 関数を使用して、コントローラーに要求を発行できます。発行の際には、ページのデータを使って URL を構築し、この種の要求に使用する HTTP delete 動詞を指定します (図 2 参照)。

図 2 jQuery AJAX 関数を使用したコントローラー要求の発行

function DeleteCustomer() {               
  $.ajax({
    url: 'CustomerManagement/' + $("#CustomerID").val(),
    type: 'delete',
    success: function (data, status) {
      $("#Messages").text(status);                       
  },
  error: function (data, msg, detail) {
    alert(data + '\n' + msg + '\n' + detail)
    }
  });
  return false;
}

次に、URL のどの部分に CustomerID を含むかを特定し、その値をパラメーター (今回の場合、パラメーター名 CustID) に割り当てるルーティング規則を作成します。

 

RouteTable.Routes.MapHttpRoute(
  "CustomerManagementDelete",
  "CustomerManagement/{CustID}",
  new { Controller = "Customer" },
  new { httpMethod = new HttpMethodConstraint("Delete") }
);

POST と同様に、Web API が HTTP DELETE 要求をコントローラー内のメソッドに自動的にルーティングします。ルーティング先のメソッドは名前で指定するか、名前を "Delete" で始めるか、HttpDelete 属性でフラグを付けます。そしてこれまでのように、テンプレートの名前と一致するメソッドのパラメーターに、URL から抽出したすべてのデータを Web API が自動的にマップします。

[HttpDelete]
public HttpResponseMessage FlagCustomerAsDeleted(string CustID)
{
  //... Code to update the Customer object ...
  HttpResponseMessage rsp = new HttpResponseMessage();
  rsp.StatusCode = HttpStatusCode.OK;
  return rsp;
}

HTTP 動詞では対応できない処理

ほとんどの ASP.NET ページは、HTTP 動詞を念頭に置いては設計されていません。どちらかと言えば、オリジナル バージョンのコードの定義には、"トランザクション処理" のアプローチが頻繁に使用されます。その結果、ページの機能を 1 つの HTTP 動詞に結び付けるのが難しくなります (あるいは、異なる種類の複数の処理に対処する複雑なポスト メソッドを作成することになります)。

トランザクション指向の機能を処理する場合は、コントローラーのメソッド (ルーティング用語では "action") を HTTP の型ではなく名前で指定するルートを追加できます。以下のサンプルでは、要求をAssignCustomerToOrder というメソッドにルーティングし、URL から CustID と OrderID を抽出する URL を定義しています (ポスト メソッドとは異なり、他の HTTP 動詞に関連付けられるメソッドは複数のパラメーターを受け取ることができます)。

RouteTable.Routes.MapHttpRoute(
  "CustomerManagementAssign",
  "CustomerManagement/Assign/{CustID}/{OrderID}",
  new { Controller = "Customer", Action="AssignCustomerToOrder" },
  new { httpMethod = new HttpMethodConstraint("Get") }
  );

メソッドの以下の宣言は、URL から抽出されるパラメータを選択しています。

[HttpGet]
public HttpResponseMessage AssignCustomerToOrder(
  string CustID, string OrderID)
{

クライアント側の適切なイベントに結び付けるインターセプト関数では、jQuery get 関数を使用して、適切なコンポーネントを含む URL を渡します。

function AssignOrder() {
  $.get('CustomerManagement/Assign/' + 
    $("#CustomerID").val() + "/" + "A123",
    function (data, status) {
      $("#Messages").text(status);
      });
  return false;
}

従来の ASPX ページのコード ファイルを Web API コントローラーにリファクタリングするのは簡単な作業ではありません。ただし、ASP.NET Web API は柔軟性が高く、HTTP データを .NET オブジェクトにバインドする機能があります。さらに、HTTP 標準を活用する機能により、既存のアプリケーションを MVC/TDD モデルに移行する手法の可能性が高まります。こうした手法に従えば、AJAX 対応のページのスケーラビリティが向上します。また、新しい ASP.NET アプリケーションを作成する際に、Web フォームの生産性と ASP.NET Web API の機能の両方を活かすパラダイムも提供されます。

Peter Vogel は、サービス指向アーキテクチャ、XML、データベース、および UI デザインの専門技術を持ち ASP.NET 開発に特化した企業、PH&V Information Services の社長です。

この記事のレビューに協力してくれた技術スタッフの Christopher Bennage および Daniel Roth に心より感謝いたします。
Christopher Bennage はマイクロソフトの Patterns & Practices チームの開発者です。彼の仕事は、開発者が利用できるプラクティスを発見、収集し、推奨することです。最近彼の興味を引いているのが JavaScript と (カジュアル) ゲーム開発です。彼のブログは http://dev.bennage.com (英語) です。

Daniel Roth は、現在 ASP.NET Web API に取り組んでいる Windows Azure Application Platform チームのシニア プログラム マネージャーです。ASP.NET の前は、.NET Framework 3.0 で最初にリリースされたときから WCF に取り組んでいました。彼は、フレームワークをシンプルで使いやすくすることでユーザーに喜んでもらうことに情熱を注いでいます。