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.
 
 

October, 2007

  • Project Programmability and Business Intelligence

    Writing and Debugging Event Handlers for Project Server 2007

    • 1 Comments

    Another Visual How-to for Project development is published on MSDN: Writing and Debugging Event Handlers for Project Server 2007

     

    In less than 12 minutes, the video shows the development, testing, and debugging of a simple event handler for publishing projects. The OnPublishing event handler cancels publishing if the project name does not satisfy a specified condition, and then logs an application event on the server. The video shows the use of Visual Basic code; the related article includes both Visual Basic and C# code.

     

    The Visual How-to is based on the Project SDK article, How to: Write and Debug a Project Server Event Handler.

  • Project Programmability and Business Intelligence

    Synchronizing Membership Provider for Project Workspaces

    • 2 Comments

    Back on May 17th I posted code that showed how to update the workspace data with the RDB:

    http://blogs.msdn.com/project_programmability/archive/2007/05/17/syncing-project-workspaces-with-the-rdb.aspx 

    Here is a similar program to synchronize project workspace membership. The interesting twist is that I show how to be kinder to the Project Queue by adding a few jobs at a time and waiting for them to complete.

    Here is the code: 

    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 WorkspaceUpdate
    {
        class Program
        {
            static void Main(string[] args)
            {
                int count = 0;
                bool verbose = false;           // Verbose Output switch
                Guid job = Guid.Empty;          // The latest job submitted to the queue.
                int timeOut = 60;               // Default timeout before terminating the queue job

                string ls_projURL = "";
                const string PROJECT_SERVICE_PATH = "_vti_bin/psi/Project.asmx";
                const string WSSINTEROP_SERVICE_PATH = "_vti_bin/PSI/WSSInterop.asmx";
                const string WSQUEUESYSTEM_SERVICE_PATH = "_vti_bin/PSI/QueueSystem.asmx";

                if (args.Length == 0 || args.Length > 3)
                {
                    Message();
                }
                else if (args[0] == "/?")
                {
                    Message();
                }
                else
                {
                    ls_projURL = args[0];

                    if (args.Length > 2 && args[2].ToLower() == "verbose")
                    {
                        verbose = true;
                    }

                    try
                    {
                        timeOut = Convert.ToInt32(args[1]);
                    }
                    catch
                    {
                        Event("Warning: Invalid timeout, defaulting to 60 seconds.", EventLogEntryType.Warning, verbose);
                    }
                   
                    WSProject.Project ws_Project = new WSProject.Project();
                    WSSInterop.WssInterop ws_WssInterop = new WSSInterop.WssInterop();
                    WSQueueSystem.QueueSystem qsWS = new WSQueueSystem.QueueSystem();
                  
                    if (!ls_projURL.EndsWith("/"))
                    {
                        ls_projURL += "/";
                    }

                    try
                    {


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

                        ws_WssInterop.Url = ls_projURL + WSSINTEROP_SERVICE_PATH;
                        ws_WssInterop.Credentials = CredentialCache.DefaultCredentials;

                        qsWS.Url = ls_projURL + WSQUEUESYSTEM_SERVICE_PATH;
                        qsWS.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, 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() != "")
                                    {
                                        Message("Synchronizing Workspace for Project" + ls_projName, verbose);
                                       
                                        //Wait to let the server process the work
                                        if (count % 4 == 3)
                                        {
                                            if (WaitForQueue(timeOut, job, qsWS) == false)
                                            {
                                                Event("Warning: Queue Job not Processed for Project:" + ls_projName + " Check Project Server Queue.", EventLogEntryType.Warning, verbose);
                                            }
                                        }

                                        job = Guid.NewGuid();

                                        ws_WssInterop.QueueSynchronizeMembershipForWssSite(lo_projGUID, job);


                                        count++;
                                    }
                                    else
                                    {
                                        Message("Notice: Project" + ls_projName + " does not have a workspace.", verbose);
                                    }
                                }
                                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")
                                        {
                                            Message("Notice: Project" + ls_projName + " is not published.", verbose);
                                        }
                                    }

                                }
                            }

                            Event("Successfully Synchronized Membership for Workspaces", EventLogEntryType.Information, verbose);
                        }

                        catch (WebException lo_ex)
                        {
                            Event("Error:" + lo_ex.Message, EventLogEntryType.Error, verbose);
                        }
                        catch (Exception lo_ex)
                        {
                            Event("Unknown Error:" + lo_ex.Message, EventLogEntryType.Error, verbose);
                        }
                    }
                    catch (UriFormatException lo_ex)
                    {
                        Event("Unknown Error:" + lo_ex.Message, EventLogEntryType.Error, verbose); ;
                    }
                }
            }

            private static bool WaitForQueue(int timeOut, Guid jobId, WSQueueSystem.QueueSystem qsWS)
            {
               

                int sleep = 3;
                int timeSlept = 0;        // Total time slept (seconds)
                bool jobSuccess = false;
                string xmlError;

                WSQueueSystem.JobState jobState; // Status of the queue job

                timeOut = timeOut * 1000;

                while (true)
                {
                    jobState = qsWS.GetJobCompletionState(jobId, out xmlError);

                    if (jobState == WSQueueSystem.JobState.Success)
                    {
                        jobSuccess = true;
                        break;
                    }
                    else if (jobState == WSQueueSystem.JobState.Unknown
                        || jobState == WSQueueSystem.JobState.Failed
                        || jobState == WSQueueSystem.JobState.FailedNotBlocking
                        || jobState == WSQueueSystem.JobState.CorrelationBlocked
                        || jobState == WSQueueSystem.JobState.Canceled)
                    {
                        jobSuccess = false;
                        break;
                    }
                    else if (timeSlept > timeOut)
                    {
                        jobSuccess = true;
                        //qsWS.CancelJobSimple(jobId);
                        break;
                    }

                    System.Threading.Thread.Sleep(sleep * 1000);

                    timeSlept = +sleep * 1000;
                }

                return jobSuccess;
            }

            static private void Message()
            {
                System.Console.WriteLine("");
                System.Console.WriteLine("WorkspaceUpdate url timeout [verbose]");
                System.Console.WriteLine("  url - The URL to the project server.");
                System.Console.WriteLine("  timeout - Seconds to wait for the queue job to process the User Sync");
                System.Console.WriteLine("  verbose - An optional parameter that outputs progress.");
            }

            static private string Message(string as_msg, bool verbose)
            {
                as_msg = DateTime.Now.ToString() + ":" + as_msg;

                if (verbose)
                    System.Console.WriteLine(as_msg);

                return as_msg;
            }


            static private void Event(string as_msg, EventLogEntryType eventType, bool verbose)
            {
                EventLog lo_eventLog = new EventLog();
                lo_eventLog.Source = "WorkspaceUpdate Sync Job";

                as_msg = Message(as_msg, verbose);
               
                lo_eventLog.WriteEntry(as_msg, eventType, 3652);

            }
        }
    }

  • Project Programmability and Business Intelligence

    Office Project Server 2007 Developer Training

    • 2 Comments

    Microsoft  Office Enterprise Project Management University (EPMU) is offering a range of new courses in Project Server and Project Portfolio Sever 2007 including Developer Training.

    Office Project Server 2007 Developer Training

    • Designed for Developers extending, developing and integrating Office Project Server 2007
    • 3 Day Course
    • USD$550

    For full details of all courses visit www.msepmu.com

  • Project Programmability and Business Intelligence

    Check out the Post on Scalable Issues & Risks Report

    • 1 Comments

    It seems that somehow I messed up and the post "Scalable Issues & Risks Report" ended up showing up in the past. So in case you missed it:

    http://blogs.msdn.com/project_programmability/archive/2007/09/28/scalable-issues-risks-report.aspx

    Chris

Page 1 of 1 (4 items)