次の方法で共有



April 2017

Volume 32 Number 4

コンテナー - 従来の .NET アプリを Docker で最新化する

Elton Stoneman

Microsoft .NET Framework は 15 年間にわたって成功を収めてきたアプリケーション プラットフォームです。以前のバージョンの .NET Framework と Windows Server では、ビジネスに不可欠なアプリケーションが数え切れないほど実行されています。このような従来のアプリケーションでは依然として大きなビジネス価値が提供されていますが、その保守、アップグレード、拡張、および管理は難しくなっている可能性があります。同時に、このようなアプリケーションをすべて作り直すことも、そのために必要な投資に見合わない場合があります。ただし、軽量なコンテナー内でアプリケーションを実行するプラットフォームである Docker と、Windows Server 2016 を併用することで、従来のアプリケーションの寿命を伸ばすことが可能です。つまり、機能を追加し、セキュリティとパフォーマンスを向上して、継続的配置に移行します。それも、時間がかかるうえにコストが高い再構築プロジェクトを実施する必要はありません。

今回は、SQL Server データベースに接続するモノリシック ASP.NET WebForms アプリケーションを取り上げ、Docker プラットフォームを活用してこのアプリケーションを最新化します。まずは、コードを変更しないで、アプリケーション全体をそのまま Docker に移行して、軽量なコンテナー内で Web サイトとデータベースを実行します。次に、アプリケーションを拡張する機能主導型のアプローチについて説明して、パフォーマンスを向上し、ユーザーにセルフ サービス分析機能を提供します。Docker プラットフォームがあれば、新しいバージョンのアプリケーションを反復的に処理し、コンポーネントを迅速かつ安全にアップグレードして、完全なソリューションを Microsoft Azure にデプロイできることがお分かりいただけることでしょう。

Docker が最適な .NET ソリューション

Docker は、サーバー アプリケーション向けのプラットフォームです。つまり、Web サイト、API、メッセージング ソリューションに加えて、バックグラウンドで実行されるその他のコンポーネントが対象になります。Docker プラットフォームと Windows ホストの間では UI が統合されないため、デスクトップ アプリを Docker で実行することはできません。したがって、Windows フォームや Windows Presentation Foundation (WPF) アプリケーションをコンテナー内で実行することは不可能です (ただし、Docker を使用してこのようなデスクトップ アプリケーションをパッケージ化して配布することはできます)。しかし、Windows Communication Foundation (WCF)、.NET コンソール アプリケーション、およびすべてのバージョンの ASP.NET には最適です。

アプリケーションをパッケージ化して Docker で実行するには、アプリケーションを配置する手順をすべて自動化する Dockerfile という小さなスクリプトを作成します。通常このスクリプトには Windows PowerShell コマンドを含め、アプリケーションのコンテンツをコピーして依存関係が設定されるように構成および指示します。圧縮済みのアーカイブを解凍したり、MSI をインストールすることもできます。ただし、パッケージ化のプロセスはすべて自動化されるため、Windows UI を用意してユーザーの入力を求めるインストール プロセスは実行できません。

どの部分なら Docker コンテナーで実行できるのか、それを把握するためにソリューションのアーキテクチャを確認する場合は、Windows UI を使わずにインストールおよび実行できるコンポーネントが最適であることを念頭に置きます。今回は、.NET Framework アプリケーションに注目します。ただし、.NET Core、Java、Node.js、Go のアプリケーションなど、Windows Server で実行されるものはすべて Windows コンテナーで実行できます。

.NET アプリケーションをコンテナーに移行

Docker への移行方法は現在のアプリケーションの実行方法によって変わってきます。完全に構成済みのアプリケーションを Hyper-V VM で実行している場合、オープン ソースの Image2Docker ツールを使用して、VM のディスクから Dockerfile を自動的に生成できます。MSI または WebDeploy パッケージを発行するビルド プロセスがある場合は、Docker Hub にある Microsoft のいずれかのベース イメージを使用して独自に Dockerfile を作成するのが簡単です。

ASP.NET WebForms アプリケーションを Docker イメージにパッケージ化するスクリプトを記述した、完全な Dockerfile を以下に示します。

FROM microsoft/aspnet:windowsservercore-10.0.14393.693
SHELL ["powershell"]
RUN Remove-Website -Name 'Default Web Site'; \
    New-Item -Path 'C:\web-app' -Type Directory; \
    New-Website -Name 'web-app' -PhysicalPath 'C:\web-app' -Port 80 -Force
