Поделиться через


Метод ResourcePlan.QueuePublishResourcePlan

Публикация планов ресурсов для указанного проекта в базу данных опубликованных проектов. Использует службу очередей Project Server.

Пространство имен:  WebSvcResourcePlan
Сборка:  ProjectServerServices (в ProjectServerServices.dll)

Синтаксис

'Декларация
<SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/ResourcePlan/QueuePublishResourcePlan", RequestNamespace := "https://schemas.microsoft.com/office/project/server/webservices/ResourcePlan/",  _
    ResponseNamespace := "https://schemas.microsoft.com/office/project/server/webservices/ResourcePlan/",  _
    Use := SoapBindingUse.Literal, ParameterStyle := SoapParameterStyle.Wrapped)> _
Public Sub QueuePublishResourcePlan ( _
    projectUid As Guid, _
    jobUid As Guid _
)
'Применение
Dim instance As ResourcePlan
Dim projectUid As Guid
Dim jobUid As Guid

instance.QueuePublishResourcePlan(projectUid, _
    jobUid)
[SoapDocumentMethodAttribute("https://schemas.microsoft.com/office/project/server/webservices/ResourcePlan/QueuePublishResourcePlan", RequestNamespace = "https://schemas.microsoft.com/office/project/server/webservices/ResourcePlan/", 
    ResponseNamespace = "https://schemas.microsoft.com/office/project/server/webservices/ResourcePlan/", 
    Use = SoapBindingUse.Literal, ParameterStyle = SoapParameterStyle.Wrapped)]
public void QueuePublishResourcePlan(
    Guid projectUid,
    Guid jobUid
)

Параметры

  • projectUid
    Тип: System.Guid

    Содержит идентификатор GUID проекта.

  • jobUid
    Тип: System.Guid

    Содержит идентификатор GUID задания очереди.

Примеры

В примере используется пространство имен SvcResourcePlan в сборке ProjectServerServices.dll прокси-сервера. Методы SetResPlanClientEndPoints, SetQueueClientEndPoints, SetProjectClientEndPointsи SetResourceClientEndPoints использовать файл app.config для настройки привязки, поведение и конечной точки WCF. Сведения о создании Необходимые условия для примеров кода на основе WCF в Project 2013просматривать сборкой PSI прокси-сервера и файл app.config.

Примечание

В следующем примере показано использование метода QueuePublishResourcePlan ; Это не полное решение.

Пример кода о создании плана ресурсов в разделе QueueCreateResourcePlan. После создания плана ресурсов метод GenerateResourcePlan вызывает метод QueuePublishResourePlan для публикации плана ресурсов. Используется шкала времени представляет собой месяцы и эквивалентами полной занятости повременной устанавливаются false.

Примечание

План ресурсов можно опубликовать только в том случае, если публикации связанного проекта.

Полный пример кода выглядит следующим образом.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ServiceModel;
using System.Data;
using System.Xml;
using PSLibrary = Microsoft.Office.Project.Server.Library;

namespace Microsoft.SDK.Project.Samples.ResourcePlan
{

    class TimephasedResourcePlan
    {

        private const string ENDPOINT_RESPLAN = "basicHttp_ResourcePlan";
        private const string ENDPOINT_Q = "basicHttp_QueueSystem";
        private const string ENDPOINT_R = "basicHttp_Resource";
        private const string ENDPOINT_P = "basicHttp_Project";
        private const string OUTPUT_FILES = @"C:\Project\Samples\Output\";
        private const string XML_FILE1 = "ResourcePlanDS.xml";
        private const string XML_FILE2 = "UpdatedResourcePlanDS.xml";

        private static SvcResourcePlan.ResourcePlanClient resourcePlanClient;
        private static SvcQueueSystem.QueueSystemClient queueSystemClient;
        private static SvcResource.ResourceClient resourceClient;
        private static SvcProject.ProjectClient projectClient;
        private static string outFile_ResourcePlanDS;
        private static string outFile_UpdatedResourcePlanDS;

        private static List<Guid> createdResources = new List<Guid>();
        private static List<Guid> createdProjects = new List<Guid>();
        private static PSLibrary.ResourcePlan.TimeScale timescale = 
            new PSLibrary.TimeScaleClass.TimeScale();
        private static int numResources = 2;    // Default number of resources to create.
        private static int numDays = 10;        // Default number of days for the plan.
        private static bool deletePlan = true;  // Delete the plan, project, and resources after creating them.

