次の方法で共有


Statusing.SubmitStatusForResource メソッド

1 つまたは複数の変更承認を受けるのためには、プロジェクト管理者に、指定したリソースの割り当てを保存して送信します。リソースの偽装は必要ありません。

名前空間:  WebSvcStatusing
アセンブリ:  ProjectServerServices (ProjectServerServices.dll 内)

構文

'宣言
<SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/Statusing/SubmitStatusForResource", RequestNamespace := "https://schemas.microsoft.com/office/project/server/webservices/Statusing/",  _
    ResponseNamespace := "https://schemas.microsoft.com/office/project/server/webservices/Statusing/",  _
    Use := SoapBindingUse.Literal, ParameterStyle := SoapParameterStyle.Wrapped)> _
Public Sub SubmitStatusForResource ( _
    resid As Guid, _
    updateGuids As Guid(), _
    comment As String _
)
'使用
Dim instance As Statusing
Dim resid As Guid
Dim updateGuids As Guid()
Dim comment As String

instance.SubmitStatusForResource(resid, _
    updateGuids, comment)
[SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/Statusing/SubmitStatusForResource", RequestNamespace = "https://schemas.microsoft.com/office/project/server/webservices/Statusing/", 
    ResponseNamespace = "https://schemas.microsoft.com/office/project/server/webservices/Statusing/", 
    Use = SoapBindingUse.Literal, ParameterStyle = SoapParameterStyle.Wrapped)]
public void SubmitStatusForResource(
    Guid resid,
    Guid[] updateGuids,
    string comment
)

パラメーター

  • updateGuids
    型: []

    割り当ての Guid の配列。Null 値は、変更されたすべての割り当てを送信します。

注釈

プロジェクト サーバーのアクセス許可

権限

説明

StatusBrokerPermission

ユーザーを読み取り、リソースのための状態を更新できます。グローバル アクセス権。

**WCF と手動でスケジュールされたタスクの例:**UpdateStatus_ManualTasksの例は、テスト アプリケーションは、手動でスケジュールされたタスクまたは自動のタスクに対して、次を。

  • 解析、プロジェクト名、タスクの名前、数、作業時間、optionalassigned リソース、およびオプションのステータスは、コメントします。

  • リソースが指定されていない場合は、アプリケーションのユーザーは、タスクに割り当てられていると仮定します。

  • 指定したタスクに割り当てられているユーザーの GUID を取得します。

  • 取得し、割り当てのデータを検証します。1 つだけのリソースが割り当てられていると仮定します。

  • UpdateStatusメソッドは、 changeXml文字列を作成します。簡単なテストでは、変換は時間を % 完了 (最大 100) に報告されます。アプリケーション ユーザーが別のリソースを指定する場合、 changeXmlの文字列内のAssn要素にResID属性を追加します。

  • UpdateStatusを呼び出すし、 SubmitStatusForResource、1 つの割り当ての呼び出しです。

  • ReadStatusForResourceを取得、更新されたStatusingDataSetを呼び出します。

    アプリケーションは、データセットとchangeXmlの値は、XML ファイルは、テストで使用するためにも書き込みます。

