次の方法で共有


Project Server のイベント ハンドラーを作成し、イベントをログに記録する

適用対象: Office 2010 | Project 2010 | Project Server 2010 | SharePoint Server 2010

この記事の内容
イベント ハンドラーの開発
イベント ハンドラーの展開
イベント ハンドラーの関連付けの登録
イベント ハンドラーのテスト: イベント ビューアーと ULS ログの使用
イベント ハンドラーのデバッグ

Events Service を使用すると、新しいビジネス ロジックを追加することにより、Microsoft Project Server 2010 を拡張できます。Project Server は、Project Server Interface (PSI) メソッドによって Project、Task、Resource、Timesheet などのビジネス オブジェクトが変更されるときに、プリイベントとポストイベントを発生します。イベント ハンドラーとイベントを関連付けると、特定のイベントの発生時にイベント ハンドラーが実行されます。この記事では、イベント ハンドラーを作成、展開、テスト、およびデバッグする方法と、Windows イベント ログおよび統合ログ サービス (ULS) トレース ログに SharePoint アプリケーションのエントリを書き込む方法について説明します。

重要

Project Server イベント ハンドラーは、Project Server を実行しているローカル コンピューター、またはリモート コンピューターで開発できます。どちらの場合も、イベント ハンドラーを開発、テスト、およびデバッグするには、運用サーバーではなく、テスト用の Project Server インストールのみを使用してください。

この記事は次のセクションで構成されます。

  • イベント ハンドラーの開発

  • イベント ハンドラーの展開

  • イベント ハンドラーの関連付けの登録

  • イベント ハンドラーのテスト: イベント ビューアーと ULS ログの使用

  • イベント ハンドラーのデバッグ

注意

Microsoft Project Professional 2010 と Project Web App は、PWA サービスと WinProj サービスのプライベート PSI メソッドを呼び出すことがあるため、パブリック PSI メソッドの場合と同じイベントが呼び出されるとは限りません。イベント ハンドラーを開発する場合は、Project Professional 2010、Project Web App、ワークフローのプロジェクト詳細ページ (PDP)、および PSI を使用するサードパーティ アプリケーションのアクションが、期待どおりにイベント ハンドラーを呼び出すかどうかをテストします。

たとえば、Project Professional 2010 を使用してプロジェクトを作成する場合、OnCreating イベント ハンドラーは呼び出されません。しかし、Project Web App において、[プロジェクト センター] ページの [新規作成] ドロップダウン メニューで、[サンプル提案] ワークフローまたは [基本的なプロジェクト計画] を選択することによってプロジェクトを作成する場合は、OnCreating イベント ハンドラーが呼び出されます。

Project Server 2010 には Microsoft Office Project Server 2007 より多くのイベント ハンドラーがありますが、イベント ハンドラーは同じように動作します。詳細については、「Project Server Events」を参照してください。ユーザーの委任の OnActivated ポストイベントと OnDeactivated ポストイベントのイベント ハンドラーが含まれる例については、Christophe Fiessinger のブログ投稿「プロジェクトのサーバー 2010 年委任監査イベント ハンドラー (英語)」を参照してください。電子メール通知を変更する OnSending プリイベントのイベント ハンドラーの例については、「How to: Customize E-Mail for Project Server Notifications」を参照してください。

イベント ハンドラーの開発

この記事における OnCreating イベント ハンドラーは ProjectCreating プリイベントに対するものであり、QueueCreateProject メソッドがプロジェクトを作成する直前に発生します。プリイベントでは、ビジネス ルールを追加し、ルールが該当しない場合はアクションを取り消すことができます。TestProjectCreating の例は、イベント引数内での DataSet の使用方法と、イベント ハンドラー内での別の PSI サービスの使用方法を示しています。例では、指定の部署のプロジェクトに 4 つ以上のタスクが含まれるかどうかを確認しています。該当する場合、イベントは取り消されます。どちらの場合も、イベント ハンドラーはアプリケーションのイベント ログと ULS ログに書き込みを行います。

Project Server 2010 内のすべてのイベントの一覧については、PSEventID 列挙を参照してください。Project オブジェクトに対して使用できるイベント ハンドラーの一覧については、ProjectEventReceiver クラスのメソッドを参照してください。プリイベントは、イベント ハンドラー内で取り消すことができます。ProjectCreated イベントなどのポストイベントは、取り消すことができません。ポストイベントは、既に発生したアクションによって生じる情報を収集および変換するために使用されます。各イベントによって、イベント ハンドラーのパラメーターにイベント引数が提供されます。OnCreating イベント ハンドラーのパラメーターには、ユーザー名、Project Web App サイトの GUID、指定カルチャなどのコンテキスト情報が含まれます。ProjectPreEventArgs パラメーター内のイベント引数には、作成されるプロジェクトの ProjectDataSet、プロジェクトの GUID、プロジェクト名などが含まれます。

セキュリティに関するメモセキュリティに関するメモ

Project Server のイベント ハンドラーは、SharePoint ファーム管理者の資格情報、または、Microsoft Project Server Events Service 2010 サービスの指定されたログオン アカウントを使用して、Project Server コンピューター上で実行されます。イベント ハンドラーは、Project Web App フロントエンドではなく、Project Server バックエンド上で既に実行されているため、通常、イベント ハンドラーでは偽装は使用されません。

