News for All PSI Developers

If you are doing Project Server development using the PSI then you NEED to check out what Colby Africa is doing with mpFx.  This is a set of class libraries that simplifies the development of PSI code. It reduces the number of calls you need to make to do things like create projects, assign resources, create tasks, etc.

This is what is required to create a project and wait for the queue job to finish:

    1: namespace Microsoft.SDK.Project.Samples.QueueCreateProject
    2: {
    3:     class Program
    4:     {
    5:         [STAThread]
    6:         static void Main(string[] args)
    7:         {
    8:             try
    9:             {
   10:                 const string PROJECT_SERVER_URI = "h//ServerName/ProjectServerName/";
   11:                 const string PROJECT_SERVICE_PATH = "_vti_bin/psi/project.asmx";
   12:                 const string QUEUESYSTEM_SERVICE_PATH = "_vti_bin/psi/queuesystem.asmx";
   13:  
   14:                 Guid jobId;
   15:  
   16:                 // Set up the Web service objects
   17:                 ProjectWebSvc.Project projectSvc = new ProjectWebSvc.Project();
   18:  
   19:                 ProjectWebSvc.ProjectDataSet projectDs = new ProjectWebSvc.ProjectDataSet();
   20:  
   21:                 projectSvc.Url = PROJECT_SERVER_URI + PROJECT_SERVICE_PATH;
   22:                 projectSvc.Credentials = CredentialCache.DefaultCredentials;
   23:  
   24:                 QueueSystemWebSvc.QueueSystem q = new QueueSystemWebSvc.QueueSystem();
   25:                 q.Url = PROJECT_SERVER_URI + QUEUESYSTEM_SERVICE_PATH;
   26:                 q.UseDefaultCredentials = true;
   27:  
   28:                 projectDs = new ProjectWebSvc.ProjectDataSet();
   29:  
   30:                 // Create the project
   31:                 ProjectWebSvc.ProjectDataSet.ProjectRow projectRow = projectDs.Project.NewProjectRow();
   32:                 projectRow.PROJ_UID = Guid.NewGuid();
   33:                 projectRow.PROJ_NAME = "Its a wonderful project at " +
   34:                    DateTime.Now.ToShortDateString().Replace("/", "") + " " +
   35:                    DateTime.Now.ToShortTimeString().Replac", "");
   36:                 projectRow.PROJ_TYPE = (int)PSLibrary.Project.ProjectType.Project;
   37:                 projectDs.Project.AddProjectRow(projectRow);
   38:  
   39:                 // Add some tasks        
   40:                 jobId = Guid.NewGuid();
   41:                 projectSvc.QueueCreateProject(jobId, projectDs, false);
   42:                 WaitForQueue(q, jobId);
   43:  
   44:             }
   45:             catch (SoapException ex)
   46:             {
   47:                 PSLibrary.PSClientError error = new PSLibrary.PSClientError(ex);
   48:                 PSLibrary.PSErrorInfo[] errors = error.GetAllErrors();
   49:                 string errMess = "==============================\r\nEr \r\n";
   50:                 for (int i = 0; i < errors.Length; i++)
   51:                 {
   52:                     errMess += "\n" + ex.Message.ToString() + "\r\n";
   53:                     errMess += "".PadRight(30, '=') + "\r\nPSCLientError Out\r\n \r\n";
   54:                     errMess += errors[i].ErrId.ToString() + "\n";
   55:  
   56:                     for (int j = 0; j < errors[i].ErrorAttributes.Length; j++)
   57:                     {
   58:                         errMess += "\r\n\t" + errors[i].ErrorAttributeNames()[j]  " + errors[i].ErrorAttributes[j];
   59:                     }
   60:                     errMess += "\r\n".PadRight(30, '=');
   61:                 }
   62:                 Console.ForegroundColor = ConsoleColor.Red;
   63:                 Console.WriteLine(errMess);
   64:             }
   65:             catch (WebException ex)
   66:             {
   67:                 string errMess = ex.Message.ToString() +
   68:                    "\n\nLog on, or check the Project Server Queuing Service";
   69:                 Console.ForegroundColor = ConsoleColor.Red;
   70:                 Console.WriteLine("Er " + errMess);
   71:             }
   72:             catch (Exception ex)
   73:             {
   74:                 Console.ForegroundColor = ConsoleColor.Red;
   75:                 Console.WriteLine("Er " + ex.Message);
   76:             }
   77:             finally
   78:             {
   79:                 Console.ResetColor();
   80:                 Console.WriteLine("\r\n\r\nPress any key...");
   81:                 Console.ReadKey();
   82:             }
   83:         }
   84:         static private void WaitForQueue(QueueSystemWebSvc.QueueSystem q, Guid jobId)
   85:         {
   86:             QueueSystemWebSvc.JobState jobState;
   87:             const int QUEUE_WAIT_TIME = 2; // two seconds
   88:             bool jobDone = false;
   89:             string xmlError = string.Empty;
   90:             int wait = 0;
   91:  
   92:             //Wait for the project to get through the queue
   93:             // - Get the estimated wait time in seconds
   94:             wait = q.GetJobWaitTime(jobId);
   95:  
   96:             // - Wait for it
   97:             Thread.Sleep(wait * 1000);
   98:             // - Wait until it is done.
   99:  
  100:             do
  101:             {
  102:                 // - Get the job state
  103:                 jobState = q.GetJobCompletionState(jobId, out xmlError);
  104:  
  105:                 if (jobState == QueueSystemWebSvc.JobState.Success)
  106:                 {
  107:                     jobDone = true;
  108:                 }
  109:                 else
  110:                 {
  111:                     if (jobState == QueueSystemWebSvc.JobState.Unknown
  112:                     || jobState == QueueSystemWebSvc.JobState.Failed
  113:                     || jobState == QueueSystemWebSvc.JobState.FailedNotBlocking
  114:                     || jobState == QueueSystemWebSvc.JobState.CorrelationBlocked
  115:                     || jobState == QueueSystemWebSvc.JobState.Canceled)
  116:                     {
  117:                         // If the job failed, error out
  118:                         throw (new ApplicationException("Queue request failed \"" + jobState + "\" Job " + jobId + ".\r\n" + xmlError));
  119:                     }
  120:                     else
  121:                     {
  122:                         Console.WriteLine("Job St " + jobState + " Job " + jobId);
  123:                         Thread.Sleep(QUEUE_WAIT_TIME * 1000);
  124:                     }
  125:                 }
  126:             }
  127:             while (!jobDone);
  128:         }
  129:     }
  130: }

 

Here is the same code in mpFx:

    1: using System;
    2: using System.Web.Services.Protocols;
    3: using CodePlex.MicrosoftProject.mpFx;
    4: using CodePlex.MicrosoftProject.mpFx.ProjectsWebService;
    5:  
    6: namespace ConsoleTest
    7: {
    8:     class Program
    9:     {
   10:         static void Main(string[] args)
   11:         {
   12:             using (ProjectServer projectServer = new ProjectServer("h//epm2007demo/pwa", DataStoreEnum.WorkingStore))
   13:             {
   14:                 using (ProjectDataSet projectDataSet = EntityFactory.NewProject("Demo"))
   15:                 {
   16:                     try
   17:                     {
   18:                         projectServer.Projects.Create(projectDataSet, false, true);
   19:                     }
   20:                     catch (SoapException exception)
   21:                     {
   22:                         Console.WriteLine(Errors.ProcessMSProjectErrors(exception));
   23:                     }
   24:                     catch (Exception exception)
   25:                     {
   26:                         Console.WriteLine(exception.Message);                        
   27:                     }
   28:                 }
   29:             }
   30:         }
   31:     }
   32: }

32 lines of code as opposed to 130!