Team Foundation Server と Exchange

Exchange と Team Foundation Server を使用してチケット システムを構築する

Mohammad Jalloul

コード サンプルのダウンロード

Team Foundation Server (TFS) は、その強力な作業項目トラッキング機能を使用して、チケットを作成および管理する優れたメカニズムを提供します。このようなトラッキングを実現する方法は、一般的に 2 つあります。1 つは、Team System Web Access (TSWA) という Web インターフェイス経由で TFS にアクセスできるサポート担当者が、作業項目の独自の種類をサポート チケット用に作成して、必要な詳細情報を入力する方法です。もう 1 つは、作業項目機能をラップするインターフェイスを作成して、外部ユーザーが簡単に TFS にアクセスできるようにする方法です。この場合、外部ユーザーはTFS について理解する必要はありません。作業項目は、通常、ソフトウェア エンジニアに割り当てられ、そのソフトウェア エンジニアが作業項目を Visual Studio 内でトラッキングして管理します。どちらの方法も目的は、チケット作成機能を電子メール システムや専用のデータベース システムから TFS に移行して、TFS のメリットを数多く利用できるようにすることです。特に、TFS の作業項目には、チケットのライフサイクルを定義するワークフローが備わっています。作業項目への変更を監視し、作業項目の履歴を確認することにより、だれでもチケットをトラッキングできます。TFS データ ウェアハウスとの統合により、SQL Server Reporting Services (SSRS) や Excel Services の強力なレポート機能の利用できるメリットも得られます。

このような方法を採用したとしても、問題の詳しい説明や詳細情報の追加のために電子メールが送られることは少なくありません。このような電子メール スレッドの追加情報は失われがちで、作業項目に関する状況をできる限り完全に記録する場合は手動で作業項目の履歴にコピーすることになります。このような手作業を行うと作業項目の目的が損なわれ、場合によっては本来作業項目によって達成される生産性が相殺されることさえあります。

今回の記事では、電子メールと作業項目の両方の長所を活かした 3 つ目の方法を紹介します。この方法では、サポート担当者が長年行ってきたように、電子メールを送信することから始まります。

Exchange Web サービス

ここで紹介するプロセスでは、Microsoft Exchange Web サービス (EWS) の機能を使用して、Exchange Server 2007 または 2010 の配布リストに送信される電子メールについての通知をサブスクライブします。通知をリッスンする Web サービスが、受信した新しい電子メールを基に作業項目を作成します。2 通目以降の同じスレッドに関連する電子メールは、Microsoft Exchange Server のスレッド追跡機能を使用して、作成した作業項目の履歴に追加されるため、作業項目に電子メール スレッドがミラーリングされます。この作業項目ではワークフローも管理します。このように、ユーザー (サポート担当者) が新しいテクノロジに適応するために作業方法を変更するのではなく、テクノロジの側がユーザーのプロセスを採用して自動化します。

図 1 に一般的なプロセス フローを示します。

Process Flow for the Support Ticket Work Item

図 1 サポート チケット作業項目のプロセス フロー

以下は、このフローについて詳しく説明しています。

  1. サポート担当者が製品に関する問題の通知を受け取ることからフローが始まります。
  2. サポート担当者は、問題を説明した電子メールを Exchange の配布リスト (DL) に送信します。DL には、問題を把握しておく必要があるすべての担当者が含まれているため、問題を適切な開発者に割り当てて解決を依頼できます。DL には、通知目的でのみ存在する "監視者" の電子メール アカウントも含まれています。監視者アカウントは、特定の Web サービスのアドレスで通知を受信するよう Exchange に登録されています。
  3. Exchange が電子メールを処理し、DL の全メンバーにルーティングします。また、指定した電子メール アカウントについての通知を受信するよう登録されているすべての Web サービスに通知が送信されます。
  4. サポート チケット Web サービスは、Exchange から Web サービス インターフェイス経由で通知を受信します。
  5. この Web サービスが通知を処理し、電子メール アドレス関連の追加情報を要求します。続いて、TFS に Support Request 作業項目を作成します。この作業項目には、電子メール メッセージから抽出した情報が設定されます。
  6. DL のメンバーも電子メールを受信します。メンバーが電子メールに返信して詳細情報を求めた場合、サポート担当者は詳細情報を送信します。DL が電子メール メッセージの To フィールドまたは CC フィールドに含められるため、監視者の電子メール アカウントでは DL が指定されていることを認識し、通知 Web サービスではスレッドに含まれるすべての電子メールの通知を受信します。TFS によって、Support Request 作業項目が更新され、追加情報が設定されます。
  7. 前の手順で作成した Support Request 作業項目の [担当者] フィールドを使用して、チケットを開発者に割り当てます。
  8. 開発者が問題解決に着手し、作業項目の状態を In Progress に変更します。修正を加えたコードをレビューおよびテストし、完了したら、チェックインします。作業結果の変更セットを、Support Request 作業項目に関連付けます。作業項目では、電子メール スレッドと修正関連の変更セットをトラッキングするようになります。
  9. サポート担当者が TFS にアクセスできる場合は、Support Request 作業項目をそのサポート担当者に割り当てて終了できます。サポート担当者にアクセス権がない場合は、電子メールで DL に通知します。通常、プロジェクト マネージャーとプロジェクト リーダーは TFS の通知を設定しているため、Support Request 作業項目が解決されると通知を受け取ります。作業項目を終了するため、作業項目の状態を In Progress から Done に変更します。

