Project Programmability

This blog focuses on customizations and programming for Project Web App, Project Server, Project Professional and Project Standard. Includes User Interface (UI) customizations, Project Server Interface (PSI) and Visual Basic for Applications (VBA) Programming. It also covers Business Intelligence.
 
 

May, 2007

  • Project Programmability and Business Intelligence

    Syncing Project Workspaces with the RDB

    • 2 Comments

    It has been a while since I have done a blog post, so I figured I would share with you something that I am currently working on. We have run into the scenario where users are updating information on Project Workspaces and Project Manager wants to report on the data that the users are entering in the Workspaces. That information does not make it into the RDB until after a project publishes. To keep the RDB in sync with the Project Workspace, I wrote the following app that we run as a scheduled job:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Net;
    using System.Data;
    using System.Web.Services.Protocols;
    using System.Diagnostics;
    using PSLibrary = Microsoft.Office.Project.Server.Library;

    namespace WorkspaceRDBUpdate
    {
      class Program
     
    {
        static void Main(string[] args)
        {
          int count = 0;
         
    bool verbose = false;
         
    string ls_projURL = "";
         
    const string PROJECT_SERVICE_PATH = "_vti_bin/psi/Project.asmx";

          if (args.Length == 0 || args.Length > 2)
          {
            System.
    Console.WriteLine("WorkspaceRDBUpdate url [verbose]");
            System.
    Console.WriteLine(" url – The URL to the project server.");
            System.
    Console.WriteLine(" verbose – An optional parameter that outputs progress.");
          }
         
    else
         
    {
            ls_projURL = args[0];
            
           
    if (args.Length > 1 && args[1].ToLower() == "verbose")
            {
              verbose =
    true;
            }

            WSProject.Project ws_Project = new WSProject.Project();

            if (!ls_projURL.EndsWith("/"))
            {
              ls_projURL +=
    "/";
            }

            ws_Project.Url = ls_projURL + PROJECT_SERVICE_PATH;
            ws_Project.Credentials =
    CredentialCache.DefaultCredentials;

            Guid lo_projGUID;
           
    string ls_projName;

     

            WSProject.ProjectDataSet lo_projs = null;

            WSProject.ProjectDataSet lo_projDS;

            try
           
    {
              lo_projs = ws_Project.ReadProjectList();
             
    DataRowCollection lo_projects = lo_projs.Tables[lo_projs.Project.TableName].Rows;

              for (int i = 0; i < lo_projects.Count; i++)
              {
                lo_projGUID =
    new Guid(lo_projects[i][0].ToString());          
               
    ls_projName = lo_projects[i][1].ToString();

                try
               
    {
                  lo_projDS = ws_Project.ReadProjectEntities(lo_projGUID, 1, WorkspaceRDBUpdate.WSProject.
    DataStoreEnum.PublishedStore);

                  // Check if the Project has a Workspace

                  if (lo_projDS.Tables[lo_projDS.Project.TableName].Rows[0][lo_projDS.Project.WSTS_SERVER_UIDColumn.ColumnName] != null && lo_projDS.Tables[lo_projDS.Project.TableName].Rows[0][lo_projDS.Project.WSTS_SERVER_UIDColumn.ColumnName].ToString() != "")
                  {
                   
    if (verbose)
                      System.
    Console.WriteLine("Synchronizing Workspace for Project " + ls_projName);

                    ws_Project.QueueSynchronizeProjectWorkspace(
    Guid.NewGuid(), lo_projGUID, false);
                    count++;
                  }
                 
    else
                 
    {
                    if (verbose)
                      System.
    Console.WriteLine("Notice: Project " + ls_projName + " does not have a workspace.");
                  }
                }
               
    catch (SoapException lo_ex)
                {
                  PSLibrary.
    PSClientError psiError = new PSLibrary.PSClientError(lo_ex);
                  PSLibrary.
    PSErrorInfo[] psiErrors = psiError.GetAllErrors();

                  if (psiErrors.Length == 1)
                  {
                   
    if (psiErrors[0].ToString() == "ProjectNotFound")
                    {
                     
    if (verbose)
                        System.
    Console.WriteLine("Notice: Project " + ls_projName + " is not published.");
                    }
                  }
                }
              }

              Event("Successfully Synchronized " + count + " Projects with the RDB", EventLogEntryType.Information);

            }
            
    catch (WebException lo_ex)
            {
             
    if (verbose)
                System.
    Console.WriteLine("Error: " + lo_ex.Message);

              Event("Error: " + lo_ex.Message, EventLogEntryType.Error);
            }
            
    catch (Exception lo_ex)
            {
              
    if (verbose)
                System.
    Console.WriteLine("Unknown Error: " + lo_ex.Message);

              Event("Unknown Error: " + lo_ex.Message, EventLogEntryType.Error);
            }
          }
        }

        static private void Event(string as_msg, EventLogEntryType eventType)
        {
         
    EventLog lo_eventLog = new EventLog();    
         
    lo_eventLog.Source =
    "Workspace RDB Sync Job";
          lo_eventLog.WriteEntry(as_msg, eventType, 3652);
        }
      }
    }

    This application is fairly straightforward. It reads all the projects and checks if a workspace exists. If one exists, it forces the RDB to be updated by calling QueueSynchronizeProjectWorkspace(…). It logges events to the event log, which makes troubleshooting easy if administrator decide to run it as a scheduled job.

    Chris Boyd

  • Project Programmability and Business Intelligence

    Getting at the Task Time Phased Data

    • 3 Comments

    I have been asked many times how to get the task time phased data from the PSI. Unfortunately there is no way to get this through the PSI. I suggest that you either go to the RDB for this information or the cubes. Here is a quick example.

    I created a project with one task and broke the work down over a week:

    clip_image002

    I saved and published the project so that it would make its way into the reporting database. Here is the query I wrote to retrieve this data:

    SELECT     
      MSP_EpmTask_UserView.TaskName,
      MSP_EpmAssignmentByDay_UserView.TimeByDay,
      MSP_EpmAssignmentByDay_UserView.AssignmentWork
    FROM         
      MSP_EpmAssignmentByDay_UserView 
        INNER JOIN MSP_EpmTask_UserView 
    ON MSP_EpmAssignmentByDay_UserView.TaskUID = MSP_EpmTask_UserView.TaskUID WHERE (MSP_EpmTask_UserView.TaskName = 'Task 1')

    Here is the result of the query:
    image

    Chris Boyd

Page 1 of 1 (2 items)
Recent Posts