UpdateStatusのテスト アプリケーションを使用するのには、次の手順で行います。

  1. テスト プロジェクトを作成、2 つの手動でスケジュールされたタスクの追加、設定、タスクの期間と開始日、およびリソースとして自分自身と他の 1 人のユーザーを追加します。他のユーザーに 1 つのタスクをし、他のタスクを割り当てます。

    たとえば、プロジェクトがテスト プロジェクトの名前 T1 と T2 では、タスクの名前し、し、各タスクの期間を 3 日に設定します。ユーザー名がユーザーの 1 と、他のユーザーが、ユーザー 2 と仮定します。T1 をユーザー 1 にユーザー 2 に T2 を割り当てるとします。

  2. WCF エンドポイントの構成は、app.config ファイルを作成します。Microsoft Visual Studio 2010プロジェクトでのコード サンプルを使用して、app.config ファイルを作成する方法については、 Project 2013 での WCF ベースのコード サンプルの前提条件を参照してください。

  3. さまざまなパラメーターを使用して、テストを実行します。パラメーターについて、次のコードは、 Usageメソッドを参照してください。たとえば、コマンド プロンプトウィンドウで、次のテストを実行します。

    • UpdateStatus -p "Test project" -t "T1" -hours 6 -c "This is a comment"

      出力を示しています。

      Updating status for User 1 on task 'T1': 6 hours
              Manually scheduled task
      
    • UpdateStatus -p "Test project" -t "T1" -hours 6 -r "User 2" -c "This is a comment"

      ユーザー 2 に割り当てられていないタスク T1、アプリケーションThe assignment on task 'T1' is for User 1, not for User 2を表示するようにします。

    • UpdateStatus -p "Test project" -t "T2" -hours 6 -r "User 2" -c "This is a comment"

      出力を示しています。

      Updating status for User 2 on task 'T2': 6 hours
              Manually scheduled task
      
  4. 各テストでは、後にProject Web Appのステータスの更新の承認センターを確認してください。

注意