手順 1. イベント ハンドラーを開発するには

  1. Project Server が実行されているコンピューターで開発している場合は、[参照の追加] ダイアログ ボックスを使用してアセンブリを参照することによって、次のアセンブリへの参照を直接設定できます。リモート コンピューターで開発している場合は、Project Server コンピューターから開発コンピューター上の適切なディレクトリに、次のアセンブリをコピーします。

    • Microsoft.Office.Project.Schema.dll:  Microsoft.Office.Project.Server.Schema 名前空間には、ProjectDataSet など、イベント引数に必要なクラス定義が含まれています。[Windows]\assembly\GAC_MSIL\Microsoft.Office.Project.Schema\14.0.0.0__71e9bce111e9429c ディレクトリからコピーするか、これを参照します。

      イベント引数にいずれの PSI データセットも含まれない場合、Microsoft.Office.Project.Server.Schema 名前空間は必要ありません。

    • Microsoft.Office.Project.Server.Events.Receivers.dll:  Project Server コンピューター上の [Program Files]\Microsoft Office Servers\14.0\Bin ディレクトリからコピーするか、これを参照します。

    • Microsoft.Office.Project.Server.Library.dll:  [Program Files]\Microsoft Office Servers\14.0\Bin ディレクトリからコピーするか、これを参照します。

    • Microsoft.SharePoint.dll:  イベント ハンドラーが別の PSI サービスを使用する場合、または、プロジェクト サイトを使用する場合は、Microsoft.SharePoint 名前空間が必要です。[Program Files]\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI ディレクトリからコピーするか、これを参照します。

    アセンブリをコピーするには、Project Server コンピューター上で、管理者として [Visual Studio コマンド プロンプト (2010)] ウィンドウを実行します。CopyRefs.bat ファイル (Project 2010 SDK ダウンロード内) によって、Project Server コンピューターから開発コンピューターへ、必要なアセンブリがコピーされます。次のスクリプトの中で、開発コンピューター名と共有名を変更してください。

    echo off
    
    set SHARE=\\DEV_PC\ShareName
    
    set SCHEMA=C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Project.Schema\14.0.0.0__71e9bce111e9429c
    set PROJ_SERVER_LIBS="c:\Program Files\Microsoft Office Servers\14.0\Bin"
    set SHAREPOINT_LIBS="C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI"
    
    xcopy /y %SCHEMA%\*.dll %SHARE%
    xcopy /y %PROJ_SERVER_LIBS%\Microsoft.Office.Project.Server.Events.Receivers.dll %SHARE%
    xcopy /y %PROJ_SERVER_LIBS%\Microsoft.Office.Project.Server.Library.dll %SHARE%
    xcopy /y %SHAREPOINT_LIBS%\Microsoft.SharePoint.dll %SHARE%
    
  2. Microsoft Visual Studio 2010 で、種類がクラス ライブラリのプロジェクトを作成し、たとえば、TestCreatingProject という名前を付けます。Visual C# プロジェクトの場合は、Class1.cs の名前を変更して、たとえば、TestCreatingProject.cs という名前に変更できます。ソース コード内で名前空間の名前を変更する場合は、プロジェクトの [プロパティ] ウィンドウの [アプリケーション] タブでも、既定の名前空間を変更する必要があります。

  3. 手順 1. で指定する参照を追加し、次の参照アセンブリを追加します。

    • System.Runtime.Serialization.dll

    • System.Security.dll

    • System.ServiceModel.dll

  4. TestCreatingProject.cs ファイル内のグローバル参照に次の行を追加します。

    using System.Diagnostics;
    using System.ServiceModel;
    using System.Security.Principal;
    using Microsoft.SharePoint;
    using Microsoft.Office.Project.Server.Events;
    using PSLib = Microsoft.Office.Project.Server.Library;
    using PSSchema = Microsoft.Office.Project.Server.Schema;
    
  5. TestCreatingProject.cs ファイル内の Class1 定義を削除し、必要なイベント レシーバーの基本抽象クラスから派生するイベント ハンドラー クラスを作成します。たとえば、クラスに CheckProjectDepartment という名前を付けます。次の例では、既定の名前空間が変更されており、クラスは ProjectEventReceiver 基本抽象クラスから派生します。

    namespace Microsoft.SDK.Project.Samples.TestCreatingProject
    {
        public class CheckProjectDepartment : ProjectEventReceiver
        {
        }
    }
    
  6. 特定のイベントの基本メソッドを上書きするメソッドを作成します。各イベントには対応する基本メソッドがありますが、これを独自の実装で上書きする必要があります。たとえば、Project ビジネス オブジェクトの Creating イベントのイベント ハンドラーを作成するには、OnCreating メソッドを上書きします。Visual Studio では、IntelliSense によって、有効な基本メソッドを選択し、次のようにメソッドのフレームワークを入力できます。

    public override void OnCreating(PSLib.PSContextInfo contextInfo, ProjectPreEventArgs e)
    {
        base.OnCreating(contextInfo, e);
    }
    

    基本メソッドは抽象クラスで処理を行わないため、base.OnCreating メソッドをコメント アウトするか、削除できます。

  7. TestCreatingProject ソリューションは、イベント ログと ULS ログへの書き込みを行います。ULS トレース ログ用のログ サービスを作成するには、LoggingService という名前のクラスを Visual Studio プロジェクトに追加し、名前空間を CheckProjectDepartment クラスの名前空間に合わせて変更します。次のコードは、LoggingService.cs ファイル内の完全なクラス実装であり、Verbose レベルの情報カテゴリと Unexpected レベルの警告カテゴリが作成されます。ULS トレース ログの使用の詳細については、「ユーザー設定コードからトレース ログに書き込む」および「SharePoint 2010 のデバッグ機能とログ機能」を参照してください。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.SharePoint.Administration;
    
    namespace Microsoft.SDK.Project.Samples.TestCreatingProject
    {
        // Define a custom logging service for the ULS log.
        public class LoggingService : SPDiagnosticsServiceBase
        {
            private const string LOG_SERVICE_NAME = "Project Test Logging Service";
            private const string PRODUCT_DIAGNOSTIC_NAME = "Project Server Event Handler";
            private const uint EVENT_ID = 5050;
    
            // ULS categories:
            public const string PROJECT_INFO = "Event Handler Information";
            public const string PROJECT_WARNING = "Event Handler Warning";
    
            private static LoggingService activeLoggingService;
    
            private LoggingService() : base(LOG_SERVICE_NAME, SPFarm.Local)
            {
            }
    
            // Register the product name and set the ULS log categories that are available.
            protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()
            {
                List<SPDiagnosticsArea> areas = new List<SPDiagnosticsArea>
                {
                    new SPDiagnosticsArea(
                        PRODUCT_DIAGNOSTIC_NAME,
                        new List<SPDiagnosticsCategory>
                        {
                            new SPDiagnosticsCategory(PROJECT_INFO,
                                                      TraceSeverity.Verbose, 
                                                      EventSeverity.Information),
                            new SPDiagnosticsCategory(PROJECT_WARNING,
                                                      TraceSeverity.Unexpected,
                                                      EventSeverity.Warning),
                        })
                };
                return areas;
            }
    
            // Create a LoggingService instance.
            public static LoggingService Active
            {
                get
                {
                    if (activeLoggingService == null)
                        activeLoggingService = new LoggingService();
                    return activeLoggingService;
                }
            }
    
            // Write an information message to the ULS log.
            public static void LogMessage(string categoryName, string message)
            {
                SPDiagnosticsCategory category =
                    LoggingService.Active.Areas[PRODUCT_DIAGNOSTIC_NAME].Categories[categoryName];
                LoggingService.Active.WriteTrace(EVENT_ID, category, TraceSeverity.Verbose, message);
            }
    
            // Write an error message to the ULS log.
            public static void LogError(string categoryName, string message)
            {
                SPDiagnosticsCategory category =
                    LoggingService.Active.Areas[PRODUCT_DIAGNOSTIC_NAME].Categories[categoryName];
                LoggingService.Active.WriteTrace(EVENT_ID, category, TraceSeverity.Unexpected, message);
            }
        }
    }
    
  8. LookupTable サービスの wcfLookupTable.cs プロキシ ファイルを Visual Studio プロジェクトに追加します。PSI プロキシ ファイルは、Project 2010 SDK ダウンロードの Documentation\Intellisense\WCF\Source サブディレクトリにあります。

  9. OnCreating イベント ハンドラーの実装を、PSContextInfo イベント引数と ProjectPreEventArgs イベント引数のプロパティを使用して記述します。次のコードの中で、eventLog オブジェクトがシステムの EventLog への参照を取得するには、using System.Diagnostics; というステートメントが必要です。

    注意

    例の中での ProjectDataSet オブジェクトの出力は、デバッグのみが目的です。運用サーバーではファイル出力を行わないでください。

    OnCreating イベント ハンドラーは、次の処理を行います。

    1. EventLog インスタンスを作成し、そのソースを割り当てます。イベント ログ エントリは、オプションのアプリケーション固有のイベント識別番号 (EVENT_ID 定数) を使用します。これにより、イベントのフィルター処理を実行できます。

    2. ユーザー名、Project Web App GUID、別のアプリケーションが QueueCreateProject を呼び出すときに使用した ProjectDataSet など、イベント引数から情報を取得します。イベント引数内の ProjectDataSet は読み取り専用です。Microsoft.Office.Project.Server.Schema.ProjectDataSet という種類の変数に割り当てることができます。

    3. 組み込みの Department 参照テーブル内の値の GUID を取得します。GUID は、Project Departments ユーザー設定フィールドの CODE_VALUE プロパティです。Project Departments ユーザー設定フィールド自体の GUID は、PROJECT_DEPARTMENT_MD_PROP_UID 値です。

    4. GetDepartmentValue メソッドを使用して部署名を見つけます (手順 10. および手順 11. を参照)。

    5. Cancel プロパティを既定値 false に設定して、イベント アクションを続行させます。

    6. ビジネス ロジックを実装し、Cancel プロパティを true に設定するかどうかを決定します。OnCreating イベント ハンドラーの例では、指定の部署のプロジェクトに 4 つ以上のタスクがある場合は、イベント アクションは取り消され、プロジェクトは作成されません。

    7. WriteLogEntries メソッドを使用して、イベント ログ エントリと ULS ログ エントリを作成します (手順 12. を参照)。

    public class CheckProjectDepartment : ProjectEventReceiver
    {
        // Change the department name to match a department in your installation.
        private const string PROJECT_DEPARTMENT2CHECK = "Test Dept 2";
    
        private const string EVENT_SOURCE = "Project Event Handler";
        private const int EVENT_ID = 5050;
        private static SvcLookupTable.LookupTableClient lookupTableClient;
        private EventLog eventLog;
    
        // Change the output directory for your computer.
        private const string OUTPUT_FILES = @"C:\Project\Samples\Output\";
        private static string outFilePath;
    
        public override void OnCreating(PSLib.PSContextInfo contextInfo, ProjectPreEventArgs e)
        {
            // The base method does no processing in an abstract class.
            //base.OnCreating(contextInfo, e);
    
            // Create an EventLog instance and assign its source.
            eventLog = new EventLog();
            eventLog.Source = EVENT_SOURCE;
            string logEntry = string.Empty;
    
            // Get information from the event arguments.
            string userName = contextInfo.UserName;
            Guid pwaUid = contextInfo.SiteGuid;
    
            string projectName = e.ProjectName;
            Guid projectUid = e.ProjectGuid;
            PSSchema.ProjectDataSet projDs = e.ProjectDataSet;
    
            // Write the ProjectDataSet to a file, for debugging purposes.
            outFilePath = OUTPUT_FILES + "ProjectDataSet4CreatingEventHandler.xml";
            projDs.WriteXml(outFilePath);
    
            e.Cancel = false;
    
            // Get the GUID of the default Project Departments custom field.
            Guid projDeptCFMdPropUid = PSLib.CustomField.PROJECT_DEPARTMENT_MD_PROP_UID;
            Guid projDeptUid = Guid.Empty;
    
            for (int i = 0; i < projDs.ProjectCustomFields.Rows.Count; i++)
            {
                if (projDs.ProjectCustomFields[i].MD_PROP_UID == projDeptCFMdPropUid)
                {
                    // Get the custom field value, which is the GUID of the value in 
                    // the Department lookup table.
                    projDeptUid = projDs.ProjectCustomFields[i].CODE_VALUE;
                    break;
                }
            }
    
            int numTasks = projDs.Task.Rows.Count;
            string departmentName = GetDepartmentValue(pwaUid, projDeptUid);
    
            if (projDeptUid != Guid.Empty)
            {
                // Sample 'business rules.'
                if (departmentName == PROJECT_DEPARTMENT2CHECK && numTasks > 3)
                {
                    e.Cancel = true;
                }
            }
            // For this example, write the log entries in all cases.
            WriteLogEntries(e.Cancel, numTasks, departmentName, userName, projectName);
        }
    
        // Add the GetDepartmentValue method and the WriteLogEntries method.
    }
    
  10. GetDepartmentValue メソッドを作成します。プロジェクト部署の GUID とテキスト値は Department 参照テーブルの LookupTableTrees テーブルに格納されており、組み込みの Department 参照テーブルの GUID は DEPARTMENTS_LT_UID で指定されるため、ReadLookupTablesByUids メソッドを使用して、参照テーブルのデータを取得できます。参照テーブルのメソッドを使用するには LookupTableClient オブジェクトを初期化する必要があり、次に SetClientEndpoint メソッド (手順 11.) が必要です。

    GetDepartmentValue メソッドは、LookupTableTrees テーブルを反復処理して、LT_STRUCT_UID (参照テーブル値の GUID) が、ProjectDataSet から取得された部署の GUID に一致するリーフ ノードを見つけます。一致するものがある場合、部署名は LT_VALUE_TEXT プロパティです。

    // Get the name of the department.
    private string GetDepartmentValue(Guid pwaUid, Guid departmentUid)
    {
        // Set the language code for the lookup table; U.S. English in this case.
        const int LCID = 1033;  
        string result = string.Empty;
    
        SetClientEndpoint(pwaUid);
    
        // Read the Departments lookup table data.
        Guid[] lutUids = { PSLib.LookupTables.DEPARTMENTS_LT_UID };
        SvcLookupTable.LookupTableDataSet lutDs = 
            lookupTableClient.ReadLookupTablesByUids(lutUids, false, LCID);
    
        // Find the text value in the lookup table tree item that matches the department GUID.
        for (int i = 0; i < lutDs.LookupTableTrees.Count; i++)
        {
            if (lutDs.LookupTableTrees[i].LT_STRUCT_UID == departmentUid)
            {
                result = lutDs.LookupTableTrees[i].LT_VALUE_TEXT;
                break;
            }
        }
        lookupTableClient.Close();
        return result;
    }
    
  11. イベント ハンドラーに対して app.config ファイルを使用することはできないため、SetClientEndpoint メソッドを作成して、LookupTableClient オブジェクトの WCF エンドポイントをプログラムで設定します。SetClientEndpoint メソッド内のコードは、記事 「[ウォークスルー] WCF を使用して PSI アプリケーションを開発する」の「サービスをプログラムで構成する」に記載されているコードによく似ています。主な違いは、Project Web App GUID がイベント引数から分かることです。サイト GUID で SPSite オブジェクトを初期化すると、サイトの URL を取得できます。

    // Programmatically set the WCF endpoint for the LookupTable client.
    private void SetClientEndpoint(Guid pwaUid)
    {
        const int MAXSIZE = 500000000;
        const string svcRouter = "/_vti_bin/PSI/ProjectServer.svc";
    
        BasicHttpBinding binding = null;
    
        SPSite pwaSite = new SPSite(pwaUid);
        string pwaUrl = pwaSite.Url;            
    
        if (pwaSite.Protocol.ToLower() == "https:")
        {
            // Create a binding for HTTPS.
            binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
        }
        else
        {
            // Create a binding for HTTP.
            binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
        }
    
        binding.Name = "basicHttpConf";
        binding.SendTimeout = TimeSpan.MaxValue;
        binding.MaxReceivedMessageSize = MAXSIZE;
        binding.ReaderQuotas.MaxNameTableCharCount = MAXSIZE;
        binding.MessageEncoding = WSMessageEncoding.Text;
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
    
        // The endpoint address is the ProjectServer.svc router for all public PSI calls.
        EndpointAddress address = new EndpointAddress(pwaUrl + svcRouter);
    
        lookupTableClient = new SvcLookupTable.LookupTableClient(binding, address);
        lookupTableClient.ChannelFactory.Credentials.Windows.AllowedImpersonationLevel
            = TokenImpersonationLevel.Impersonation;
        lookupTableClient.ChannelFactory.Credentials.Windows.AllowNtlm = true;
    }
    
  12. WriteLogEntries メソッドを作成します。次のコードでは、イベント ログ エントリの Information 型と Warning 型を作成し、イベントに関する情報を格納する logEntry 文字列を作成し、イベント ログ エントリを作成します。イベント ログ エントリは、複数行にわたることができます。

    コードでは、次に、ULS ログ メッセージを作成します。この情報は、1 行で指定する必要があります。イベントが取り消されると、LoggingService.LogError メソッドによって警告メッセージが ULS ログに書き込まれます。それ以外の場合、LoggingService.LogMessage は情報メッセージを書き込みます。

    // Write entries to the event log and to the ULS log.
    private void WriteLogEntries(bool canceled, int numTasks, string projectDept,
        string userName, string projectName)
    {
        EventLogEntryType entryType = EventLogEntryType.Information;
        string taskInfo = "\nThe number of tasks is valid.";
    
        // Create an event log entry.
        if (canceled)
        {
            entryType = EventLogEntryType.Warning;
            taskInfo = 
                "\nFor that department, the project cannot be created with more than 3 tasks.";
        }
    
        string logEntry = "User: " + userName;
        logEntry += "\nProject: " + projectName;
    
        projectDept = ((projectDept == string.Empty) ? "[none]" : projectDept);
        logEntry += "\nDepartment: " + projectDept;
        logEntry += "\nTasks: " + numTasks.ToString() + taskInfo;
    
        // Create an event log entry.
        eventLog. WriteEntry(logEntry, entryType, EVENT_ID);
    
        // Create a ULS log entry.
        logEntry = string.Format(
            "User: {0}; project: {1}; department: {2}; tasks: {3}. ",
            userName, projectName, projectDept, numTasks);
        logEntry += taskInfo;
    
        if (canceled)
        {
            LoggingService.LogError(LoggingService.PROJECT_WARNING, logEntry);
        }
        else
        {
            LoggingService.LogMessage(LoggingService.PROJECT_INFO, logEntry);
        }
    }
    
  13. 最後に、TestCreatingProject.dll アセンブリの、厳密な名前のキー ファイルを作成します。たとえば、Visual Studio で TestCreatingProject のプロパティ ウィンドウを開き、[署名] タブをクリックし、[アセンブリの署名] チェック ボックスをオンにします。CreatingProjectKey.snk など、厳密な名前のキー ファイルを作成します。