このプロセスは、実際のシナリオでサポートが必要な問題に対処するプロセスとよく似ています。ただし、実際のシナリオでは、電子メール スレッドとチケット システムは、通常は 2 つのまったく異なる別のシステムです。

サポート チケットの通知 Web サービス

サポート チケットの通知 Web サービスでは、EWS Managed API を使用します。この API を使用すると、使い慣れた SOAP ベース メッセージング経由の説明付きインターフェイスを使用して、マネージ .NET アプリケーションと EWS で通信できます。EWS Managed API の詳細については、bit.ly/jGKRgG (英語) を参照してください。

EWS は、通常、Microsoft Exchange と共にインストールされるコンポーネントではなく、多くの IT セットアップ環境では、別途 Exchange クライアント アクセス サーバーにインストールされます。EWS を使用可能にするには、Microsoft Exchange と共にインストールして構成する必要があります。開発者は Exchange 管理者から EWS Web サービスの URL を入手する必要があり、この URL は、https://<ホスト名>/EWS/Exchange.asmx のような形式になります。通常はこれらの Web サービスを SSL エンドポイント上にセットアップすることに注意してください。

この記事の執筆時点における EWS Managed API の最新バージョンは、1.1 です。このバージョンは、Microsoft Exchange Server 2007 SP1 から Exchange Server 2010 SP1 までをサポートしています。EWS Managed API は、bit.ly/mkb7Is (英語) からダウンロードできます。

既定では、インストール時にファイルが [Program Files]\Microsoft\Exchange\Web Services\1.1 にコピーされます。API は Microsoft.Exchange.WebServices.dll という 1 つのアセンブリにパッケージ化されています。インストール フォルダーには、API の作業を開始する前に確認する必要がある、Readme.htm と GettingStarted.doc という 2 つの重要なファイルが含まれています。

EWS を操作するには、まず Exchange から受信する通知をリッスンする Web サービスを作成します。この Web サービスを作成したら、Exchange に登録して、通知の受信を開始する必要があります。

Microsoft Exchange Server 2010 SP1 Web Services SDK を使用すると、このような Web サービスを簡単に作成できます。2010 年 10 月リリース (この記事の執筆時点における最新バージョン) は、bit.ly/kZtjLq (英語) からダウンロードできます。

SDK を使用すると、最初の Web サービスの構築が大幅に簡略化されます。SDK には、API が対象とするさまざまな分野を紹介する 4 つのサンプルが含まれています。サンプルにアクセスするには、SDK をインストールしてから、[スタート] ボタンをクリックし、[すべてのプログラム] をポイントします。次に、[Exchange Server 2010 SP1 Web Services SDK] (Exchange Server 2010 SP1 Web サービス SDK)、[October 2010] (October 2010) の順にポイントし、[Exchange Server 2010 SP1 Web Services SDK Sample Directory] (Exchange Server 2010 SP1 Web サービス SDK サンプル ディレクトリ) をクリックします。特に重要なサンプルは、PushNotification です。このサンプルは、Exchange から着信する通知をリッスンして処理する、プッシュ型の通知 Web サービスです。このサンプルには、Exchange での Web サービス向けサブスクリプションの作成に使用できるクライアント アプリケーションも含まれています。このサンプルを基本実装として使用すると、EWS のしくみを理解しやすくなり、必要なすべての部分が機能することを確認しやすくなります。

Exchange を使用してサブスクライブする