EXPOSE 80
RUN Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' \
    -Name ServerPriorityTimeLimit -Value 0 -Type DWord
COPY ProductLaunch.Web /web-app

このスクリプトの 9 行のコードはすべて必要です。また、アプリケーションに変更は加えていません。このアプリケーションが、現在 Windows Server 2003 で実行されている ASP.NET 2.0 アプリケーションだったとしても、上記の Dockerfile を使って、アプリケーションをイメージに組み込み、そのイメージでアプリケーションを即座に Windows Server 2016 と .NET Framework 4.5 にアップグレードできます。このスクリプトの命令を 1 つずつ見てみましょう。

  • FROM microsoft/aspnet は、出発点に使用するイメージを Docker に指示します。今回の場合は、特定バージョンの Windows Server Core 上に IIS と ASP.NET をインストールした Microsoft イメージを出発点にします。
  • SHELL ["powershell"] によって、Dockerfile の残りの部分がすべて別のシェルに変わります。そのため、PowerShell コマンドレットを実行できるようになります。
  • RUN Remove-Website は、PowerShell を使用して IIS を設定し、既定の Web サイトを削除して、アプリケーションの既知の場所に新しい Web サイトを作成します。
  • EXPOSE 80 は、コンテナー内へのネットワーク トラフィックを許可するために、ポート 80 を明示的に開放します。Docker コンテナーは、既定ではロック ダウンされます。
  • RUN Set-ItemProperty は、イメージ内での Windows DNS キャッシュをオフにします。そのため、DNS 要求は Docker によって対応されることになります。
  • COPY ProductLaunch.Web は、発行済みの Web サイト プロジェクトを、ホスト上の ProductLaunch.Web ディレクトリからイメージにコピーします。

Dockerfile は Web アプリケーションの配置ガイドのようなものです。ただし、あいまいな人間向けのドキュメントではなく、正確かつ実行可能なスクリプトです。パッケージ化されたアプリケーションを作成するには、Dockerfile と発行済みの Web サイトを格納したディレクトリから、次の Docker ビルド コマンドを実行します。

docker build --tag sixeyed/msdn-web-app:v1 .

このコマンドによって、sixeyed/msdn-web-app という名前と v1 タグを使って Docker イメージがビルドされます。この名前には、Docker Hub の筆者のユーザー アカウント (sixeyed) が含まれています。そのため、筆者の資格情報を使用してサインインし、Docker Hub にプッシュすることでこのイメージを共有できます。タグはイメージのバージョン管理に役立ちます。そのため、新しいバージョンのアプリケーションをパッケージ化する場合、イメージの名前は変わりませんが、タグは v2 にします。

これで、このイメージからコンテナーを実行できるようになります。コンテナーを実行すると、アプリケーションが起動されます。ただし、サンプル アプリケーションは SQL Server に対する依存関係があるため、Web サイトを起動する前に SQL Server を実行しておく必要があります。

Docker Hub から依存関係を取得

Docker には、仮想ネットワーク経由でコンテナー間の相互アクセスを可能にするネットワーク スタックが用意されています。また、このネットワーク スタックによって、物理ネットワーク上で実行されている外部ホストにコンテナーからアクセスできるようになります。ネットワーク内のコンピューターで実行されている SQL Server インスタンスがある場合は、コンテナー内の ASP.NET アプリケーションからこのインスタンスを使用することができます。そのために必要なのは、接続文字列でサーバー名を指定することだけです。または、コンテナー内で SQL Server を実行することも可能です。この場合、Web アプリケーションでは、接続文字列でコンテナーの名前を使用すれば、その SQL Server にアクセスできます。

SQL Server Express が、Docker Hub にある Microsoft が管理するイメージで利用できます。このイメージのデータベース コンテナーを開始するには、次のコマンドを実行します。