TestCreatingProject ソリューションをエラーなくコンパイルできたら、そのソリューションを Project Web App コンピューターに展開できます。

イベント ハンドラーの展開

イベント ハンドラー アセンブリは、2 種類の方法で展開できます。手順 2a. では、アセンブリを Project Web App コンピューターのグローバル アセンブリに登録する方法を示しています。管理者ログオンで Project Server コンピューターにアクセスする必要があります。アセンブリをグローバル アセンブリ キャッシュに登録すると、イベント ハンドラーのテスト、および後で行う運用サーバーへのイベント ハンドラーの登録で必要な公開キー トークンを取得できます。

手順 2b. では、アセンブリを [Program Files]\Microsoft Office Servers\14.0\Bin\ProjectServerEventHandlers ディレクトリに登録する方法を示しています。Project Server の運用コンピューター上のグローバル アセンブリ キャッシュに直接アクセスする必要はありません。

手順 2a. イベント ハンドラーをグローバル アセンブリ キャッシュに登録するには

  1. 管理者として [Visual Studio コマンド プロンプト] ウィンドウを実行し、ソリューション ディレクトリに変更し、次のコマンドを入力します。

    gacutil /i bin\debug\TestCreatingProject.dll
    
  2. アセンブリが登録されていることを確認します。エクスプローラーで [Windows]\assembly ディレクトリを開き (または、[スタート] メニューの [ファイル名を指定して実行] ダイアログ ボックスで「assembly」と入力)、下にスクロールして、図 1 のように、TestCreatingProject アセンブリが登録されていることを確認します。

    図 1. TestCreatingProject アセンブリがグローバル アセンブリ キャッシュに登録されている状態

    グローバル アセンブリ キャッシュ内の TestCreatingProject

  3. Project Server でイベント ハンドラーを登録するときに備えて、登録されているアセンブリの完全名をテキスト ファイルにコピーします。完全名には、テキスト名、カルチャ、バージョン、および公開キー トークンが含まれます。

    1. グローバル アセンブリ キャッシュ内の TestCreatingProject アセンブリを右クリックし、[プロパティ] をクリックします。

    2. [TestCreatingProject のプロパティ] ダイアログ ボックスで、名前を選択し、コピーし、その名前をメモ帳などのテキスト ファイルに貼り付けます。

    3. カルチャ、バージョン、および公開キー トークンをコピーし、テキスト ファイルにそれぞれ貼り付けます。アセンブリの完全名は、次のようになります。

      TestCreatingProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=92978aaaab03ff98
      
  4. Project Web App でイベント ハンドラーを登録するときに備えて、完全修飾されたクラス名をテキスト ファイルにコピーします。例の TestCreatingProject の完全修飾されたクラス名は、Microsoft.SDK.Project.Samples.TestCreatingProject.CheckProjectDepartment です。