Exchange を使って通知のサブスクリプションを作成するには、Exchange アカウントが必要です。サブスクリプションでは、Exchange アカウントのメールボックスに電子メールが送信されるたびに、そのアカウントに登録された通知サービスが Exchange から呼び出されるよう、ルーティングを設定します。どのアカウントにも複数の通知を登録できます。しかも、同一の Web サービス エンドポイントに複数のサブスクリプションを作成できます。Exchange と EWS に関する限り、この条件はまったく問題になりません。

EWS に登録する Web サービスに必要なことは、INotificationServiceBinding という特定のインターフェイスを実装することだけです。このインターフェイスのシグネチャは次のとおりです。

public interface INotificationServiceBinding {
  SendNotificationResultType SendNotification(
    SendNotificationResponseType sendNotification);
}

このインターフェイスの唯一の要件は、Web サービスに SendNotification メソッドの実装を含めることです。このメソッドは、サブスクリプションの属性に一致する電子メールを受信するたびに、Exchange から呼び出される Web メソッドです。

PushNotification サンプルに話を戻します。特に PushNotificationSubscriber コンソール アプリケーションに注目すると、サブスクリプションに必要な機能がよくわかります。図 2 に、PushNotificationSubscriber.cs ファイルから抜粋した SubscribeForPushNotifications メソッドを示します。

図 2 PushNotification サンプルのサブスクリプション コード

public static void SubscribeForPushNotifications()
{
  System.Net.ServicePointManager.ServerCertificateValidationCallback =
    delegate(Object obj, X509Certificate certificate, X509Chain chain,
    SslPolicyErrors errors)
  {
      // Replace this line with code to validate server certificate.
      return true; 
  };

  // Create the bindings and set the credentials.
  ExchangeServiceBinding esb = new ExchangeServiceBinding();
  esb.Url = "https://CAS01.contoso.com/EWS/exchange.asmx";
  esb.Credentials = new NetworkCredential("username", "password", "domain");

  // Create a new subscription.
  SubscribeType subscribeRequest = new SubscribeType();
  PushSubscriptionRequestType pushSubscription = 
    new PushSubscriptionRequestType();

  // Subscribe to events in the inbox folder.
  BaseFolderIdType[] folders = new BaseFolderIdType[1];
  DistinguishedFolderIdType folderId = new DistinguishedFolderIdType();
  folderId.Id = DistinguishedFolderIdNameType.inbox;
  folders[0] = folderId;
  pushSubscription.FolderIds = folders;

  // Subscribe to all events.
  NotificationEventTypeType[] eventTypes = 
    new NotificationEventTypeType[6];
  eventTypes[0] = NotificationEventTypeType.NewMailEvent;
  eventTypes[1] = NotificationEventTypeType.CopiedEvent;
  eventTypes[2] = NotificationEventTypeType.CreatedEvent;
  eventTypes[3] = NotificationEventTypeType.DeletedEvent;
  eventTypes[4] = NotificationEventTypeType.ModifiedEvent;
  eventTypes[5] = NotificationEventTypeType.MovedEvent;
  pushSubscription.EventTypes = eventTypes;

  // Receive push notifications every 1 minutes.
  pushSubscription.StatusFrequency = 1;

  // Identify the location of the client Web service.
  pushSubscription.URL = "http://clientWebService/Service.asmx";

  // Form the subscribe request.
  subscribeRequest.Item = pushSubscription;

  // Send the subscribe request and get the response.
  SubscribeResponseType subscribeResponse = 
    esb.Subscribe(subscribeRequest);

  // Check the result.
  if (subscribeResponse.ResponseMessages.Items.Length > 0 &&
    subscribeResponse.ResponseMessages.Items[0].ResponseClass ==
      ResponseClassType.Success)
  {
    SubscribeResponseMessageType subscribeResponseMessage =
      subscribeResponse.ResponseMessages.Items[0] as   
        SubscribeResponseMessageType;

      using (StreamWriter sw = new StreamWriter("MailboxEventLog.txt"))
      {
        sw.WriteLine("Subscribed for Push notifications: {0}", 
          subscribeResponseMessage.SubscriptionId);
      }
  }

  CreateXmlMessageTextFile(subscribeRequest, subscribeResponse);

}

図 2 のコードをここで紹介した理由は、サブスクリプションの登録時に利用できる主な機能がこのコードに含まれているためです。特に、サンプルで最初の情報 (クライアント アクセス サーバーの URL) を割り当てる方法に注目してください。

esb.Url = "https://CAS01.contoso.com/EWS/exchange.asmx";

続いてサンプルでは、EWS を使って認証する電子メール アカウントの資格情報を使用します。

esb.Credentials = new NetworkCredential("username", "password", "domain");