        static void Main(string[] args)
        {
            timescale = PSLibrary.TimeScaleClass.TimeScale.Months; // Default timescale.

            try
            {
                if (args.Length > 1 && args.Length < 9)
                {
                    if (args[0].ToLower() == "-delete")
                    {
                        deletePlan = Convert.ToBoolean(args[1]);
                    }
                    if (args.Length > 3)
                    {
                        if (args[2].ToLower() == "-timescale")
                            switch (args[3].ToLower())
                            {
                                case "days":
                                    timescale = PSLibrary.TimeScaleClass.TimeScale.Days;
                                    break;
                                case "quarters":
                                    timescale = PSLibrary.TimeScaleClass.TimeScale.Quarters;
                                    break;
                                case "weeks":
                                    timescale = PSLibrary.TimeScaleClass.TimeScale.Weeks;
                                    break;
                                case "years":
                                    timescale = PSLibrary.TimeScaleClass.TimeScale.Years;
                                    break;
                                default:
                                    timescale = PSLibrary.TimeScaleClass.TimeScale.Months;
                                    break;
                            }
                    }
                    if (args.Length > 5)
                    {
                        if (args[4].ToLower() == "-numresources")
                            numResources = Convert.ToInt32(args[5]);

                    }
                    if (args.Length > 7)
                    {
                        if (args[6].ToLower() == "-numdays")
                            numDays = Convert.ToInt32(args[7]);
                    }
                }

                // Configure the endpoints.
                bool configResult = false;
                configResult = ConfigClientEndpoints(ENDPOINT_RESPLAN);
                configResult = ConfigClientEndpoints(ENDPOINT_Q);
                configResult = ConfigClientEndpoints(ENDPOINT_P);
                configResult = ConfigClientEndpoints(ENDPOINT_R);

                if (!configResult) throw new ApplicationException();

                // If output directory does not exist, create it.
                if (!Directory.Exists(OUTPUT_FILES))
                {
                    Directory.CreateDirectory(OUTPUT_FILES);
                }

                // Set the output file path.
                outFile_ResourcePlanDS = OUTPUT_FILES + XML_FILE1;
                outFile_UpdatedResourcePlanDS = OUTPUT_FILES + XML_FILE2;

                try
                {
                    bool createAssignments = true;

                    GenerateResourcePlan(numResources, numDays, createAssignments);
                }
                catch (FaultException fault)
                {
                    // Use the WCF FaultException, because the ASMX SoapException does not 
                    // exist in a WCF-based application.
                    WriteFaultOutput(fault);
                }
                catch (CommunicationException e)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine(
                        "\n***System.ServiceModel.CommunicationException\n{0}:", e.Message);
                    Console.ResetColor();
                }
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("\n\n***Exception:\n{0}", ex.Message);
                Console.ResetColor();
            }
            Console.Write("\nPress any key to exit: ");
            Console.ReadKey(true);
        }

        // 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;

            if (error != null)
            {
                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();
        }