手順 2b. XCopy 展開を使用してイベント ハンドラーを登録するには

  1. システム管理者は、Project Server コンピューター上の [Program Files]\Microsoft Office Servers\14.0\bin\ProjectServerEventHandlers ディレクトリへの完全なアクセス権を持つ、共有を作成する必要があります。たとえば、ディレクトリに対して EventHandlers という名前の共有を作成します。

    ProjectServerEventHandlers サブディレクトリ内のイベント ハンドラーが自動的に登録されます。

  2. 開発コンピューター上の [Visual Studio コマンド プロンプト] ウィンドウで、イベント ハンドラー アセンブリが格納されているディレクトリに変更し、次のコマンドを入力します (パスに空白が含まれる場合は、目的のディレクトリを二重引用符で囲みます)。

    xcopy /y TestCreatingProject.dll \\ServerName\EventHandlers
    

    イベント ハンドラー アセンブリが、Project Server コンピューターの [Program Files]\Microsoft Office Servers\14.0\bin\ProjectServerEventHandlers ディレクトリにコピーされます。

テスト中は、アセンブリの登録解除と登録を何度も行う必要がある可能性があります。TestCreatingProject ソリューションでは、Utilities サブディレクトリ内の InstallEventHandler.bat ファイルに、次のスクリプトが含まれています。バッチ ファイルを管理者として実行します。