docker run --detach `
 --publish 1433:1433 `
 --env sa_password=MSDNm4g4z!n3 `
 --env ACCEPT_EULA=Y `
 --name sql-server `
 microsoft/mssql-server-windows-express

その結果、detach フラグを付けたことでコンテナーがバックグラウンドで開始され、ポート 1433 が公開されます。そのため、コンテナー内の SQL インスタンスに外部から接続できます。おそらく、ホストでは SQL Server Management Studio が使用されます。env オプションはキーと値のペアです。このペアはシステム環境変数としてコンテナー内部で Docker により検出されます。SQL Server イメージでは、これらの値を使用してライセンス契約が承認されていることを確認し、sa ユーザーのパスワードを設定します。

コンテナーを実行する場合、Docker ではイメージのコピーをローカルに用意する必要があります。Docker プラットフォームには Distribution が組み込まれているため、このコマンドの実行時に SQL Server Express イメージがローカルに存在しない場合、Docker によってそのイメージが Docker Hub からダウンロードされます。Docker Hub には 50 万個以上のイメージが用意されており、90 億回以上ダウンロードされています。Docker の歴史は Linux の世界で始まったため、Docker Hub にあるイメージの大半は Linux アプリケーションですが、ダウンロードしてそのままソリューションに組み込める高品質な Windows アプリケーションの数も増え続けています。

SQL Server が現在 Docker コンテナーで実行されていて、今回の Web アプリケーションでは接続文字列のホスト名に sql-server を使用しているため、Docker で実行されるデータベースに接続されます。次のように、まず WebForms アプリケーションをバックグラウンドで起動し、ポート 80 を公開すると、Web サイトにアクセスできるようになります。

docker run --detach `
 --publish 80:80 `
 sixeyed/msdn-web-app:v1

外部のコンピューターからポート 80 に対する要求がホストに送信された場合、Docker はその要求を受け取ると、コンテナーで実行されている ASP.NET アプリケーションにその要求を透過的に転送します。ホストで作業している場合は、docker inspect を使用してコンテナーの IP アドレスを取得し、コンテナーを参照してサイトを表示する必要があります。このサイトは、製品リリース用の簡単なマイクロサイトです。図 1 に、Docker で実行しているサイトのデータ キャプチャ ページを示しています。

Docker で実行されているサイトのサインアップ ページ
図 1 Docker で実行されているサイトのサインアップ ページ

dcker ps を実行すると、実行中のすべてのコンテナーの一覧が表示されます。1 つはデータベースで、1 つは Web アプリケーションです。ただし、どちらも同じ方法で管理します。docker top を実行すると、コンテナーで実行中のプロセスが表示されます。docker logs を実行すると、アプリケーションのログ出力を確認できます。docker inspect を実行すると、どのポートが開放されているかなど、コンテナーに関する多数の情報が示されます。Docker プラットフォームの大きな利点は一貫性です。アプリケーションでどのようなテクノロジを使用していたとしても、アプリケーションを同じ方法でパッケージ化、配布、および管理することができます。

モノリシック アプリケーションの機能を分割

アプリケーションが最新のプラットフォームで実行されるようになったので、アプリケーション自体の最新化を開始します。モノリシック アプリケーションを小さなサービスに分割することは、作業の中でも重要なプロジェクトになる可能性があります。ですが、定期的に変更される機能など、重要な機能に取り組むことによるターゲットを絞ったアプローチを取ることもできます。そのようにして、アプリケーション全体に対する回帰テストを行うことなく、変更される機能に対して更新を配置できます。アプリケーション全体を再構築する必要がなく、異なった設計のメリットが得られる、機能要件を持たない機能もまた適切な選択肢になる可能性があります。

ここでは、パフォーマンスの問題を解決するところから始めます。既存のコードでは、アプリケーションはデータベースに同期接続してユーザーのデータを保存します。このアプローチは適切にスケーリングされません。同時接続ユーザーが多くなれば、SQL Server でボトルネックが生じることになります。メッセージ キューを使用した非同期通信の方がずっとスケーラブルな設計です。この機能の場合、Web アプリケーションのイベントをメッセージ キューに発行し、イベント メッセージを処理する新しいコンポーネントにデータ保存コードを移動できます。

この設計なら適切にスケーリングされます。Web サイトへのトラフィックが急増した場合は、より多くのホストでもっと多くのコンテナーを実行すれば、その着信要求に対処できます。イベント メッセージは、メッセージ ハンドラーでメッセージが処理されるまで、キューに保持されることになります。具体的な SLA がない機能の場合、1 つのコンテナー内で 1 つのメッセージ ハンドラーを実行しておき、すべてのイベントが最終的には処理されるというメッセージ キューの保証を利用できます。SLA 主導の機能の場合、より多くのメッセージ ハンドラー コンテナーを実行することで、永続化層をスケールアウトできます。

本稿付属のソース コードには、アプリケーションのバージョン 1、バージョン 2、およびバージョン 3 のフォルダーが含まれています。バージョン 2 では、ユーザーが詳細フォームを送信したときに、SignUp.aspx ページでイベントが発行されます。

var eventMessage = new ProspectSignedUpEvent
{
  Prospect = prospect,
  SignedUpAt = DateTime.UtcNow
};
MessageQueue.Publish(eventMessage);

またバージョン 2 には、メッセージ キューの詳細を抽象化する共有メッセージング プロジェクトと、Web アプリケーションによって発行されたイベントをリッスンしてユーザーのデータをデータベースに保存するコンソール アプリケーションがあります。このコンソール アプリケーションの永続化コードは、Web アプリケーションのバージョン 1 のコードから直接移植しています。そのため実装は同じですが、機能の設計は最新化されています。

新しいバージョンのアプリケーションは、機能パーツが多数存在する分散ソリューションです (図 2 参照)。

多くの機能パーツを備える最新化されたアプリケーション
図 2 多くの機能パーツを備える最新化されたアプリケーション

コンポーネント間には依存関係があるため、ソリューションが適切に動作するにはコンポーネントが適切な順番で開始される必要があります。多数のコンテナーで実行されるアプリケーションを編成する際には、この点が 1 つの問題になります。ただし、Docker プラットフォームは、分散アプリケーションを第一級要素として扱うことによってこうした問題に対処しています。

Docker Compose によるアプリケーションの編成

Docker Compose は Docker プラットフォームの一部であり、分散アプリケーションに重点を置いています。アプリケーションのすべてのパーツをサービスとして簡単なテキスト ファイルに定義します。これには、パーツ間の依存関係や必要な構成値も含みます。以下は、バージョン 2 の Docker Compose ファイルの一部です。Web アプリケーションの構成のみを示しています。

product-launch-web:
  image: sixeyed/msdn-web-app:v2
  ports:
    - "80:80"
  depends_on:
    - sql-server
    - message-queue
  networks:
    - app-net

ここで Web アプリケーションに使用するイメージのバージョンを指定しています。ポート 80 を公開し、次に Web アプリケーションが SQL Server とメッセージ キューのコンテナーに依存することを明示的に指定します。これらのコンテナーにアクセスするには、Web コンテナーが同じ仮想 Docker ネットワーク内に存在している必要があります。そのため、Docker Compose ファイル内のコンテナーはすべて、app-net という名前の同じ仮想ネットワークに参加しています。

Docker Compose ファイルの他の場所で、Docker Hub の Microsoft イメージを使って SQL Server のサービスを定義しています。また、メッセージ キューのサービスには NATS メッセージング システムを使用しています。NATS は、パフォーマンスの高いオープン ソース メッセージ キューです。NATS は Docker Hub で公式イメージとして提供されています。最後はメッセージ ハンドラーのサービスです。これは、簡単な Dockerfile を使用して Docker イメージとしてパッケージ化された .NET コンソール アプリケーションです。

これで、次の Docker Compose コマンド ラインを使用してアプリケーションを実行できるようなります。

docker-compose up -d

実行後、Docker Compose によって各コンポーネントのコンテナーが適切な順番で開始されます。つまり、実用的なソリューションを単一のコマンドから利用できます。Docker イメージと Docker Compose ファイルへのアクセス権があれば、だれでもアプリケーションを実行でき、そのアプリケーションの動作も同じになります。つまり、Windows 10 ノート PC でも、データセンターで実行している Windows Server 2016 コンピューターでも、Azure でも同じことが実現されます。

バージョン 2 では、アプリケーション コードを少し変更して、機能の実装を 1 つのコンポーネントから別のコンポーネントに移動しました。エンド ユーザー側の動作は同じですが、Web 層がデータ層から分離されているため、ソリューションを簡単にスケーリングできるようになり、またメッセージ キューによってトラフィックの急増に対処されるようになっています。新しい設計は拡張するのも簡単です。これはイベント ドリブン アーキテクチャを導入したことによるものです。したがって、既存のイベント メッセージに新しい動作を組み込むことで、その動作をトリガーできます。

セルフサービス分析の追加

Docker プラットフォームを利用すると、ほとんど手間をかけずにどれほどのことが実現されるかを示すために、今回のサンプル アプリケーションにさらに 1 つ変更を加えます。現在、アプリケーションでは SQL Server をトランザクション データベースとして使用しています。ここで、2 つ目のデータ ストアをレポート データベースとして追加します。これにより、トランザクションの懸案事項と、レポートの懸案事項を分離でき、テクノロジ スタックを自由に選ぶこともできるようになります。

サンプル コードのバージョン 3 では、Web アプリケーションによって発行された同じイベント メッセージをリッスンする新しい .NET コンソール アプリケーションを追加しました。両方のコンソール アプリケーションが実行されている場合、NATS メッセージ キューによって、この両コンソール アプリケーションがすべてのイベントのコピーを取得することが保証されます。新しいコンソール アプリケーションは、イベントを受け取って、ユーザー データを Elasticsearch に保存します。Elasticsearch は、Windows Docker コンテナーで実行可能なオープン ソースのドキュメント ストアです。Elasticsearch はここでは有効な選択肢です。その理由は 2 つあります。1 つは Elasticsearch が適切にスケーリングされることです。そのため、複数のコンテナー間で Elasticsearch をクラスター化して冗長性を実現できます。もう 1 つの理由は、ユーザー側の優れたフロント エンドを利用できることです。このフロント エンドは Kibana と呼ばれます。

Web アプリケーションも SQL Server メッセージ ハンドラーもバージョン 2 から何も変更していません。そのため、Docker Compose ファイルでは、Elasticsearch および Kibana 用の新しいサービスと、ドキュメントを Elasticsearch インデックスに記述する次の新しいメッセージ ハンドラーのサービスを追加しただけです。

index-prospect-handler:
  image: sixeyed/msdn-index-handler:v3
  depends_on:
    - elasticsearch
    - message-queue
  networks:
    - app-net

Docker Compose ではアプリケーションの増分アップグレードが可能です。また、Docker Compose ファイル内のサービスと実行中のコンテナーの定義が一致した場合、そのコンテナーが置き換えられることはありません。サンプル アプリケーションのバージョン 3 には新しいサービスがありますが、既存のサービスは変更していません。そのため、docker-compose up –d を実行すると、Docker によって Elasticsearch、Kibana、およびインデックス メッセージ ハンドラーの新しいコンテナーが実行されますが、他の要素は現状のまま実行されます。このしくみにより、非常に安全なアップグレード プロセスが実現され、アプリケーションをオフラインにすることなく機能を追加できるようになります。

このアプリケーションは構成よりも規則を優先します。そのため、Elasticsearch のような依存関係に対応するホスト名は、アプリケーションでは既定に設定されます。必要なことは、Docker Compose の設定内のコンテナー名が一致しているのを確認することだけです。

新しいコンテナーが開始されたら、docker inspect を使用して Kibana の IP アドレスを取得し、その IP アドレスのポート 5601 を参照できます。Kibana には非常にシンプルなインターフェイスが用意されており、サインアップしたユーザーの重要な指標をその詳細情報と共に表示するダッシュボードを数分で構築できます (図 3 参照)。

Kibana ダッシュボード
図 3 Kibana ダッシュボード

パワー ユーザーなら短時間で Kibana を理解できるでしょう。IT 部門を巻き込む必要もなく、独自の視覚化とダッシュボードを作成できるようになります。ダウンタイムなしで、セルフサービス分析をアプリケーションに追加しました。こうした機能の中核部分は、Docker Hub から取得してソリューションに組み込んだエンタープライズ級のオープン ソース ソフトウェアから取得しています。ドキュメント ストアにデータを渡すカスタム コンポーネントは、100 行程度のコードで作成した簡単な .NET コンソール アプリケーションです。Docker プラットフォームは、このコンポーネントを組み込む作業もまとめて対応します。

Docker 化したソリューションの Azure での実行

Docker には移植性というもう 1 つすばらしいメリットがあります。Docker イメージにパッケージ化されたアプリケーションは、どのホスト上でもまったく同じように実行されます。今回の最終アプリケーションでは、Microsoft が所有する Windows Server イメージと SQL Server イメージ、Docker が管理する NATS イメージ、および筆者独自のカスタム イメージを使用します。これらのイメージはすべて Docker Hub で公開されています。そのため、Windows 10 PC または Windows Server 2016 コンピューターならどれでも、イメージを取得してそこからコンテナーを実行できます。

これで、アプリケーションをテストする準備が整いました。このアプリケーションを Azure の共有環境にデプロイするのは簡単です。コンテナー オプションのある Windows Server 2016 Datacenter を使用して、Azure で仮想マシン (VM) を作成しました。この VM イメージにはインストールと構成が済んだ Docker が付属しており、Windows Server Core および Nano Server 用の基本 Docker イメージが既にダウンロードされています。この VM に含まれていないアイテムは、Docker Compose だけです。これは、GitHub のリリース ページからダウンロードします。

今回の Docker Compose ファイルで使用しされているイメージは、すべて Docker Hub の公開リポジトリにあります。プライベート ソフトウェア スタックでは、すべてのイメージを一般公開することは求めていないでしょう。それでも Docker Hub を使用して、イメージを専用リポジトリに保持できます。または、Azure Container Registry のようなホスト型レジストリを代替として使うことも可能です。独自のデータセンター内では、Docker Trusted Registry のような、オンプレミス オプションを使用できます。

今回のイメージはすべて公開されているため、必要な作業は Docker Compose ファイルを Azure VM にコピーし、docker-compose up –d を実行することのみです。Docker によって、Docker Hub からすべてのイメージが取得され、そのイメージからコンテナーが正しい順序で実行されます。各コンポーネントは規則を使って他のコンポーネントにアクセスします。そして、これらの規則は Docker Compose ファイルに組み込まれています。そのため、完全に新しい環境であっても、今回のソリューションは想定どおりに開始され、実行されます。

エンタープライズ ソフトウェア リリースでは、新しい環境のセットアップはリスクを伴ううえに時間のかかる手動のプロセスになります。このような業務に従事している場合は、Windows Server 2016 と Docker プラットフォームから得られるメリットが非常に大きいことがわかるでしょう。Docker ソリューションにおける重要な成果物である Dockerfile と Docker Compose ファイルは、手動の配置ドキュメントのシンプルかつ明確な代替品となります。これらのファイルにより自動化が後押しされ、ソリューションを簡単にビルドして、リリースし、どのコンピューター上でも一貫した方法で実行できるようになります。

次のステップ

Docker を試してみようとお考えになったら、Image2Docker PowerShell モジュールから始めるのがお勧めです。このモジュールを使って独自の Dockerfile をビルドできるため、速やかに学習プロセスを開始できます。また、training.docker.com (英語) ではマイペースで学習できるすばらしいコースが無料で提供されています。このサイトでは、ユーザー用に環境がプロビジョニングされます。その後、次の段階に進む準備が整ったら、GitHub の docker/labs を確認してみましょう。ここでは Windows コンテナーのチュートリアルが豊富に用意されています。

また、Docker ミートアップが世界中に存在しているので、そこで実践経験のある開発者や専門家から Docker のあらゆる側面について話を聞くことができます。大規模な Docker カンファレンスとしては DockerCon があります。このカンファレンスは常に満員です。今年は 4 月にテキサス州で、10 月にはコペンハーゲンで開催されます。最後に、Docker Captains もチェックしてみましょう。Docker Captains は、Microsoft MVP の Docker バージョンに相当します。Docker Captains の専門家は、Docker で自分たちが行っているすばらしい作業について、継続的にブログを投稿し、ツイートして、講演を実施しています。このような専門家をフォローすることは、Docker の動向を把握し続けるのに最適な手段です。


Elton Stoneman は、7 回 Microsoft MVP を受賞している Pluralsight の執筆者であり、Docker でデベロッパー アドボケイトとしての職務に従事しています。彼は 2000 年以降、Microsoft テクノロジ、Azure の最新の API とビッグ データ プロジェクト、および Docker と分散アプリケーションを使った優れたソリューションを設計および提供してきました。

この記事のレビューに協力してくれた技術スタッフの Mark Heath に心より感謝いたします。
Mark Heath は、Azure を専門にしている .NET 開発者で、NAudio の作成者です。また、Pluralsight の執筆者でもあります。彼のブログは、markheath.net (英語) です。Twitter は、@mark_heath (英語) からフォローできます。