How to ensure your accepted updates get published in Project Server 2007


In Project Server 2003 updates needed to be made with Project Professional , and then when Project was closed an auto publish would happen – if you wanted it to or not.  Some people wanted it, some didn’t.  In 2007 as we don’t need to use Project Professional and this can happen purely on the server then we leave the choice of when to publish up to you. 

One way you can simulate the 2003 behavior is to use a server-side event handler to act on the Statusing.OnApplied method, and carry out a publish of the project via the PSI.  This would then ensure that all accepted updates were reflected in PWA.  The following code samples is based on the SDK TestEventHandler, and apart from the code, would also require web references to the Project and LoginWindows web services.  I am also not using impersonation, so my SSP Administrator (the account that would be running the Event services) does need to be a user in PWA with the right permissions to publish the projects.  You could use the same techniques as I recently published for impersonation if you did not want to give any PWA permissions to this account.  If multiple publish events hit the queue at one time then most will get skipped for optimization – but if you are processing a great deal of updates you should consider the load this extra publish work will put on your server.  I use the “post” rather than the “pre” event so that even if the event handler fails it will not block or cancel the event.  Obviously my writing to the event log is optional too – just helped me to see it was working.

As usual with MSDN blog postings the code is supplied “as-is”, with no warranties or support and could probably do with some better exception handling – but hopefully for any customers wanting to get auto publishing this will be a help.  You will need to replace servername and pwa with your own servername and pwa instance names.

using System;
using System.Net;
using System.Diagnostics;
using Microsoft.Office.Project.Server.Events;
using Microsoft.Office.Project.Server.Library;

namespace TestEventHandler
{
    public class MyPublishingEventHandler : StatusingEventReceiver 
    {
        const string LOGINWINDOWS = "_vti_bin/PSI/LoginWindows.asmx";
        const string PROJECT = "_vti_bin/PSI/Project.asmx";
        private static WebSvcLoginWindows.LoginWindows 
            loginWindows = new 
                WebSvcLoginWindows.LoginWindows();
        private static WebSvcProject.Project project =
            new WebSvcProject.Project();
        private string baseUrl = "http://servername/pwa/";
 
        public override void  OnApplied(PSContextInfo contextInfo, 
            StatusingPostApplyEventArgs e)

        {
             base.OnApplied(contextInfo, e);
            
            loginWindows.Url = baseUrl + LOGINWINDOWS;
            loginWindows.Credentials = 
                CredentialCache.DefaultCredentials;
            project.Url = baseUrl + PROJECT;
            project.Credentials = 
                CredentialCache.DefaultCredentials;

            // I don't do a full publish 
            // You could change the third parameter to true if you wanted to
            Guid jobUid = Guid.NewGuid();
            project.QueuePublish(jobUid, e.ProjectID, false, "");

            // Create an EventLog instance and assign its source.
            EventLog myLog = new EventLog();
            myLog.Source = "Auto Publish Event Handler";

            // Get information from the event arguments, and 
            // write an entry to the Application event log. 
            string userName = contextInfo.UserName.ToString();
            string projectGuid = e.ProjectID.ToString();
            int eventId = 3945;
            string logEntry;

            logEntry = "User: " + userName + "\nProject UID: "
                + projectGuid + " has been queued for publish.";
            myLog.WriteEntry(logEntry, 
                EventLogEntryType.Information, eventId);

            }
        
    }
}

The SDK description of the Event Handlers, and links to the SDK samples can be found here.