echo off

@SET EVENT_HANDLERS="C:\Program Files\Microsoft Office Servers\14.0\Bin\ProjectServerEventHandlers"

REM To deploy to a production server, copy the event handler to the ProjectServerEventHandlers subdirectory.
REM xcopy /y ..\bin\debug\TestCreatingProject.dll %EVENT_HANDLERS%
REM xcopy /y ..\bin\debug\TestCreatingProject.pdb %EVENT_HANDLERS%

REM To debug the event handler, register it in the global assembly cache.
gacutil /u TestCreatingProject
gacutil /i ..\bin\debug\TestCreatingProject.dll

手順 2b. で InstallEventHandler.bat ファイルを使用するには、gacutil.exe ステートメントをコメント アウトし、xcopy ステートメントのコメント化を解除します。

イベント ハンドラーの関連付けの登録

イベント ハンドラー アセンブリを Project Server コンピューターに展開したら、イベント ハンドラーを使用する前に、イベント ハンドラー アセンブリと Project Server 内のイベントを関連付ける必要があります。手順 3. は、Project Web App を使用して TestCreatingProject イベント ハンドラーを登録する方法を示しています。PSI の Events Service を使用することによって、イベント ハンドラーの関連付けを登録するアプリケーションを作成することもできます。

ヒント