また、サブスクリプション オブジェクトを作成したら、そのサブスクリプション オブジェクトを構成して、特定のイベント (新しいメール、コピー、移動、削除、変更など) や特定のメール フォルダーだけをサブスクライブするように設定できます。このようにすると、すべてのイベントをサブスクライブしてからアプリケーションでフィルター処理するのではなく、フィルター処理を Exchange に委任でき、柔軟性が大きく向上します。

最後に、StatusFrequency プロパティに注目します。これは数値プロパティで、登録済みのエンドポイントが使用可能なことを確認するために、Exchange からハートビート呼び出しを Web サービスに送信する頻度を分単位で表します。このプロパティを使用すると、無効になったエンドポイントへのサブスクリプションを Exchange でキャンセルできます。無効になったサブスクリプションとは、新しいホストに移動したことで新しい URL を使用するようになった Web サービスのサブスクリプションなどです。Web サービスの移動前にサブスクリプションの登録抹消を忘れた場合、そのサブスクリプションが永久に存続するため、存在しないエンドポイントに Exchange から通知が無駄に送信され続けます

次は、TFS の Support Request 作業項目の作成をサポートするために実装をカスタマイズする方法について説明します。この機能を説明する最適な方法は、Web サービスのデモを紹介してから実装の説明に進むことでしょう。

Web サービスを配置する

この記事に付属するコード プロジェクトには、1 つの Web サービスとその他サポート用成果物がいくつか含まれているだけです。登録を処理するコンソール アプリケーションは Web サービスに組み込まれており、独立していません。

Web サービスをビルドすると、Visual Studio 2010 から、または生成されたコンパイル済み Web サイトをホストにコピーして、Web サービスを配置できます。Web アプリケーションと、対応するアプリケーション プールは手動で作成する必要があります。アプリケーション プールの ID を監視者のユーザー アカウントとして設定します。Web サービスではアプリケーション プールの ID を偽装でき、偽装した ID を使用してサブスクリプションを実行できるため、この設定は重要です。これには 2 つのメリットがあります。

  1. Web サービスを再登録する必要が生じるたびに資格情報を入力する必要がなくなります。
  2. サブスクリプションを再度登録するために使用する視覚情報を、アクセス可能な場所に保存する必要がなくなります

