Partager via


Statusing.SubmitStatusForResource - Méthode

Envoie une ou plusieurs modifiée et enregistrée des affectations de la ressource spécifiée au responsable de projet pour approbation. Ne nécessite pas l'emprunt d'identité de la ressource.

Espace de noms :  WebSvcStatusing
Assembly :  ProjectServerServices (dans ProjectServerServices.dll)

Syntaxe

'Déclaration
<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 _
)
'Utilisation
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
)

Paramètres

  • updateGuids
    Type : []

    Tableau de GUID d'affectation. Une valeur null envoie toutes les modifications d'affectations.

  • comment
    Type : System.String

    Commentaire pour la notification.

Remarques

Autorisations Project Server

Autorisation

Description

StatusBrokerPermission

Permet à un utilisateur de lire et mettre à jour de statut au nom d'une ressource. Autorisation globale.

Exemples

Exemple pour WCF et les tâches planifiées manuellement :   L'exemple de UpdateStatus_ManualTasks est une application de test qui effectue les tâches suivantes pour une tâche planifiée manuellement ou à une tâche planifiées automatiquement :

  • Analyse le nom du projet, le nom de la tâche, le nombre d'heures travaillées, la ressource optionalassigned et un état facultatif comment.

  • Si aucune ressource n'est spécifié, suppose que l'utilisateur de l'application est affectée à la tâche.

  • Obtient le GUID de l'utilisateur affecté à la tâche spécifiée.

  • Obtient et valide les données d'affectation. Suppose qu'une ressource est affectée.

  • Crée la chaîne changeXml pour la méthode UpdateStatus . Pour un test simple, convertit signalé heures complètes pourcentage (100 maximum). Si l'utilisateur de l'application spécifie une ressource différente, ajoute l'attribut ResID à l'élément Assn dans la chaîne changeXml .

  • Appelle UpdateStatuset appelle ensuite SubmitStatusForResource, pour l'affectation unique.

  • Appelle ReadStatusForResource pour obtenir une mise à jour StatusingDataSet.

    L'application écrit également les jeux de données et la valeur changeXml pour les fichiers XML, à utiliser pour tester.

Pour utiliser l'application de test UpdateStatus , procédez comme suit :

  1. Créer un projet de test, ajouter deux tâches planifiées manuellement, définissez la durée de la tâche et la date de début et puis ajoutez vous-même et un autre utilisateur en tant que ressources. Affecter une tâche à vous et les autres tâches à l'autre utilisateur.

    Par exemple, nommez le projet Test project, nommer les tâches T1 et T2, puis définissez la durée de chaque tâche pour trois jours. Supposons que votre nom d'utilisateur est l'utilisateur 1 et l'autre utilisateur est l'utilisateur 2. Affecter des T1 à l'utilisateur 1 et affecter T2 à l'utilisateur 2.

  2. For configuration of the WCF endpoints, create an app.config file. For information about using the code sample in a Microsoft Visual Studio 2010 project and creating an app.config file, see Prerequisites for WCF-Based Code Samples.

  3. Exécutez les tests, à l'aide de divers paramètres. Voir la méthode Usage dans le code suivant pour des informations sur les paramètres. Par exemple, exécutez les tests suivants dans une fenêtre d'invite de commandes:

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

      La sortie indique :

      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"

      L'utilisateur 2 n'est pas affecté à la tâche T1, afin que l'application affiche 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"

      La sortie indique :

      Updating status for User 2 on task 'T2': 6 hours
              Manually scheduled task
      
  4. Après chaque test, consultez le Centre d'approbation dans Project Web App les mises à jour de l'état.

Notes

Lorsque vous ajoutez une tâche planifiée manuellement qui n'est pas une date de début ou la durée, la valeur par défaut est de 8 heures de travail. Vous pouvez affecter une ressource à la tâche et mettre à jour le statut. Par exemple, si une tâche a T3 aucune début date ou la durée et l'application de test UpdateStatus vous permet de définir les six heures de travail pour la ressource affectée, Project Server définit la date de début pour T3 à la date de début du projet, puis ajoute six heures de travail réel. Après l'acceptation de la mise à jour d'état, vous pouvez ajouter la colonne Travail réel et le Travail restant à l'affichage Diagramme de Gantt dans Project Professionnel 2010. Le travail pour T3 est de huit heures, travail réel est six heures et travail restant est de deux heures. Si vous ajoutez la ligne de Travail réel dans le volet de Détails dans l'affichage Utilisation des ressources ou l'affichage Utilisation des tâches, vous pouvez également consulter les six heures de travail réel.

La solution Visual Studio complète est dans la Project 2010 téléchargement 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;
        }
    }
}

Voir aussi

Référence

Statusing classe

Statusing - Membres

WebSvcStatusing - Espace de noms

ReadStatusForResource

UpdateStatus