追加すると、手動でスケジュールされたタスクの開始日、または期間がない、既定値は 8 時間の作業。まだタスクにリソースを割り当てるし、ステータスを更新できます。たとえば、T3 は、タスクの開始日や期間、いいえ、 UpdateStatusテスト アプリケーションを使用して、6 時間の作業時間の割り当てられたリソースを設定する場合は、Project Server T3 のプロジェクトの開始日に開始日を設定し、し実績作業時間を 6 時間に設定を追加します。同意した後、ステータスの更新、 Project Professional 2010で [ガント チャート] ビューには、実績作業時間] 列と、[残存作業時間] 列を追加できます。T3 の作業時間は 8 時間、実績作業時間は 6 時間、および残存作業時間、2 時間が。詳細ペインで、リソース配分状況] ビューまたは [タスク配分状況] ビューに[実績作業時間の行を追加する場合は、6 時間の実績作業時間も表示できます。

完全な Visual Studio のソリューションは、 Project 2010 SDK のダウンロードです。

using System;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Security.Principal;
using System.Xml;
using PSLibrary = Microsoft.Office.Project.Server.Library;

namespace Microsoft.SDK.Project.Samples.UpdateStatus
{
    class Program
    {
        private const string ENDPOINT_PROJECT = "basicHttp_Project";
        private const string ENDPOINT_RESOURCE = "basicHttp_Resource";
        private const string ENDPOINT_STATUSING = "basicHttp_Statusing";

        // Change the output directory for your computer.
        private const string OUTPUT_FILES = @"C:\Project\Samples\Output\";
        private const string XML_FILE1 = "UpdateStatus_jc_BasicProjectInfo.xml";
        private const string XML_FILE2 = "UpdateStatus_jc_FullProjectInfo.xml";
        private const string XML_FILE3 = "UpdateStatus_jc_ChangeXml.xml";
        private const string XML_FILE4 = "UpdateStatus_jc_NewStatus.xml";

        private static SvcProject.ProjectClient projectClient;
        private static SvcResource.ResourceClient resourceClient;
        private static SvcStatusing.StatusingClient statusingClient;

        private static string projectName = string.Empty;      // Project name.
        private static string taskName = string.Empty;         // Task name.
        private static string resName = string.Empty;          // Assigned resource name.
        private static string requestedResName = string.Empty; // Requested resource name.
        private static string appUserName = string.Empty;      // Application user name.
        private static DateTime minDate = DateTime.Today;      // Minimum date for statusing data.
        private static DateTime maxDate = DateTime.Today;      // Maximum date for statusing data.
        private static decimal hoursWorked = 0.0M;             // Number of hours worked on the assignment.
        private static string comment = string.Empty;          // Comment for status submission.

        private static bool showUsage = false;
        private static StreamWriter writer;
 
        static void Main(string[] args)
        {
            string outFilePath1 = OUTPUT_FILES + XML_FILE1;
            string outFilePath2 = OUTPUT_FILES + XML_FILE2;
            string outFilePath3 = OUTPUT_FILES + XML_FILE3;
            string outFilePath4 = OUTPUT_FILES + XML_FILE4;

            writer = new StreamWriter(outFilePath3);

            Guid projUid = Guid.Empty;          // GUID of the project.
            Guid taskUid = Guid.Empty;          // GUID of the task.
            Guid assnUid = Guid.Empty;          // GUID of the assignment.
            Guid resUid = Guid.Empty;           // GUID of the assigned resource.
            Guid requestedResUid = Guid.Empty;  // GUID of the requested resource, for submitting status.
            Guid myUid = Guid.Empty;            // GUID of the application user.
            double regularWork = 0;             // Assignment working time at the regular rate, 
                                                // in thousandths of minutes.
            bool isTaskManual = false;          // Specifies whether the task is manually scheduled.

            if (!ParseCommandLine(args)) 
            {
                Usage();
                ExitApp();
            }

            try
            {
                ConfigClientEndpoints(ENDPOINT_PROJECT);
                ConfigClientEndpoints(ENDPOINT_RESOURCE);
                ConfigClientEndpoints(ENDPOINT_STATUSING);

                WindowsIdentity winId = WindowsIdentity.GetCurrent();
                appUserName = winId.Name;

                myUid = resourceClient.GetCurrentUserUid();
                Console.WriteLine("User: {0}; PWA GUID: {1}", appUserName, myUid.ToString());

                // Get the basic information for the project.
                SvcProject.ProjectDataSet projectDs = projectClient.ReadProjectStatus(
                    Guid.Empty, SvcProject.DataStoreEnum.PublishedStore, projectName,
                    (int)PSLibrary.Project.ProjectType.Project);

                Console.WriteLine("XML output for ReadProjectStatus:\n\t{0}",
                    outFilePath1);
                projectDs.WriteXml(outFilePath1);

                projUid = projectDs.Project[0].PROJ_UID;

                if (projUid == Guid.Empty)
                    throw (new ArgumentException(
                        string.Format("\nThe project '{0}' does not exist.", projectName)));

                // Get the full information for the project.
                projectDs = projectClient.ReadProject(projUid,
                    SvcProject.DataStoreEnum.PublishedStore);
                Console.WriteLine("XML output for ReadProject:\n\t{0}", outFilePath2);
                projectDs.WriteXml(outFilePath2);

                bool isCurrentUser;  // Specifies whether the assignment is for the current user.

                // Get requested resource GUID. Exit if the requested resource is not a project resource.
                if (string.IsNullOrEmpty(requestedResName))
                {
                    // The current user is the requested resource.
                    isCurrentUser = true;

                    // Use a Linq query over the typed ProjectDataSet to check whether 
                    // the app user is a resource on the project.
                    var query = from r in projectDs.ProjectResource
                                where r.RES_UID == myUid
                                select new { r.RES_NAME };

                    foreach (var resRow in query)
                    {
                        requestedResName = resRow.RES_NAME;
                        requestedResUid = myUid;
                    }
                }
                else
                {
                    isCurrentUser = false;

                    var query = from r in projectDs.ProjectResource
                                where r.RES_NAME == requestedResName
                                select new { r.RES_UID };

                    foreach (var resRow in query)
                    {
                        requestedResUid = resRow.RES_UID;
                    }
                }

                if (requestedResUid == Guid.Empty)
                {
                    if (string.IsNullOrEmpty(requestedResName)) 
                        requestedResName = appUserName;

                    throw (new ArgumentException(
                        string.Format("\nThe resource '{0}' is not on the project '{1}'",
                                      requestedResName, projectName)));
                }

                // Get the assignment data for the task.
                for (int i = 0; i < projectDs.Assignment.Count; i++)
                {
                    if (projectDs.Assignment[i].TASK_NAME == taskName)
                    {
                        taskUid = projectDs.Assignment[i].TASK_UID;
                        assnUid = projectDs.Assignment[i].ASSN_UID;
                        resUid = projectDs.Assignment[i].RES_UID;
                        regularWork = projectDs.Assignment[i].ASSN_WORK;
                        minDate = projectDs.Assignment[i].ASSN_START_DATE;
                        maxDate = projectDs.Assignment[i].ASSN_FINISH_DATE;

                        // Get the assigned resource name.
                        for (int j = 0; j < projectDs.ProjectResource.Count; j++)
                        {
                            if (projectDs.ProjectResource[j].RES_UID == resUid)
                            {
                                resName = projectDs.ProjectResource[j].RES_NAME;
                                break;
                            }
                        }

                        // Is the task manually scheduled?
                        for (int t = 0; t < projectDs.Task.Count; t++)
                        {
                            if (projectDs.Task[t].TASK_UID == taskUid)
                            {
                                isTaskManual = projectDs.Task[t].TASK_IS_MANUAL;
                                break;
                            }
                        }
                        break;
                    }
                }
                ValidateAssignment(isCurrentUser, resUid, myUid, assnUid, requestedResUid);

                string changeXml = CreateChangeXml(projUid, assnUid, resUid, 
                                                   hoursWorked, regularWork, isCurrentUser);

                Console.WriteLine("XML output for ChangeXml:\n\t{0}", outFilePath3);
                writer.WriteLine(changeXml);

                Console.ForegroundColor = ConsoleColor.Yellow;
                string yellowString = "\nUpdating status for {0} on task '{1}': {2} hours\n\t";
                yellowString += (isTaskManual) ? "Manually scheduled task" : "Auto-scheduled task";
                Console.WriteLine(yellowString, resName, taskName, hoursWorked);
                Console.ResetColor();

                statusingClient.UpdateStatus(changeXml);

                Guid[] assignments = { assnUid };
                statusingClient.SubmitStatusForResource(resUid, assignments, comment); 

                SvcStatusing.StatusingDataSet statusingDs =
                    statusingClient.ReadStatusForResource(resUid, assnUid, minDate, maxDate);

                Console.WriteLine("\nXML output for ReadStatusForResource:\n\t{0}", outFilePath4);
                statusingDs.WriteXml(outFilePath4);
            }
            catch (FaultException fault)
            {
                // Use the WCF FaultException, because the ASMX SoapException does not 
                // exist in a WCF-based application.
                Console.ForegroundColor = ConsoleColor.Red;
                WriteFaultOutput(fault);
                Console.WriteLine();
                showUsage = true;
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex.Message);
                Console.WriteLine();
                showUsage = true;
            }
            finally
            {
                writer.Close();
                Console.ResetColor();
                if (showUsage) Usage();
                ExitApp();
            }
        }

        // Validate the assignment and the resource.
        private static void ValidateAssignment(bool isCurrentUser, Guid resUid, Guid myUid,
                                               Guid assnUid, Guid requestedResUid)
        {
            if (!isCurrentUser && resUid == myUid)
                throw (new ArgumentException(
                    string.Format("\nThe assignment on task '{0}' is for {1}, not for {2}",
                                  taskName, resName, requestedResName)));

            if (assnUid == Guid.Empty)
                throw (new ArgumentException(
                    string.Format("\nNo assignment for {0} on task '{0}'", resName, taskName)));

            if (requestedResUid != resUid)
                throw (new ArgumentException(
                    string.Format("\nResource '{0}' does not match assignment on task '{1}'",
                                  requestedResName, taskName)));
        }

        /// <summary>Create a ChangeXml string for the UpdateStatus method.</summary>
        /// <param name="projUid">Project GUID</param>
        /// <param name="assnUid">Assignment GUID</param>
        /// <param name="resUid">Resource GUID</param>
        /// <param name="hoursWorked">Number of hours worked.</param>
        /// <param name="totalRegHours">
        /// Total assigned hours at the regular rate, in thousandths of minutes.</param>
        /// <param name="isCurrentUser">True if the assignment is for the current user.</param>
        /// <returns></returns>
        private static string CreateChangeXml(Guid projUid, Guid assnUid, Guid resUid,  
            decimal hoursWorked, double totalRegHours, bool isCurrentUser)
        {
            StringBuilder cXmlBuilder = new StringBuilder("<Changes>");
            cXmlBuilder.AppendFormat("<Proj ID=\"{0}\">", projUid.ToString());
            cXmlBuilder.AppendFormat("<Assn ID=\"{0}\"", assnUid.ToString());

            // If the assignment is not for the current user, add the ResID attribute, 
            // and then close the Assn element.
            if (isCurrentUser)
                cXmlBuilder.Append(">");
            else
                cXmlBuilder.AppendFormat(" ResID=\"{0}\">", resUid.ToString());

            // Specify the process ID (PID) for percent work complete.
            // The "Supported Project Fields and Field Information for Statusing ChangeXML"  
            // SDK article shows the PID value is 251658274.
            string pidPctWorkComplete = PSLibrary.AssnConstID.s_apid_pct_wrk_complete.ToString(
                CultureInfo.InvariantCulture);

            // Calculate the percent work complete.
            int pctComplete = Convert.ToInt32(100 * hoursWorked / 
                              Convert.ToDecimal(totalRegHours / 1000 / 60));

            if (pctComplete > 100) pctComplete = 100;

            cXmlBuilder.AppendFormat("<Change PID=\"{0}\">{1}</Change>", pidPctWorkComplete,
                pctComplete.ToString());
            cXmlBuilder.Append("</Assn></Proj></Changes>");

            return cXmlBuilder.ToString();
        }

        // Extract a PSClientError object from the WCF FaultException object, and
        // then display the exception details and each error in the PSClientError stack.
        private static void WriteFaultOutput(FaultException fault)
        {
            string errAttributeName;
            string errAttribute;
            string errOut;
            string errMess = "".PadRight(30, '=') + "\r\n"
                + "Error details: " + "\r\n";

            PSLibrary.PSClientError error = Helpers.GetPSClientError(fault, out errOut);
            errMess += errOut;

            PSLibrary.PSErrorInfo[] errors = error.GetAllErrors();
            PSLibrary.PSErrorInfo thisError;

            for (int i = 0; i < errors.Length; i++)
            {
                thisError = errors[i];
                errMess += "\r\n".PadRight(30, '=') + "\r\nPSClientError output:\r\n";
                errMess += thisError.ErrId.ToString() + "\n";

                for (int j = 0; j < thisError.ErrorAttributes.Length; j++)
                {
                    errAttributeName = thisError.ErrorAttributeNames()[j];
                    errAttribute = thisError.ErrorAttributes[j];
                    errMess += "\r\n\t" + errAttributeName
                        + ": " + errAttribute;
                }
            }
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(errMess);
            Console.ResetColor();
        }

        // Use the endpoints defined in app.config to configure the client.
        public static void ConfigClientEndpoints(string endpt)
        {
            if (endpt == ENDPOINT_PROJECT)
                projectClient = new SvcProject.ProjectClient(endpt);
            else if (endpt == ENDPOINT_RESOURCE)
                resourceClient = new SvcResource.ResourceClient(endpt);
            else if (endpt == ENDPOINT_STATUSING)
                statusingClient = new SvcStatusing.StatusingClient(endpt);
        }

        // Parse the command line. Return true if there are no errors.
        private static bool ParseCommandLine(string[] args)
        {
            int i;
            bool error = false;
            int argsLength = args.Length;

            for (i = 0; i < argsLength; i++)
            {
                if (error) break;
                if (args[i].StartsWith("-") || args[i].StartsWith("/"))
                    args[i] = "*" + args[i].Substring(1).ToLower();

                switch (args[i])
                {
                    case "*projectname":
                    case "*p":
                        if (++i >= argsLength) return false;
                        projectName = args[i];
                        break;
                    case "*taskname":
                    case "*t":
                        if (++i >= argsLength) return false;
                        taskName = args[i];
                        break;
                    case "*resourcename":
                    case "*r":
                        if (++i >= argsLength) return false;
                        requestedResName = args[i];
                        break;
                    case "*hours":
                    case "*h":
                        if (++i >= argsLength) return false;
                        hoursWorked = Convert.ToDecimal(args[i]);
                        break;
                    case "*comment":
                    case "*c":
                        if (++i >= argsLength) return false;
                        comment = args[i];
                        break;
                    case "*?":
                    default:
                        error = true;
                        break;
                }
            }
            return !error;
        }

        private static void Usage()
        {
            string example = "Usage: UpdateStatus -p \"Project Name\" -t \"Task name\"  -h 3"
                + "\r\n\t\t[-r \"Resource Name\"] [-d 6/29/2011] [-c \"This is a comment\"]";
            Console.WriteLine(example);
            Console.WriteLine("  -projectName | -p:  Name of the project.");
            Console.WriteLine("  -taskName | -t:  Name of the assigned task.");
            Console.WriteLine("  -hours | -h:  Number of hours worked.");
            Console.WriteLine("  -resourceName | -r:  Resource name. Default is the current user.");
            Console.WriteLine("  -date | -d:  Date of the work. Default is non-timephased.");
            Console.WriteLine("  -comment | -c:  Comment for submitted status.");
        }

        private static void ExitApp()
        {
            Console.Write("\nPress any key to exit... ");
            Console.ReadKey(true);
            Environment.Exit(0);
        }
    }

    // Helper method: GetPSClientError.
    class Helpers
    {
        /// <summary>
        /// Extract a PSClientError object from the ServiceModel.FaultException,
        /// for use in output of the GetPSClientError stack of errors.
        /// </summary>
        /// <param name="e"></param>
        /// <param name="errOut">Shows that FaultException has more information 
        /// about the errors than PSClientError has. FaultException can also contain 
        /// other types of errors, such as failure to connect to the server.</param>
        /// <returns>PSClientError object, for enumerating errors.</returns>
        public static PSLibrary.PSClientError GetPSClientError(FaultException e, 
                                                               out string errOut)
        {
            const string PREFIX = "GetPSClientError() returns null: ";
            errOut = string.Empty;
            PSLibrary.PSClientError psClientError = null;

            if (e == null)
            {
                errOut = PREFIX + "Null parameter (FaultException e) passed in.";
                psClientError = null;
            }
            else
            {
                // Get a ServiceModel.MessageFault object.
                var messageFault = e.CreateMessageFault();

                if (messageFault.HasDetail)
                {
                    using (var xmlReader = messageFault.GetReaderAtDetailContents())
                    {
                        var xml = new XmlDocument();
                        xml.Load(xmlReader);

                        var serverExecutionFault = xml["ServerExecutionFault"];
                        if (serverExecutionFault != null)
                        {
                            var exceptionDetails = serverExecutionFault["ExceptionDetails"];
                            if (exceptionDetails != null)
                            {
                                try
                                {
                                    errOut = exceptionDetails.InnerXml + "\r\n";
                                    psClientError = 
                                        new PSLibrary.PSClientError(exceptionDetails.InnerXml);
                                }
                                catch (InvalidOperationException ex)
                                {
                                    errOut = PREFIX + "Unable to convert fault exception info ";
                                    errOut += "a valid Project Server error message. Message: \n\t";
                                    errOut += ex.Message;
                                    psClientError = null;
                                }
                            }
                            else
                            {
                                errOut = PREFIX 
                                    + "The FaultException e is a ServerExecutionFault, "
                                    + "but does not have ExceptionDetails.";
                            }
                        }
                        else
                        {
                            errOut = PREFIX 
                                + "The FaultException e is not a ServerExecutionFault.";
                        }
                    }
                }
                else // No detail in the MessageFault.
                {
                    errOut = PREFIX + "The FaultException e does not have any detail.";
                }
            }
            errOut += "\r\n" + e.ToString() + "\r\n";
            return psClientError;
        }
    }
}

関連項目

参照先

Statusing クラス

Statusing メンバー

WebSvcStatusing 名前空間

ReadStatusForResource

UpdateStatus