Comments (38)

  1. vserrano says:

    Hello Brian,

    I still have the error: "HTTP status 401: Unauthorized". My SSP Administrator is an account Domain administrator and Project Server administrator, the account is DEMOAdministrator.

    Why this error happen?

    What is the solution?

  2. Hi Vserrano,

    I’d suggest you check the IIS logs to see if it is really the demoadministrator account that is jitting the site.

    Best regards,

    Brian.

  3. vserrano says:

    Hello Brian,

    I’m doing an integration with Project Server 2007, I’m using Event Handlers that

    make calls to stored procedures. But it doesn’t work.In the event viewer doesn’t

    appear any error. Are stored procedures and the event handlers incompatible?

    Why doesn`t it work correctly?

    Find enclosed a part of source code.

    namespace TestEventHandler

    {

       public class PublishingEventHandler: ProjectEventReceiver

       {

           //Creamos la cadena de conexión base datos ProjectServer_Reporting

           SqlConnection cn = new SqlConnection("Data Source=SERVER;Initial

    Catalog=ProjectServer_Reporting;Integrated Security=True");

           DataSet ds = new DataSet();

           const string LOGINWINDOWS = "_vti_bin/PSI/LoginWindows.asmx";

           const string PROJECT = "_vti_bin/PSI/Project.asmx";

           private static WebSvcLoginWindows.LoginWindows

           loginWindows = new WebSvcLoginWindows.LoginWindows();

           private static WebSvcProject.Project project = new WebSvcProject.Project();

           private string baseUrl = "http://portal/pwa/";

           public override void

    OnPublished(Microsoft.Office.Project.Server.Library.PSContextInfo

    contextInfo, ProjectPostPublishEventArgs e)

           {

               base.OnPublished(contextInfo, e);

               EventLog myLog = new EventLog();

               myLog.Source = "Project Server";

               loginWindows.Url = baseUrl + LOGINWINDOWS;

               loginWindows.Credentials =

                CredentialCache.DefaultCredentials;

               project.Url = baseUrl + PROJECT;

               project.Credentials =

               CredentialCache.DefaultCredentials;

               // Get information from the event arguments, and

               // write an entry to the Application event log.

               string userName = contextInfo.UserName.ToString();

               string projectName = e.ProjectName.ToString();

               Guid siteGuid = contextInfo.SiteGuid;

               string pwaUrl = new WSS.SPSite(siteGuid).Url;

               this.Obtener_Recursos_Coste(e.ProjectGuid.ToString());

    protected void Obtener_Recursos_Coste(string idproyecto)

           {

               SqlCommand cmd = new SqlCommand("GetGenericResourceCostProject", cn);

               cmd.CommandType = CommandType.StoredProcedure;

               cmd.Parameters.Add("@IdProyecto", SqlDbType.NVarChar).Value = idproyecto;

               SqlDataAdapter da = new SqlDataAdapter();

               da.SelectCommand = cmd;

               cn.Open();

               da.Fill(ds, "RecursosCostes");

               cn.Close();

           }

                       MailMessage msg = new MailMessage();

                       msg.To.Add(new MailAddress("administrator@demo.local"));

                       msg.From = new MailAddress("Administrador@demo.local");

                       msg.Subject = "Nuevos Recursos Coste";

                       string body;

                       body = i["NomRecursoD"].ToString() + "   " +

    i["DiferenciaCostD"].ToString() + "euros";

                       msg.Body = body;

                       SmtpClient clienteSmtp = new SmtpClient("server");

                       clienteSmtp.Send(msg);

                       // Este es el código nuevoclienteSmtp.Credentials = new

    NetworkCredential("usuario", "clave");

  4. Hi,

    I can’t see any reason this shouldn’t work – have you tested the stored procedure in isolation?  Also the event handler will run as the SSP admin account – so make sure they have the right permissions.

    Best regards,

    Brian

  5. vserrano says:

    Hi Brian

    The source code and the stored procedures work correctly because I´ve tested it. My SSP account(DEMOfarmadmin) is owner of reporting database but the user of the stored procedures is DEMOadministrator. The stored procedures  are inside of reporting database so if the SSP account is owner of reporting database, the ssp account will have permissions over the stored procedures.¿it is all right?  

  6. Sounds good to me.  I would suggest using SQL Profiler and look for errors – it should show in the trace if any permissions issues are happening at the DB level.

    Best regards,

    Brian.

  7. Zisa says:

    Hi,

    I’m trying to catch the event when I’m publishing the projects   and alter override it to make some additional calculations with custom fields.

    I do the next steps:

    1. Override  the default event :  OnPublishing(PSLibrary.PSContextInfo contextInfo, ProjectPrePublishEventArgs );

    2. Obtain the project custom fields information :

    projectsDs = projectSvc.ReadProjectEntities((Guid)projectRow["ProjectUID"], ENTITY_TYPE_PROJ_AND_CF, DataStoreEnum.WorkingStore);

    3. Update project dataset with one of the next methods:

    projectSvc.QueueUpdateProject(jobIdUpdate, projectsDs.Project[0].PROJ_SESSION_UID, projectsDs, false);

    projectSvc.QueueAddToProject(jobIdAdd, projectsDs.Project[0].PROJ_SESSION_UID, newPojectsDataCF, false).

    In my develop environment the event Works because the user that publish the project in MS Project is the same is the SSP Admin User.

    In production environment I get the exception:

    System.Web.Services.Protocols.SoapException: ProjectServerError(s) LastError=CICOCheckedOutToOtherUser Instructions: Pass this into PSClientError constructor to access all error information  at Microsoft.Office.Project.Server.WebService.Project…

    1. Yes, the Project is checkout by the same user of contextInfo.UserName:

    2. On event i´m using the default credenciais in url “http://localhost/Litware/_vti_bin/psi/project.asmx”;

    3. The SSP Admin is epm user;

    Is needed make impersonate to call project Web service?

    Instead of I use PWA Web services why I have this problem???

    Please, Can you show me how I can make a project update in event handler when this project is already checkout?  Is this possible?

    Thanks,

  8. vserrano says:

    Hi Brian.

    I have project indicators of work and cost, and when I try to autopublish a project with your code the indicators don´t change.   I use  this formula for costs:

    IIf(ProjDateValue([Baseline Finish])=4294967295,"4_ No Baseline",IIf([Cost Variance]>[Baseline Cost]*0.15,"1_ 15%+ Over Budget",IIf([Cost Variance]>[Baseline Cost]*0.01 And [Cost Variance]<=[Baseline Cost]*0.15,"2_ 1% to 15% Over Budget","3_ On Budget")))

    In My tasks pane, I´ve put more hours of the planned, so that cost indicator should change to yellow or red in Project Center, but nothing happens.

    However, when I open Project Professional 2007, I can see how the indicator has changed.

    What may be happening?

    Thank you.

  9. Sandeep says:

    Please, if you got the solution of this problem "Can you show me how I can make a project update in event handler when this project is already checkout?  Is this possible? "

  10. Hi Sandeep,

    You could check it in – but this risks losing changes others are making.  Use of the statusing web service is another option – as the update is then processed later so will not be blocked by a checked out project.

    Best regards,

    Brian

  11. vserrano says:

    Hi Brian.

    I have project indicators of work and cost, and when I try to autopublish a project with your code the indicators don´t change.   I use  this formula for costs:

    IIf(ProjDateValue([Baseline Finish])=4294967295,"4_ No Baseline",IIf([Cost Variance]>[Baseline Cost]*0.15,"1_ 15%+ Over Budget",IIf([Cost Variance]>[Baseline Cost]*0.01 And [Cost Variance]<=[Baseline Cost]*0.15,"2_ 1% to 15% Over Budget","3_ On Budget")))

    In My tasks pane, I´ve put more hours of the planned, so that cost indicator should change to yellow or red in Project Center, but nothing happens.

    However, when I open Project Professional 2007, I can see how the indicator has changed.

    What may be happening?

    Thank you.

  12. Hi vserrano,

    If you then publish from Pro do you see the correct indicators?  I know we have seen some issues in this area with recalculation and display of indicators.  I will search and see if this fits in with any known issues.

    Best regards,

    Brian

  13. vserrano says:

    Hi Brian,

    If I publish the project from Project Profesional I see the correct indicators but If I autopublish from your code in Project Server the indocators don`t change.

    Thanks

  14. We had a question recently regarding having multiple servers each with some custom server-side event

  15. Angeldb says:

    Hi Brian,

    Great post. It works for us.

    Only thing is that our Reporting database doesn’t get fully updated. We have "Time entry by Timesheets only enabled". So after a PM approves hours submitted by Resources and this EventHandler gets fired, we figured that the Reporting database would be updated. However, what we have found is that the Actual Work is updated in the non-timephased table (MSP_EpmAssignment) but not updated in the time-phased table (MSP_EpmAssignmentByDay).

    We have a Timesheet report that compares hours on the Timesheet with the Actuals reported in MSP_EpmAssignmentByDay. It is only after we Publish the project from Microsoft Project that this table in the Reporting database gets updated.

    I understand that the CU from August (KB 956061) has something in it that fixes Actual Work missing in the Reporting Database after successful Published of the Project Plan. We are nervous however because before this KB article was documented, we got the hotfix from Microsoft, applied it on our Server, and it broke PWA.

    Anyways, just posting this in case anyone else saw the same behavior. Also wondering if Brian has any input on this issue. (similoar to vserrano up above)

  16. Pedro Mesquita says:

    Hi.

    Im from Portugal, im using your code but it doesnt work 🙁

    when the approver accepts (or rejects) the hours from de resource my event handler isnt called. i dont know why. it is well installed. when this event is really called, i mean, the OnApplied event ????

    thanks!

    best regards

    Pedro

  17. PatLac says:

    Hi Brian,

    We implemented a similar handler many months ago and it was working fine….. until last month when we moved our environment to different servers.  

    Now, we have the same problem as the one mentionned by "Angeldb".  We also notice the problem when publishing from ProjTool, the reporting DB does not get correctly updated.

    We have october CU installed.

    Any idea if something changed lately ??

  18. PatLac says:

    Hi Brian,

    We implemented a similar handler many months ago and it was working fine….. until sometime ago (we dont kno exactly when).  

    Now, we have the same problem as the one mentionned by "Angeldb".  We also notice the problem when publishing from ProjTool, the reporting DB does not get correctly updated.

    We have october CU installed.

    Any idea if something changed lately ??

    Pat

  19. Hi PatLac, Pedro and Angeldb, sorry for the delayed responses.

    Certainly there is aneed to do a full publish from Project Professional to drive some of the functionality as some of you have seen.  I am not aware of any recent changes but I will re-test my event handler in the next few days (other things permitting) and just ensure we haven’t broken anything.

    One other point that I may well do a full blog posting on shortly is the changes in TASK UID when the first update is made to an assignment.  This is by design, but can catch you out if you are handling the TASK UIDs in some external system.  It has also been behind some of the bugs we have discovered and can give an issue when comparing data between timesheet and tasks – depending which system was used first when updating.

    Best regards,

    Brian.

  20. Michael says:

    Has anyone found a way yet to automatically publish a project (ie. not opening it in project professional) and getting the reporting database to properly update the actual work?  Is this going to be fixed?  It is quite the limitation on the system when you are working with 50 or so projects.

  21. Justin says:

    Is possible to enable Auto-Approve functionality so that Project Managers do not have to constantly approve tasks?

  22. James Fraser says:

    Brian,

    As always, I appreciate the ideas and effort. But it seems like this automated publish is worse than no publish at all.

    Without updating the timephased reporting tables many reports and data analysis views will be left behind. Project Managers won’t think they need to publish, the "Last Published Date" available in PWA won’t indicate any problems, but reporting data will be incomplete.

    After some experimenting, it looks like the Edit Properties -> Publish does the same thing.

    Couple of questions:

    1. Is the partial publish behavior by design or a bug? Should I open an issue with Support to try to get this resolved for a customer?

    2. Is there a list of differences between the two publishes?

    (Our client’s situation is that they have many "operational" plans with few dependencies and long tasks with many assignments. These drive some critical reports  with timephased actuals. Being able to use the PWA publish or an automated publish would be a huge timesaver for them.)

    Thanks again for all your useful information…

    James Fraser

  23. Hi James, and Justin,

    Releated questions so I’ll answer both (or possibly neither).  Firstly James – I have started an e-mail thread with my escalation colleagues to hopefully get to the bottom of this behavior – I will post again when I have some news.  Justin – it is possible to do a level of automation, but as you can see from this thread you need to be sure this isn’t going to lose your project managers some degree of control.  Take a look a Manage Rules on the Action menu of the Task Updates page for options on how you can set rules to automatically accept the updates.

    Best regards,

    Brian.

  24. James Fraser says:

    I noticed that the February 2009 Cumulative Update for Project Server lists a fix for:

    • You use the Project Server Interface (PSI) to update the timephased actual work. After you publish the project, the timephased work and the timephased actual work are not added to the MSP_EpmAssignmentByDay table in the reporting database. However, the MSP_EpmAssignment table shows the correct timephased work and actual work.

    Does that refer to the Publish issues that we are running into here?

    James Fraser

  25. My understanding James, is that it does.  Please let me and the group know your experiences.  I meant to pull this fix out for special mention and do a posting, but haven’t got round to it yet.

    Best regards,

    Brian.

  26. James Fraser says:

    Confirming the fix…

    The February Cumulative Update does resolve the issue mentioned above regarding incomplete updates of the MSP_EpmAssignmentByDay table with actual work.

    Steps to demonstrate fix:

    (All on a server updated from Dec CU to Feb CU.)

    – Published a new project with tasks assigned to resource.

    – Resource created a new time sheet and saved.

    – Allowed the TSAutoStatus codeplex solution to import to My Tasks and submit the update.

    – PM accepted update in PWA (without previewing)

    – Event fired, publishing project.

    – SQL query of MSP_EpmAssignmentByDay shows AssignmentActualWork fields are updated.

    Yay!

    James Fraser

  27. Justin says:

    Just to clarify, does this enable auto publishing from PWA or from MS Project (desktop app)? Would this code enable auto publishing when the following occurs:

    1. Users access their Project via Project Web Access and add a Task

    2. Users submits Task and custom code/event handlers would auto publish this Task to the Project

  28. Hi Jason,

    The code fires on the statusing.applied event -so it would not fire for your first scenario, and would only fire on your second when the project manager accepted and applied the task.

    If you wanted the first to work you could use the save or checkin events to fire off a publish.

    Best regards,

    Brian.

  29. Justin says:

    Brian,

    Thanks for your help.

    Couple questions on your resonse:

    How do you configure an event? In other words, how would one use the "save event to fire off a publish"?

    If I can custimize the Save event to not only save the the task, but also publish it, that gets me to where I need to be.

    As for firing on a status.applied event; If I were to setup a rule to auto approve, what would would have to occur to trigger the custom code you provide above? What do you mean when you say the PM would have to "apply the task"? Could this action be automated as well?

  30. Hi Justin,

    The event handlers are covered in the SDK which can be found at the Project Developer Portal – http://msdn.microsoft.com/en-us/office/aa905469.aspx.  Basically you do not modify an existing event, but build a handler in Visual Studio and then deploy to the server and register in PWA – so your event handler subscribes to the save event – and then when any save occurs your code should run.  THere is a good walk-through article – http://msdn.microsoft.com/en-us/library/ms469450.aspx – called How to: Write and Debug a Project Server Event Handler.

    Best regards,

    Brian.

  31. lbass says:

    Brian,

    I have implemented your example and it works perfectly. However, I am attempting to add logic based on custom field values. I am receiving the error:

    ==============================

    PSCLientError Output:

    ProjectHasWriteLock

    ============================

    from the ReadProjectEntities method and the WorkingStore. Nothing is checked out, and I am not attempting to write. Have you seen anything like this before? It works fine from a console application but it errors as an event handler.

    Any help is greatly appreciated, thanks.

  32. Hi lbass,

    If it works as a console app then could the event it is firing from have it locked?  What exactly are you trying to do, and at which point in the code?

    Best regards,

    Brian.

  33. lbass says:

    Brian,

    The exception is being thrown in the ReadProjectEntities method when I am trying to obtain the custom field values.

    Basically, I am combing your example with the code found at http://blogs.msdn.com/project_programmability/archive/2008/02/28/custom-field-and-lookup-table-webcast.aspx

    to selectively publish projects based on a custom field value.

    My question: what would the event do to the project to cause a ProjectHasWriteLock exception? Is there another way for me to obtain the custom field value from an event handler?

    Thanks again for your help.

  34. Hi lbass,

    I can only think the project is checked out and locked as the update is being applied and is still in this state when the event fires (the queue may give some ideas here if you see it a check-in job at this time).  I’ll give this more thought to see how one might workaround this  issue.

    Best regards,

    Brian.

  35. jad says:

    Hi,

    I’m trying to catch the event when I’m publishing the projects   and alter override it to make some additional calculations with custom fields.

    I do the next steps:

    1. Override  the default event :  OnPublishing(PSLibrary.PSContextInfo contextInfo, ProjectPrePublishEventArgs );

    2. Obtain the project custom fields information :

    projectsDs = projectSvc.ReadProjectEntities((Guid)projectRow["ProjectUID"], ENTITY_TYPE_PROJ_AND_CF, DataStoreEnum.WorkingStore);

    3. Update project dataset with one of the next methods:

    projectSvc.QueueUpdateProject(jobIdUpdate, projectsDs.Project[0].PROJ_SESSION_UID, projectsDs, false);

    projectSvc.QueueAddToProject(jobIdAdd, projectsDs.Project[0].PROJ_SESSION_UID, newPojectsDataCF, false).

    In my develop environment the event Works because the user that publish the project in MS Project is the same is the SSP Admin User.

    In production environment I get the exception:

    System.Web.Services.Protocols.SoapException: ProjectServerError(s) LastError=CICOCheckedOutToOtherUser Instructions: Pass this into PSClientError constructor to access all error information  at Microsoft.Office.Project.Server.WebService.Project…

    1. Yes, the Project is checkout by the same user of contextInfo.UserName:

    2. On event i´m using the default credenciais in url “http://localhost/Litware/_vti_bin/psi/project.asmx”;

    3. The SSP Admin is epm user;

    Is needed make impersonate to call project Web service?

    Instead of I use PWA Web services why I have this problem???

    Please, Can you show me how I can make a project update in event handler when this project is already checkout?  Is this possible?

    Thanks,

  36. Hi Jad,

    For performance and other reasons (timing being the main one) you probably don’t want to try changing information in line with events.  Not sure exactly what you are trying to achieve – but the saved or checked-in event might be easier to work with – and then push another publish at the end of your code.  You may need to impersonate depending on your security seetings and if the SSP account is actually a Project user.

    Hope this helps,

    Best regards,

    Brian.

  37. Maria says:

    Hello to all!!

    I've Project Server 2007 and we need that the PM mustn't accept the update of the task submitted by resources through Outlook, we have created rules to make this automatic, but we still need to run the rules, so we will need that rules execute without any intervention, and evenmore, we will need the publish of the project.

    I've read the post and the questions, but all it's not clear for me because I'm not experience with this. Could anyone help me to implement the automatization explained?

    I would be very gratefully if someone can help me.

    THANKS A LOT!!

    Maria

  38. Hi Maria,

    Not sure what you mean by 'accept in Outlook' so certainly more automation would be needed than I explain here.  One option you should consider is if Project Server 2010 would suit you needs better.  We support better integration wtih Exchange/Outlook (but not task approvals in Outlook) and we have just added with SP1 a rule to auto approve AND publish updates.

    Best regards,

    Brian.

Skip to main content