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!