イベント ハンドラーの関連付けを追加および削除するサンプル アプリケーションについては、CodePlex の「Project Server 2007 Event Handler Admin Tool (英語)」を参照してください。ツールは Office Project Server 2007 用に設計されていますが、Project Server 2010 でも動作します。

手順 3. Project Web App でイベント ハンドラーの関連付けを登録するには

  1. Project Web App で、サイド リンク バーの [サーバー設定] をクリックします。

  2. [サーバー設定] ページの [運用セクション] セクションで、[サーバー側のイベント ハンドラー] をクリックします。

  3. [サーバー側のイベント ハンドラー] ページで、[イベント] ボックスの一覧を下にスクロールして Creating イベントの Project リンクをクリックし、[新しいイベント ハンドラー] をクリックします (図 2)。

    図 2. Project Creating イベント ハンドラーの追加

    プロジェクトの作成イベント ハンドラーの登録

  4. [新しいイベント ハンドラー] ページ (図 3) で、フィールドに次の値を入力します。

    1. 名前:  イベント ハンドラーのフレンドリ名。

    2. 説明:  イベント ハンドラーの説明 (オプション)。

    3. アセンブリ名:  手順 2a. で準備したテキスト ファイル内のアセンブリの完全名。たとえば、次のように入力します。

      TestCreatingProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=92978aaaab03ff98
      
    4. クラス名:  イベント ハンドラーを実装するアセンブリ内のクラスの完全修飾名。たとえば、「Microsoft.SDK.Project.Samples.TestCreatingProject.CheckProjectDepartment」と入力します。

    5. 順序  1 つのイベントに複数のイベント ハンドラーが関連付けられる場合、この値によってイベント ハンドラーが呼び出される順序が決まります。1 ~ 999 の値を指定できます。

    図 3. イベント ハンドラーの構成

    Project Web アプリケーションでの新しいイベント ハンドラーの構成

  5. [保存] をクリックします。

    注意

    イベントの登録は非同期であり、Project Server サービス アプリケーションと Microsoft SharePoint Foundation タイマー プロセスが使用されます。タイマーの周期性が 1 分の場合は、Project Server にイベント ハンドラーを登録するのに 2 分かかります。

  6. イベントが追加されたことを確認します。[イベント] ボックスの一覧で、Creating イベントの Project リンクを再びクリックします。登録が完了していれば、[イベント ハンドラー] ボックスの一覧にイベント ハンドラーが表示されます。

TestCreatingProject ソリューションの Utilities サブディレクトリの EventHandlerRegistration.txt ファイルには、手順 3. で使用する次の情報が格納されています。

Add the following to the Edit Event Handler page in Project Web App,
for the Project Creating event.

Name: 
Project Creating Event Handler

Description: 
Test the OnCreating event handler for department requirements

Assembly Name (check the correct attributes after registering the event handler in the GAC): 
TestCreatingProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=92978aaaab03ff98

Class Name:
Microsoft.SDK.Project.Samples.TestCreatingProject.CheckProjectDepartment

Order:
1

注意

イベント ハンドラー コードを変更し、再コンパイルするたびに、イベント ハンドラーを再登録し (手順 2a. または手順 2b. を使用)、Project Web App リスト内のイベント ハンドラーを削除し、更新したイベント ハンドラーを手順 3. を使用して再び追加する必要があります。

イベント ハンドラーのテスト: イベント ビューアーと ULS ログの使用

TestCreatingProject イベント ハンドラーは、アプリケーションが QueueCreateProject メソッドを呼び出すたびに、イベント ログと ULS ログにメッセージを書き込みます。テストの例として、プロジェクトの部署の名前が Test Dept 2 で、4 つ以上のタスクが含まれる場合、イベントは取り消され、プロジェクトは作成されないものとします。

注意

プロジェクトを作成するために、Project Professional 2010 は、PSI のプライベート WinProj サービスのメソッドを呼び出します。QueueCreateProject は呼び出されないため、Project Professional 2010 が Project Creating イベントを呼び出すことはありません。イベント ハンドラーをテストするには、ProjTool.exe などのカスタム アプリケーションや、QueueCreateProject の CreateProject4Department サンプルを使用できます。ProjTool については、「Project Server 2010 での ProjTool テスト アプリケーションの使用」を参照してください。