        /// <summary>
        /// Generate the resource plan.
        /// </summary>
        /// <param name="resourceCount">Number of resources.</param>
        /// <param name="lengthInDays">Length of the resource plan in days.</param>
        /// <param name="generateAssignmentValues">True to generate assignment values.</param>
        public static void GenerateResourcePlan(int resourceCount, 
            int lengthInDays, bool generateAssignmentValues)
        {
            // Create enterprise resources.
            Guid[] resGuids = GenerateResources(resourceCount);

            // Create a project.
            Guid projUid = GenerateProject();

            // Create a resource plan DataSet of the specified duration.
            int daysLeft = lengthInDays;
            DateTime endDate = DateTime.Now;

            while (daysLeft > 0)
            {
                endDate = endDate.AddDays(1);
                if (!(endDate.DayOfWeek == DayOfWeek.Saturday 
                    || endDate.DayOfWeek == DayOfWeek.Sunday))
                    --daysLeft;
            }

            // Read the resource plan.
            string resPlanFilter = string.Empty;
            bool fteTime = false;
            bool autoCheckOut = false;

            SvcResourcePlan.ResourcePlanDataSet rpds = 
                resourcePlanClient.ReadResourcePlan(resPlanFilter, projUid,
                DateTime.Now, endDate, (short)timescale, fteTime, autoCheckOut);

            // Add the resources to the resource plan DataSet.
            for (int i = 0; i < resGuids.Length; i++)
            {
                SvcResourcePlan.ResourcePlanDataSet.PlanResourcesRow newRes = 
                    rpds.PlanResources.NewPlanResourcesRow();

                newRes.RES_UID = resGuids[i];
                newRes.ASSN_BOOKING_TYPE = 
                    (byte)PSLibrary.Resource.BookingType.Proposed;
                newRes.PROJ_UID = projUid;
                rpds.PlanResources.AddPlanResourcesRow(newRes);
            }

            // Set the resource utilization date limit.
            SvcResourcePlan.ResourcePlanDataSet.UtilizationRow utilizationRow =
                rpds.Utilization.NewUtilizationRow();
            utilizationRow.RESPLAN_UTILIZATION_TYPE = 
                (int)PSLibrary.ResourcePlan.UtilizationType.FromResourcePlan;
            utilizationRow.RESPLAN_UTILIZATION_DATE = new DateTime(2031, 2, 20);
            utilizationRow.PROJ_UID = projUid;

            if (rpds.Utilization.Count == 0)
            {
                rpds.Utilization.AddUtilizationRow(utilizationRow);
            }

            // Set assignment values.
            if (generateAssignmentValues)
            {
                for (DateTime d = DateTime.Now; d <= endDate; d = d.AddDays(1))
                {
                    // Set the number of hours in each workday.
                    double workVal = (d.DayOfWeek == DayOfWeek.Saturday || 
                        d.DayOfWeek == DayOfWeek.Sunday) 
                        ? 0 
                        : 8;

                    string interval = GetIntervalNameByDate(d, rpds);

                    foreach (Guid res in resGuids)
                    {
                        SetWorkForResourceForInterval(interval, res,
                            projUid, workVal, rpds);
                    }
                }
            }

            // Create the resource plan.
            Guid jobGuid = Guid.NewGuid();
            int numJobs = 1;
            bool autoCheckIn = false;
            resourcePlanClient.QueueCreateResourcePlan(projUid, rpds,
                fteTime, autoCheckIn, jobGuid);

            Helpers.WaitForQueue(SvcQueueSystem.QueueMsgType.ResourcePlanSave,
                   numJobs, queueSystemClient, jobGuid);
            Console.WriteLine("Resource plan created successfully.");

            // Publish the resource plan.
            resourcePlanClient.QueuePublishResourcePlan(projUid, jobGuid);

            Helpers.WaitForQueue(SvcQueueSystem.QueueMsgType.ResourcePlanPublish,
                   numJobs, queueSystemClient, jobGuid);
            Console.WriteLine("Resource plan published.");

            // Read the resource plan.
            rpds = resourcePlanClient.ReadResourcePlan(resPlanFilter, projUid, DateTime.Now,
                endDate, (short)timescale, fteTime, autoCheckOut);

            // Write the ResourcePlan DataSet to an XML file.
            rpds.WriteXml(outFile_ResourcePlanDS);
            Console.WriteLine("\nSee XML output of resource plan DataSet at\n\t{0}",
                outFile_ResourcePlanDS);
            Console.Write("\nPress any key to continue: ");
            Console.ReadKey(true);
            
            // Change the booking type for a resource and update the resource plan.
            Guid updateJob = Guid.NewGuid();

            rpds.PlanResources[0].ASSN_BOOKING_TYPE = 
                (int)PSLibrary.Resource.BookingType.Committed;
            resourcePlanClient.QueueUpdateResourcePlan(projUid, rpds, 
                fteTime, autoCheckIn, updateJob);

            Helpers.WaitForQueue(SvcQueueSystem.QueueMsgType.ResourcePlanSave,
                  numJobs, queueSystemClient, jobGuid);
            Console.WriteLine("Resource plan updated successfully.");

            // Write the updated resource plan DataSet to an XML file.
            rpds.WriteXml(outFile_UpdatedResourcePlanDS);
            Console.WriteLine("\nSee XML output of the updated resource plan DataSet at \n\t{0}",
                outFile_UpdatedResourcePlanDS);

            if (deletePlan)
            {
                Console.WriteLine("\nPress any key to continue");
                Console.Write("...and delete the resource plan, project, and resources:");
                Console.ReadKey(true);
                DeleteResourcePlan(projUid, resGuids);
            }
        }

