Syncing Project Workspaces with the RDB

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