手順 4. イベント ハンドラーをテストするには

  1. SharePoint アプリケーションが ULS トレース ログ エントリを記録できるようにします。

    1. SharePoint 2010 の全体管理アプリケーションを開き、[監視] をクリックし、[監視] ページの [タイマー ジョブ] セクションの [ジョブ定義の確認] をクリックします。

    2. [診断データ プロバイダー: トレース ログ] をクリックし、[タイマー ジョブの編集] ページで、タイマー ジョブが 10 分ごとに実行するように設定します。[OK] をクリックします。図 4 は、トレース ログのスケジュールの種類が [分単位] であることを示しています。

      図 4. ULS トレース ログの設定

      ULS トレースログの設定

  2. ULS ログの表示と監視、イベントのフィルター処理、および ULS ログ サンプルの保存を行うには、MSDN Code Gallery から ULS ビューアー (英語)をダウンロードします。または、既定の [Program Files]\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS\ ディレクトリ内の現在の ULS ログをメモ帳で表示したり、現在のログを別のディレクトリにコピーして、Microsoft Excel で表示することもできます。

    注意

    ULS ビューアーは、サポートされているアプリケーションではありません。

    1. [ULS ビューアー] アプリケーション ウィンドウで、ULS ログをリアル タイムで監視するには、Ctrl + U を押します。

    2. TestCreatingProject イベント ハンドラーと Project Server Queue Service のイベントのみを表示するには、イベント ID が 5050 に等しいか、カテゴリ が Queue に等しいフィルターを追加します。フィルターは保存して、将来のセッションで読み込むことができます。

  3. ProjTool では、プロジェクトを作成するときに部署の値を直接追加しないため、Project 2010 SDK ダウンロード内の CreateProject4Department サンプルを使用できます。または、ProjTool を変更するか、独自のアプリケーションを使用して、指定の部署が含まれるプロジェクトを作成することもできます。この手順の以降の部分では、CreateProject4Department.exe を使用します。

    1. Project Web App の [エンタープライズ ユーザー設定フィールドと参照テーブル] ページで、[部署] 参照テーブルを編集して、Test Dept 2 (または、TestCreatingProject コード内の PROJECT_DEPARTMENT2CHECK 定数に対応するテキスト値) を含めます。

    2. Microsoft SQL Server Management Studio で、次のクエリを使用して、LT_VALUE_TEXT フィールドが Test Dept 2 である参照テーブル エントリの LT_STRUCT_UID 値を見つけます。

      SELECT TOP 1000 [LT_UID]
            ,[LT_STRUCT_UID]
            ,[LT_VALUE_TEXT]
        FROM [ProjectServer_Published].[dbo].[MSP_LOOKUP_TABLE_VALUES]
      
    3. LT_STRUCT_UID 値を CreateProject4Department コードの DEPARTMENT_TEST 定数値にコピーし、CreateProject4Department アプリケーションをコンパイルします。

  4. ULS ビューアーを使用している場合は、これが実行されていて、現在のトレース エントリを収集していることを確認します。[コマンド プロンプト] ウィンドウで、CreateProject4Department.exe を少なくとも 2 回実行します。1 回は、3 つ以下のタスクを含むプロジェクトを作成し、もう 1 回は、4 つ以上のタスクを含むプロジェクトを作成します。次のコマンド内の name パラメーター値は、図 5 および図 6 内のプロジェクト名に対応しています。

    CreateProject4Department -name "Test Proj4Dept 10" -tasks 3 
    CreateProject4Department -name "Test Proj4Dept 11" -tasks 4
    
  5. [イベント ビューアー] ウィンドウを開き、[Windows ログ] ノードを展開し、[アプリケーション] ログをクリックします。[Project Event Handler] ソース (図 5) は、プロジェクトに 3 つのタスクが含まれる場合は、情報レベルのイベントを示します。プロジェクトは作成されます。

    図 5. イベント ビューアーの使用

    イベント ビューアーの使用

    選択されているイベントの上の警告レベルのイベントは、4 つのタスクの場合の [Project Event Handler] エントリを示しています。エラー レベルのイベントは、QueueCreateProject メソッドがプロジェクトを作成できなかったときに Project Server Queue がブロックされたことを示しています。

  6. [ULS ビューアー] ウィンドウ (図 6) で、手順 2. に記載されているようにフィルターを設定し、[Event Handler Warning] をクリックします。メッセージには、4 つのタスクを含むプロジェクトが作成されなかったことと、そのすぐ後に重大なキュー イベントがあったことが示されます。

    図 6. ULS ビューアーとフィルターの使用

    ULS ビューアーの使用

Project Server キュー ジョブに関する情報は、イベント ログと ULS ログに加えて、Project Web App で見つけることができます。たとえば、サイド リンク バーの [個人用の設定] をクリックし、[自分のキュー ジョブ] をクリックします。図 7 は、OnCreating イベント ハンドラーがイベントを取り消したときに失敗したキュー ジョブの、エラーの詳細を示しています。[ULS ビューアー] 内の重大なキュー イベント メッセージには、[キュー ジョブのエラーの詳細] ダイアログ ボックス内の JobUID 値が含まれます。

図 7. キュー ジョブのエラーの詳細を示している Project Web App

キューのジョブにおけるエラーの詳細

注意

アクションが取り消されると、88 個のプリイベント ハンドラーの動作に多少の違いが生じます。アクションが取り消されたときは動作をテストして、状況に応じてユーザーに指示を与えます。通常、Project Professional 2010 では、キューに問題がある、プロジェクトが発行されないなど、エラー メッセージはステータス バーに表示されますが、CancelReason プロパティはエンド ユーザーに表示されません。Project Web App では、2011 年 6 月の Project Server 2010 の累積的な更新プログラムにより、プロジェクト詳細ページ (PDP) に取り消しの理由が表示されるようになりました。いくつかの取り消されたアクションも、Project Web App の [キュー ジョブのエラーの詳細] ダイアログ ボックスに表示されます。

いくつかの取り消されたアクションも、Project Web App の [キュー ジョブのエラーの詳細] ダイアログ ボックスに表示されます。たとえば、ProjectEventReceiver メソッドの場合、OnCreating イベント ハンドラーまたは OnUpdating イベント ハンドラー内のコードが CancelReason プロパティを設定すると、そのテキストがキュー情報にも表示されます (図 7)。しかし、OnDeleting イベント ハンドラーと OnSummaryPublished イベント ハンドラーは、キュー情報に CancelReason 値を表示しません。