Web サービスには、ログを書き込むフォルダーと TFS キャッシュとして使用するフォルダーへの書き込みアクセス許可が必要です。また、次の設定は Web サービスを使用する特定の環境に依存するため、web.config ファイルで構成する必要があります。

  • EWSServiceUrl: Exchange サービスの URL です。この URL は Exchange 管理者から入手します。
  • TeamFoundationServerUrl: 作業項目の配置先となる TFS プロジェクト コレクションの URL です (http://<サーバー名>:8080/tfs/ など)。
  • WorkItemTeamProject: TFS チーム プロジェクトの名前です。サポート チケット作業項目の種類を含みます (SupportWorkFlow など)。
  • WorkItemType: サポート チケット作業項目の種類に付けられた実際の名前です (Support Request など)。作業項目の名前を変更する場合、または他の作業項目の種類をサポートするために Web サービスを使用する場合 (この方法については、この記事の後半で説明します)、この構成を使用して新しい作業項目の名前を設定できます。
  • RequestSupportTeamName: 作業項目には、さまざまなチームをさまざまなサポート タスクに割り当てるための "Request Support Team" フィールドが含まれています。この割り当ては、作業項目の定義に含まれる Teams というグローバル リストによって実行されます。この機能を使用するには、フィールド定義を保持したままグローバル リストを作成し (作成方法については、この記事の「作業項目を構成する」を参照してください)、グローバル リストのいずれかの値を RequestSupportTeamName 構成キー (Customer Service など) に割り当てます。この機能を使用しない場合は、このフィールドのグローバル リストと "REQUIRED" 制約を作業項目から削除し、RequestSupportTeamName キーの値を空白のままにします。

これで、Web サービスを使用する準備が整いました。Web サーバーで IIS マネージャーを使用して Web アプリケーション フォルダーに移動すると、正常に設定できたかどうか確認できます (IIS 7 以降を使用している場合は、[コンテンツ ビュー] タブをクリックします)。続いて、[Service.asmx] ファイルのアイコンを右クリックし、[参照] をクリックします (図 3 参照)。図 4 と同じ Web ページが表示されます。

Browsing to the ASMX Page

図 3 ASMX ページの参照

Default Web Service URL with localhost as the Host

図 4 localhost をホストとしている既定の Web サービス URL

Web サービスの使用を開始するには、作業項目を TFS に登録する必要があります。この記事では TFS 2010 を使用することを想定していますが、TFS 2008 でも同じ作業項目と Web サービスを使用できます。

作業項目を構成する

この記事のサンプル コード (code.msdn.microsoft.com/mag201108TFS (英語) からダウンロード可能) には、Support Request というサンプルのサポート チケット作業項目の種類が含まれています。TFS に作業項目の種類をインポートする前にその定義、ワークフロー、およびレイアウトを確認するには、bit.ly/hyUNqo (英語) からダウンロードできる TFS Power Tools をインストールする必要があります。TFS Power Tools をインストールすると、Visual Studio IDE の [ツール] メニューに新しい [Process Editor] (プロセス エディター) コマンドが追加されます。Support Request.xml ファイル (サンプル ソリューションの Work Item フォルダーにあります) のアイコンをダブルクリックすると、[Fields] (フィールド)、[Layout] (レイアウト)、および [Workflow] (ワークフロー) という 3 つのタブを備えた Work Item Editor (作業項目エディター) ウィンドウが読み込まれます (図 5 参照)。

Workflow for the Support Ticket Work Item
(クリックすると拡大表示されます)

図 5 サポート チケット作業項目のワークフロー

作業項目のワークフローは、作業項目がサポートするさまざまな状態を表しています。このサンプルでは、New はワークフローが最初に作成された状態、In Progress は作業項目で説明している問題を実際に解決中の状態、Done は問題解決が完了した状態を表します。

前述のように Request Support Team フィールドを構成する場合は、[Fields] (フィールド) タブで Request Support Team フィールドを探し、このフィールドをダブルクリックして [Field Definition] (フィールド定義) ダイアログ ボックスを開き、[Rules] (規則) タブをクリックします。このフィールドを使用する予定がない場合は、表示されている 2 つの規則 (ALLOWEDVALUES と REQUIRED) を削除します。このフィールドを使用する予定がある場合に別のグローバル リストを使用するよう構成する必要があるときは、ALLOWEDVALUES 規則をダブルクリックし、1 つだけ表示される [GLOBALLIST: Teams] エントリを選択します。[List Item Edit] (リスト項目編集) ダイアログ ボックスで、目的のグローバル リストを選択して [OK] をクリックします。

グローバル リストをまだ設定していない場合は、次の手順で作成できます (TFS 管理者のアクセス許可が必要です)。

  1. Visual Studio IDE で、[ツール] メニューの [Process Editor] (プロセス エディター)、[Global List] (グローバル リスト) の順にポイントし、[Open Global List from Server] (サーバーからグローバル リストを開く) をクリックします。
  2. ダイアログ ボックスが表示されます。チーム プロジェクト コレクションを選択し、[Connect] (接続) をクリックします。
  3. [Global List] (グローバル リスト) ダイアログ ボックスで、任意の項目を右クリックし、[New Global List] (新しいグローバル リスト) をクリックします。
  4. グローバル リストの名前を入力します。作業項目のグローバル リストと同じ「Teams」という名前をそのまま使用できます。
  5. 新しいグローバル リストを右クリックし、[New Item] (新しい項目) をクリックします。入力する必要があるチーム名の数だけこの手順を繰り返します。
  6. [OK] をクリックして新しいグローバル リストを保存します。

新しいグローバル リストに別の名前を付けた場合は、作業項目を編集し、新しいグローバル リスト名で定義を更新する必要があることに注意してください。

後は、次のように作業項目を TFS にインポートするだけです。

  1. Visual Studio IDE で、[ツール] メニューの [Process Editor] (プロセス エディター)、[Work Item Types] (作業項目の種類) の順にポイントし、[Import WIT] (WIT のインポート) をクリックします (WIT は "作業項目の種類" の略称です)。
  2. [Browse] (参照) をクリックし、Support Request.xml ファイルの場所に移動します。
  3. [Project to Import to] (インポート先プロジェクト) の一覧で、作業項目をインポートする TFS チーム プロジェクトの名前をクリックし、[OK] をクリックします。

作業項目が正常に TFS にインポートされたことを確認するには、チーム エクスプローラーで、目的のチーム プロジェクトの [作業項目] ノードを右クリックし、[新しい作業項目] ウィンドウを展開します。使用できるオプションの 1 つとして、[Support Request] が表示されます。この作業項目の種類が表示されない場合は、[作業項目] ノードを右クリックし、[最新の情報に更新] をクリックします。

サブスクリプションを作成する

図 4 に示すように、Web サービスには CheckStatus、SendNotification、および Subscribe の 3 つのメソッドがあります。Subscribe Web メソッドは、通知のサブスクリプションを作成するために使用します。

サブスクリプション プロセスは、Web サービスのアプリケーション プールの ID として設定されているユーザー アカウントに対するサブスクリプションを作成します。通知を効果的に使用するために、対象となるアカウント (監視者アカウント) を監視対象の DL に含めます (図 6 参照)。

Adding the Watcher E-mail Account to a Distribution List

図 6 監視者の電子メール アカウントを配布リストに追加する

サブスクリプションを作成するには、まず図 4 の Web ページで [Subscribe] リンクをクリックします。次に、表示される Web ページで [Invoke] ボタンをクリックします。正常に作成されると、サブスクリプション ID が表示されます。また、この ID は web.config ファイルで定義している Logs フォルダーにログ記録されます。

サブスクリプションの詳細情報は、2 つのファイルにログ記録されます。1 つは、サブスクリプションを実行するために EWS に送信した要求をログ記録する、SubscribeType-<タイムスタンプ>.xml という形式の名前のファイルです。もう 1 つは、サブスクリプションを確認するために EWS から受信した応答をログ記録する、SubscribeResponseType-<タイムスタンプ>.xml という形式の名前のファイルです。SubscriberEventLog.txt という名前の 3 つ目のファイルは、Web で Exchange から受信したすべてのイベント、つまり、毎分発生するハートビートの状態イベントや新しいメールのイベントなどが発生するたびにログ記録します。

サブスクリプションの状態は、任意のタイミングで CheckStatus Web メソッドを呼び出して確認できます。このメソッドを実行すると、図 7 のように、最後にハートビート イベントを受信した日時と Web サービスのサブスクリプションの状態を示す結果が返されます。有効なサブスクリプションがある場合、図のように "Status: Subscribed" というテキストが表示されます。

Sample Output from the CheckStatus Web Method

図 7 CheckStatus Web メソッドの出力例

プロセス全体を図 8 のシーケンス図に示します。

The Subscription and Notification Process

図 8 サブスクリプションと通知のプロセス

チケット システムを使用する

チケット システムの使用を開始する最も簡単な方法は、実際のシナリオをまねて、監視者アカウントが含まれた DL に電子メールを送信することです。図 9 に、図 6 に示した DL へのサンプル電子メールを示します。また、図 10 に、Exchange から通知 Web サービスに送信された通知を基に生成した Support Request 作業項目を示します。

The First E-mail in a Mail Thread

図 9 メール スレッドでの最初の電子メール

The Work Item Generated as a Result of the First E-mail
(クリックすると拡大表示されます)

図 10 最初の電子メールから生成された作業項目

図 11 に、同じ電子メール スレッドの一部として別の電子メールを送信した結果と、この電子メールが作業項目の履歴に変換されたようすを示します。スレッドの最初のメールは、ヘッダーを目立つ色にしています。2 通目以降は、別の色を設定しています (ここでは黄色ですが、web.config で色を構成できます)。

The Work Item After a Second E-mail
(クリックすると拡大表示されます)

図 11 2 通目の電子メールを送信した後の作業項目

コードをカスタマイズする

ここで、システムを動かす別のコードを見てみましょう。この記事のサンプル コードには、Email2Workitem.sln という Visual Studio 2010 ソリューションを含めています。このソリューションを Visual Studio で読み込むと、Diagrams、Subscription Library、Web Service、および Work Item の 4 つのソリューション フォルダーに分かれた構造になっているることがわかります。

Web サービスのほとんどの部分は PushNotification SDK サンプルに基づいています。ただし、ソリューションの汎用性を高め、使いやすくするために、いくつか変更を加えています。ここでは、SDK のサンプルをチケット ソリューションに変えるために行った変更点とカスタマイズについて説明します。

最初の大きな変更点は、サブスクリプション プロセスを Web サービスに統合する機能です。Web サービスがアカウントの資格情報を管理しなくてもサブスクライブできるようになるため、この変更は非常に重要です。Web サービスをホストしているサーバーでメンテナンス作業を実施する場合など、サブスクリプションの更新が必要になることがあります。更新が必要になった場合、通常はアプリケーションが停止し、ハートビート イベントの応答が返されなくなるため、Exchange はサブスクリプションをキャンセルします。サブスクリプションを自動更新するには、Web サービスのコンストラクターで InitializeTimer メソッドを呼び出します。InitializeTimer メソッド (図 12 参照) は、web.config で指定した間隔のタイマーを作成し、このタイマーを使って、サービスの中断後などにサブスクリプションを更新します。

図 12 InitializeTimer メソッド

private void InitializeTimer()
{
  int autoSubscribeTimeoutThresholdInMinutes = Convert.ToInt32(
    ConfigurationManager.AppSettings["AutoSubscribeTimeoutThresholdInMinutes"]);
 
    lock (_pollingTimerSyncLock)
    {
      if (autoSubscribeTimeoutThresholdInMinutes > 0)
      {
        // Seed the timer with the polling interval specified in config.
        if (_pollingTimer == null)
        {
          TimerCallback timerCallback = OnTimedEvent;
          _pollingTimer = new Threading.Timer(timerCallback, null, 0, 
          _pollingIntervalInMilliseconds); // Enable the timer.
        }
      }
      else
      {
        // Dispose of the timer.
        if (_pollingTimer != null)
        {
          _pollingTimer.Dispose();
          _pollingTimer = null;
        }
      }
    }
}

2 つ目の重要な変更点は、受信メッセージを調べて、スレッドで最初の電子メールかどうかを判断する処理です。図 13 はこの機能を示しています。

図 13 スレッドで最初の電子メールの判断

// Get either the folder or item identifier for a 
// create/delete/new mail event.
if (bocet.Item is ItemIdType)
{
  // Get the item identifier.
  ItemIdType itemId = bocet.Item as ItemIdType;
 
  //
  // Get the message using the ItemIdType.
  //
 
  // From web.config
  string ewsServiceUrl = 
    ConfigurationManager.AppSettings["EWSServiceUrl"];
 
  ExchangeService esb = 
    new ExchangeService(ExchangeVersion.Exchange2010);
  esb.Url = new Uri(ewsServiceUrl);
  // From Web service App Pool identity.
  esb.UseDefaultCredentials = true;
 
  EmailMessage message = EmailMessage.Bind(esb, new ItemId(itemId.Id));
  ConvertEmailToRequestItem(message);
}

このコードでは、Web サービスのアプリケーション プール ID がメール アカウントの ID であることを利用しています。この手法により、資格情報を入力しなくても、電子メール メッセージの詳細を取得する Web 呼び出しを実行できます。

ConvertEmailToRequestItem メソッドが処理のほとんどを実行します。最初の電子メールなのか、スレッドに含まれる電子メールなのかを判断するには、EmailMessage クラスのインスタンスの ConversationIndex プロパティを利用します。最初の電子メールの場合、ConversationIndex バイト配列の長さは 22 です。スレッドでの 2 通目以降の電子メールの場合、ConversationIndex プロパティの長さが数バイト増加します。ConvertEmailToRequestItem メソッドではこのしくみを利用して、電子メールを新しいメッセージとして処理して新しい対応する作業項目を作成するか、既存のスレッドの一部として扱うか判断します。既存のスレッドの一部として扱う場合は、既存の作業項目を参照し、メール メッセージのスレッド固有の部分を作業項目のリビジョン履歴に追加します。Exchange は、EmailMessage の UniqueBody プロパティを使用して、スレッドの現在の電子メールに固有の部分を公開します。スレッド全部を取得するには、Body プロパティを使用します。この手法は、作業項目のリビジョン履歴内に電子メール スレッドを構築できるので、きわめて強力です (図 11 参照)。

説明しておく必要のある特別な状況の 1 つが、スレッドの一部であっても、更新可能な対応作業項目が存在しない電子メールを受信した場合です。これは通常、チケット システムの配置前にスレッドが存在していた場合に発生します。その場合は、新しい作業項目を作成します。

Web サービスから電子メールが作業項目として既に存在しているかどうか確認するには、作業項目を最初に作成したときに格納した情報 (ConversationIndex) を使用します。この値に基づいて、Web サービスから作業項目をクエリし、作業項目が存在するかどうか確認します。クエリでは、次のコードに示すように TFS の作業項目クエリ言語 (WIQL) を使用します。

private const string QUERY_BY_CONVERSATION_INDEX_WIQL =
  "SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = '{0}'  AND
    [System.WorkItemType] = 'Support Request' AND
    [MsdnMag.SupportTicket.ConversationIndex] = '{1}' ORDER BY [System.Id] desc";

WIQL を使用すると、オブジェクトを読み込んでコレクション全体を列挙しなくても、簡単かつ強力な方法でクエリを作成できます。

Web サービスでは、TFS アクティビティ ログの作業項目も簡単にトラッキングできます。TFS アクティビティ ログは、チーム プロジェクト コレクションが格納されるデータベース内の 2 つの SQL Server テーブル (tbl_Command と tbl_Parameter) に格納されます。tbl_Command の UserAgent 列を調べると、TFS 管理者は要求の送信元を把握できます。

通知 Web サービスでは、次のステートメントを使用してユーザー エージェントのデータを明確に特定できるように、このデータをカスタマイズしています。

TfsConnection.ApplicationName = string.Format(
  TFS_APPLICATIONNAME_TEMPLATE, WindowsIdentity.GetCurrent().Name);

この例では、ユーザー エージェントは "MsdnMagSubscribeSvc – Contoso\JDoe" のような形式になります。

ConvertEmailToRequestItem メソッドには、次のコードのように、件名に含まれる特定のプレフィックスに従って電子メールをフィルター処理する便利な機能もあります。

// First check if prefix-based filtering is turned on, and if so, 
// if the e-mail subject line matches the defined prefix.
string subjectPrefix = 
  ConfigurationManager.AppSettings["SubjectPrefix"];
if (!string.IsNullOrWhiteSpace(subjectPrefix))
{
  if (!title.StartsWith(subjectPrefix, 
    StringComparison.InvariantCultureIgnoreCase))
  {
    WriteEventToLog(
      string.Format(SUBJECT_DOES_NOT_MATCH_PREFIX_TEMPLATE,
      subjectPrefix, title));
 
    return;
  }
}

この機能を使用すると、サービスの機能の対象を一部の電子メール (たとえば、"Code Review" とプレフィックスを定義したコード レビューの電子メールなど) に制限できます。

その他のユース ケース: コード レビュー

ここまでは、サポート チケットのユース ケースを紹介してきました。ただし、この記事で紹介した方法は柔軟性が高いため、コード レビューのトラッキングなどの別のユース ケースにも簡単に流用できます。コード レビュー ユース ケースのプロセス フローを図 14 に示します。

Process Flow for the Code Review Work Item

図 14 コード レビュー作業項目のプロセス フロー

開発組織は電子メールを使ってコード レビューを実施することがよくあります。これまでも、コード レビュー作業項目を作成し、Visual Studio でコード レビューのプロセスを管理できるようにするアドインを構築することでコード レビューを TFS に統合する試みが何度も行われてきました。しかし、サポート チケットと同じ手法を使用すると、コード レビューの電子メール スレッドを TFS の作業項目トラッキング システムに容易に統合できます。以下の手順では、通知インフラストラクチャをコード レビューに使用するプロセスの例を簡単に説明しています。

  • まず、Support Request 作業項目と同様に Code Review 作業項目を作成します。
  • DL に送信された電子メールを監視する、監視者アカウントを DL に設定します。
  • SubjectPrefix の機能を使用して、コード レビューの電子メールを識別するプレフィックスを定義します。電子メールで送信されるコード レビュー依頼には、多くの場合、"Code Review: My-Shelveset-Name" というパターンに従った件名が使用されます。

図 14 に示すように、シェルブセットの内容に対する実際のチェックインを作業項目に関連付けることで、コードが完成してから、コード レビューに送られ、チェックインが承認され、最後にチェックインが完了するまでのコードの有効期間を追跡できるようになります。この関連付けは、TFS の強力な機能であり、ソース管理を通じてチェックインするすべてのコードを詳しく把握できます。監査上の理由から追跡可能性を確保する必要がある組織にとって、この機能は特に便利です。

次のステップ

この記事の目標は、TFS と Exchange を併用して生産性と効率の両方を向上するさまざまな方法の 1 つを説明することでした。作業項目の (特に TFS 2010 における) 優れた点の 1 つは、TFS 内での統合方法です。作業項目は、変更セットにリンクできます。テスト計画を表してトラッキングできます。Excel や SSRS を使用してレポートを容易に作成でき、Microsoft Project と同期することもできます。

この記事で紹介したユース ケースと手法を身に付ければ、実際の環境固有のさまざまなシナリオでも、通知 Web サービスと作業項目のカスタマイズを活用できます。

Mohammad Jalloul は、ソーシャル エンターテイメント Web サイトである Myspace Inc. のソフトウェア エンジニアとして、TFS をさまざまなビジネス プロセスに統合し、TFS を活用して効率と生産性を向上する仕事を担当しています。現職に就く前は、レドモンドにあるマイクロソフト開発部門で Gibraltar と呼ばれる内部ツールに携わっていました。彼のブログは、mohammadjalloul.com (英語) からご覧になれます。

この記事のレビューに協力してくれた技術スタッフの Bill Heys に心より感謝いたします。