        // Delete the resource plan and the test project and resources.
        public static void DeleteResourcePlan(Guid projUid, Guid[] resUids)
        {
            // QueueDeleteResourcePlan takes an array of project GUIDs and job GUIDs.
            Guid deleteResPlanJob = Guid.NewGuid();
            Guid[] deleteJobs = new Guid[1] { deleteResPlanJob };
            Guid[] projects = new Guid[1] { projUid };

            resourcePlanClient.QueueDeleteResourcePlan(projects, deleteJobs);

            int numJobs = 1;
            Helpers.WaitForQueue(SvcQueueSystem.QueueMsgType.ResourcePlanDelete,
                                 numJobs, queueSystemClient, deleteResPlanJob);

            Guid projDeleteJob = Guid.NewGuid();
            bool deleteProjectSite = false;  // No project site was created during publish.
            bool deleteInPubAndDraftDb = true;
            projectClient.QueueDeleteProjects(projDeleteJob, deleteProjectSite, 
                                              projects, deleteInPubAndDraftDb);
            Helpers.WaitForQueue(SvcQueueSystem.QueueMsgType.ProjectDelete,
                                 numJobs, queueSystemClient, projDeleteJob);

            // Resources must be checked out before they can be deleted.
            resourceClient.CheckOutResources(resUids);
            string noComment = string.Empty;
            resourceClient.DeleteResources(resUids, noComment);

            Console.WriteLine("Resource plan, project, and resources deleted successfully.");             
        }

        // Create the specified number of enterprise resources.
        public static Guid[] GenerateResources(int numRes)
        {
            Console.WriteLine("Creating {0} resources:", numRes.ToString());
            Guid[] resUids = new Guid[numRes];
            SvcResource.ResourceDataSet rds = new SvcResource.ResourceDataSet();
            for (int i = 0; i < numRes; i++)
            {
                SvcResource.ResourceDataSet.ResourcesRow resRow = 
                    rds.Resources.NewResourcesRow();
                resRow.RES_UID = Guid.NewGuid();

                string resName = "Res Name " + resRow.RES_UID;
                Console.WriteLine("\t {0}", resName);
                resRow.RES_NAME = resName;

                rds.Resources.AddResourcesRow(resRow);
                resUids[i] = resRow.RES_UID;
            }
            resourceClient.CreateResources(rds, false, true);
            createdResources.AddRange(resUids);
            return resUids;
        }

        // Create a project.
        public static Guid GenerateProject()
        {
            SvcProject.ProjectDataSet pds = new SvcProject.ProjectDataSet();
            SvcProject.ProjectDataSet.ProjectRow pRow = pds.Project.NewProjectRow();
            pRow.PROJ_UID = Guid.NewGuid();

            string projName = "Proj " + pRow.PROJ_UID;
            Console.WriteLine("Creating project: {0}", projName);
            pRow.PROJ_NAME = projName;
            pds.Project.AddProjectRow(pRow);

            Guid jobUid = Guid.NewGuid();
            projectClient.QueueCreateProject(jobUid, pds, false);

            Helpers.WaitForQueue(SvcQueueSystem.QueueMsgType.ProjectCreate,
                           1, queueSystemClient, jobUid);
            Guid joubUid = Guid.NewGuid();
            string mssUrl = string.Empty;   // Don't create a project site.
            bool fullPublish = true;
            projectClient.QueuePublish(jobUid, pRow.PROJ_UID, fullPublish, mssUrl);
            Helpers.WaitForQueue(SvcQueueSystem.QueueMsgType.ProjectPublish, 1, 
                queueSystemClient, jobUid);
            createdProjects.Add(pRow.PROJ_UID);
            return pRow.PROJ_UID;
        }

        // Get the assignment interval name.
        public static string GetIntervalNameByDate(DateTime date, 
            SvcResourcePlan.ResourcePlanDataSet resDS)
        {
            foreach (SvcResourcePlan.ResourcePlanDataSet.DatesRow row in resDS.Dates)
                if (date >= row.StartDate && date < row.EndDate)
                    return row.IntervalName;
            return string.Empty;
        }