イベント ハンドラーのデバッグ

登録されたイベント ハンドラーは Project Server コンピューター上で実行され、Project Server Eventing Service によって呼び出されます。イベント ハンドラーをデバッグするには、Visual Studio 2010 を使用し、デバッガーを Project Server Eventing プロセスにアタッチします。

ヒント

Project Server 2010 には、Eventing プロセスとして、親プロセスと子プロセスの 2 つがあります。親プロセスが子プロセスを生成し、子プロセスが停止した場合はこれを再起動します。親プロセスは、準備される新しい Project Web App サイトやプロジェクト サイト、または削除されるサイトも監視し、子プロセスに更新メッセージを送信します。

子 Eventing プロセスは、準備される各サイトのイベント レシーバーを作成し、ジョブの通常のポーリングとディスパッチを開始します。Eventing Service も Queueing Service も親/子モデルを使用するため、サービスごとに 2 つのプロセスが存在します。どちらが子プロセスであるかを調べることもできますが、両方の Eventing プロセスにデバッガーをアタッチする方が簡単です。

手順 5. イベント ハンドラーをデバッグするには

  1. 前の手順に記載されているように、イベント ハンドラーを登録し、テストします。

  2. リモート コンピューターからデバッグしている場合は、「Remote Debugging Setup」を参照してください。

  3. Visual Studio で、登録したイベント ハンドラー プロジェクトを開き、[デバッグ] メニューの [プロセスにアタッチ] をクリックします。

  4. [プロセスにアタッチ] ダイアログ ボックス (図 8) で、[既定] トランスポートを選択し、[限定子] フィールドで Project Server コンピューター名を参照します。[選択] をクリックし、[コードの種類の選択] ダイアログ ボックスで、[次のコードの種類をデバッグする] オプションの [マネージ] を選択します。

    図 8. Eventing プロセスへのデバッガーのアタッチ

    イベント プロセスへのデバッガーのアタッチ

  5. [すべてのユーザーからのプロセスを表示する] チェック ボックスと [すべてのセッションのプロセスを表示する] チェック ボックスをオンにします。

  6. Visual Studio をデバッグ モードにするには、[選択可能なプロセス] ボックスの一覧で、両方の Microsoft.Office.Project.Server.Eventing.exe プロセスを選択し、[アタッチ] をクリックします。

  7. [ツール] メニューの [オプション] をクリックします。オプション リストの [デバッグ] ノードを展開し、[シンボル] をクリックします。フォルダー アイコンをクリックし、TestCreatingProject プロジェクトのデバッグ ビルドのディレクトリ パスを、新しいシンボル ファイルの場所に貼り付けます。[すべてのシンボルを読み込み] をクリックして TestCreatingProject.pdb シンボル ファイルを読み込み、[OK] をクリックします。

  8. TestCreatingProject.cs ファイルのコード ウィンドウで、PSSchema.ProjectDataSet projDs = e.ProjectDataSet; ステートメントか、デバッグを開始する任意の場所にブレークポイントを設定します。

    ブレークポイントが赤色のアウトラインと黄色の警告シンボルでのみ表示される場合、TestCreatingProject.pdb シンボル ファイルが読み込まれていないか、Project Server によるイベント ハンドラーの登録が完了していません。Project Web App におけるイベント ハンドラーの登録設定が正しいことを確認してから、手順 9. を実行して、イベント プロセスの処理を開始します。

  9. CreateProject4Department アプリケーションを実行し、Visual Studio で OnCreating イベント ハンドラーを 1 行ずつ実行することによって、Creating イベントを発生させます。

  10. イベント ハンドラーを Project Server に登録した後、コードを変更し、再コンパイルすると、デバッグは動作しません。再コンパイルする場合は、次のように、再コンパイルしたイベント ハンドラーを再登録する必要があります。

    1. Project Web App でイベント ハンドラーを削除します。

    2. 古いイベント ハンドラー アセンブリをグローバル アセンブリ キャッシュから削除します。

    3. 再コンパイルしたイベント ハンドラーをグローバル アセンブリ キャッシュに登録します。

    4. イベント ハンドラーを Project Web App に再登録します。

堅牢なプログラミング

注意

この記事のコード例には、WCF System.ServiceModel.FaultException や他の例外の try-catch ブロックは含まれていません。運用コードには例外処理を含める必要があり、例外は ULS トレース ログに書き込まれます。

FaultException のトラッピングの例については、QueueCreateProject の WCF の例を参照してください。Project 2010 SDK ダウンロード内の CreateProject4Department ソリューションにも、例外処理が実装されています。

例の中の ULS エラー メッセージ レベルは、LoggingService.LogError メソッドの TraceSeverity.Unexpected に設定されています。このレベルは、通常、try-catch ブロック内で発生する予期しない例外で使用されます。広範な TraceSeverity レベルの多くのメソッドを LoggingService クラスに作成する必要があります。たとえば、FaultException の場合は High レベルのメッセージを記録し、予期しない一般的な例外の場合は Unexpected メッセージを記録し、TestCreatingProject の例のように、イベントを取り消すが深刻な状態に陥るわけではないプリイベント ハンドラーの場合は Medium レベルのメッセージを記録します。

関連項目

タスク

[ウォークスルー] WCF を使用して PSI アプリケーションを開発する

参照

PSEventID

QueueCreateProject

概念

Project Server 2010 での ProjTool テスト アプリケーションの使用

その他のリソース

Project Server Events

プロジェクトのサーバー 2010 年委任監査イベント ハンドラー (英語)

Project Server 2007 Event Handler Admin Tool (英語)

ULS Viewer (英語)

ユーザー設定コードからトレース ログに書き込む

SharePoint 2010 のデバッグ機能とログ機能

Remote Debugging Setup