        // Set work for a resource, for the specified interval.
        public static void SetWorkForResourceForInterval(string intervalName, 
            Guid resourceGuid, 
            Guid projUid, double value, 
            SvcResourcePlan.ResourcePlanDataSet rpds)
        {
            SvcResourcePlan.ResourcePlanDataSet.DatesRow datesRow = 
                rpds.Dates.FindByIntervalName(intervalName);
            if (datesRow == null)
            {
                Console.WriteLine("\nFailed to set value for interval: {0}. Did not find interval.", 
                    intervalName);
                return;
            }
            SvcResourcePlan.ResourcePlanDataSet.PlanResourcesRow planRow = 
                rpds.PlanResources.FindByRES_UIDPROJ_UID(resourceGuid, projUid);
            planRow[intervalName] = value * PSLibrary.ValidationConst.s_cal_units_per_hour;
        }

        // Configure the PSI client endpoints.
        public static bool ConfigClientEndpoints(string endpt)
        {
            bool result = true;

            switch (endpt)
            {
                case ENDPOINT_RESPLAN:
                    resourcePlanClient = new SvcResourcePlan.ResourcePlanClient(endpt);
                    break;
                case ENDPOINT_P:
                    projectClient = new SvcProject.ProjectClient(endpt);
                    break;
                case ENDPOINT_Q:
                    queueSystemClient = new SvcQueueSystem.QueueSystemClient(endpt);
                    break;
                case ENDPOINT_R:
                    resourceClient = new SvcResource.ResourceClient(endpt);
                    break;
                default:
                    result = false;
                    Console.WriteLine("Invalid endpoint: {0}", endpt);
                    break;
            }
            return result;
        }        
    }
    class Helpers
    {
        /// <summary>
        /// Public TimeOut property.
        /// </summary>
        /// <value>Gets or sets the timeout for WaitForQueue calls.</value>
        public static int TimeOut
        {
            get
            {
                return timeOut;
            }
            set
            {
                timeOut = value;
            }
        }
        // Default timeout is 3 minutes.
        private static int timeOut = 3 * 60 * 1000;

        // Incremental sleep time is 2 seconds.
        private static int incrementalSleepTime = 2 * 1000;

        public static SvcQueueSystem.JobState WaitForQueue(
            SvcQueueSystem.QueueMsgType jobType, int numJobs,
            SvcQueueSystem.QueueSystemClient queueSystemClient, Guid jobId)
        {
            int timeSlept = 0;
            int sleepInterval = (TimeOut / 60 > incrementalSleepTime) ? 
                TimeOut / 60 : incrementalSleepTime;

            SvcQueueSystem.QueueStatusDataSet queueStatusDs = 
                new SvcQueueSystem.QueueStatusDataSet();
            String errorString = String.Empty;
            Console.WriteLine("\nWaiting for job" + jobType.ToString());

            while (true)
            {
                SvcQueueSystem.JobState jobState = 
                    queueSystemClient.GetJobCompletionState(out errorString, jobId);

                SvcQueueSystem.QueueStatusDataSet jobStatus = 
                    queueSystemClient.ReadJobStatusSimple(new Guid[] { jobId }, true);
                if (jobState == SvcQueueSystem.JobState.Unknown)
                {
                    string jobStatusInfo = "Job status is unknown.";
                    jobStatusInfo += "\n\tWas the job placed on the Queue?";
                    jobStatusInfo += "\n\t--returning from WaitForQueue.";
                    Console.WriteLine(jobStatusInfo);
                    return jobState;
                }
                if (jobState == SvcQueueSystem.JobState.Success ||
                    jobState == SvcQueueSystem.JobState.Failed ||
                    jobState == SvcQueueSystem.JobState.FailedNotBlocking ||
                    jobState == SvcQueueSystem.JobState.CorrelationBlocked ||
                    jobState == SvcQueueSystem.JobState.Canceled)
                {
                    Console.WriteLine("\tJob completed, returning from WaitForQueue");
                    return jobState;
                }
                System.Threading.Thread.CurrentThread.Join(sleepInterval);
                timeSlept += sleepInterval;

                if (timeSlept > TimeOut)
                {
                    return SvcQueueSystem.JobState.Unknown;
                }
            }
        }

        /// <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;
        }
    }
}

См. также

Справочные материалы

ResourcePlan класс

Элементы ResourcePlan

Пространство имен WebSvcResourcePlan