Working with Project Server datasets and the web services – don’t AcceptChanges!


I thought this was one worth mentioning to a wider audience in case it catches others out.  One of our customer had written some code to update data in the timesheet using the PSI.  All seemed to be working OK, but no numbers changed.  You could even debug in Visual Studio and use the cool data visualizer to see the dataset and watch the changes – but even though the call worked and the queue showed a successful update the timesheet didn’t reflect the changes.  The right dataset was also being passed to the final web service – in this case the QueueUpdateTimesheet method of the Timesheet web service.

I then noticed that the customer had an ADO.NET “AcceptChanges” call on the dataset before the call to the web service.  This was breaking the update as the web service is expecting the dataset to have a delta holding the changes from the original read of the timehseet dataset.  The AcceptChanges is used in ADO.NET to commit changes in the dataset – but the delta then disappears.  So even though the dataset was different to that originally read from the PSI call, it didn’t have the deltas – so no changes were made to the original (different) data.  Simply removing this line got everything working again and the changes were then visible in the timesheet control of PWA!

Technorati Tags:

 

Comments (42)

  1. diogoxluis@gmail.com says:

    Thanks… I had the exact same problem…

    Diogo

    PT-SI

    Portugal

  2. chester says:

    Is there anyway to update PWA customized columns (such as in Issues and Risks) onto the Reporting datbase WssRisk/WssIssues if we extend the schema of these tables?

  3. JK says:

    Can you please share the code regarding updating the timesheet using PSI.Its my projects requirement.

    Thanks in advance

  4. Hi JK,

    See the ChangeXML sample in the SDK – direct link http://msdn2.microsoft.com/en-us/library/bb428819.aspx.

    Best regards,

    Brian.

  5. Yury Fedarovich [SS] says:

    I’ve tried many times to update CalendarExceptionsDataTable rows in ResourceDataSet, which i’v got via Resource web service, but project server always threw an exception ‘GeneralInvalidRowState’. When I tried to use AcceptChanges for table, the row’s state switched to Unchanged and the calling of method UpdateResource passed successfully. Of course, calendarexceptions didn’t reflect any changes. So, I can’t understand whether PSI supports updating of calendar exceptions at all..

  6. Hi Yury,

    You don’t need to use AcceptChanges – the web service needs to see what has changed. Are you using the UpdateResources method to make the change?  I haven’t tried this specific change but can’t see anywhere in the SDK that it isn’t supported.  Are you checking the resource out first?

    Best regards,

    Brian.

  7. Yury Fedarovich [SS] says:

    I’ve already found out, that the method AcceptChanges is called implicitly during synchronization of dataset and data in the database. Naturally I used approach, described in Microsoft Office Project 2007 SDK i.e. checkout->updating->checkin. Sample from SDK changes ResourcesDataTable(name of resource) and update passes successfully. But when I try to change CalendarExceptionsDataTable(e.g. start time of exisiting exception) and update resource, GeneralInvalidRowState exception raises. There remains one thing to do – delete exception and then create with modified fields (but who grants, that PS will keep other components untouched after deleting of exception!!)

    How Microft Office Project changes exceptions for resources – it remains a riddle for me (isn’t direct access to database is used???)

  8. Hi Yury,

    We will not be using direct database access.  In most cases we will be using exactly the same web services that you can use – and you can see this by looking at the http traffic between the client and server.  In some cases we make use of private web services pwa and project – which are only considered private because we don’t gurantee not to change the methods for our own needs in new releases.  I would suggest you try the delete/create to see if that resolves your issue.

    Best regards,

    Brian.

  9. Johnny says:

    Hi Brian,

    I have a quick question for you.  I’m working on a project that adds timelines from the contextInfo.UserGuid’s previous timesheet to the new timesheet that is created when the OnCreated Timesheet event in PWA is fired.  This works fine when I’m logged in as the box admin, it finds/adds the timelines no problem, however, when I log into pwa with a regular user account it fails every time.  It seems to fail when it hits the waitforqueue().  I was wondering if you’ve encountered this before and know what may be causing it.

    TimesheetDataSet.Lines.AddLinesRow(line);

                       Timesheet.PrepareTimesheetLine(tsGuid, ref TimesheetDataSet, new Guid[] { line.TS_LINE_UID });

                       Guid jobUid = Guid.NewGuid();

                       Timesheet.QueueUpdateTimesheet(jobUid, tsGuid, TimesheetDataSet);

                       WaitForQueue(QueueSystem, jobUid);

  10. Hi Johnny,

    Sounds like a permissions issue.  You could try giving the "manage queue" global permission in PWA to a user to see if this is what is blocking things.  You then have the choice of either giving the permissions or changing context to check the queue.

    Best regards,

    Brian.

  11. Johnny says:

    Hi Brian,

    I already issued my test user "allow" permissions over everything in Edit Resource -> "Global Permissions".  It seems like I’ve tried everything and still no luck.  Any other ideas?

  12. Johnny says:

    I still do not have a clue on how to fix this.  Do you have any other ideas?

    Btw, I enjoyed your webcast on using BDC yesterday.

  13. Hi Johnny,

    Looking at the newsgroup thread Chris Boyd is saying that impersonation is required.  When you are impersonation you are running as the SSP admin, and hitting the web services in the SSP rather than the pwa instance – so it may be these differences that overcome this issue.

    Glad you enjoyed the webcast – the BDC stuff is a fun feature.  I enjoyed putting that oen together.

    Best regards,

    Brian.

  14. Maik says:

    Hello Brian,

    i´m trying to delete a CalendarExceptionsRow from the ResourceDataSet.CalendarExceptions table. But the RemoveCalendarExceptionsRow() and Delete() methods don´t work for me. These methods delete the row in the DataTable, but after successfully calling the UpdateResources method the exception is still there ( with/without GetChanges() ). I´m only able to add a new exception. Am i missing something ?

    Best regards

    Maik

  15. Arvind says:

    we are unable to update part timer’s information (work Type Exceptions) at EPM level. It is not allowing us to update / delete any type of exceptions but, we can add the exceptions for existing resource. How we can update part timer’s information (work Type Exceptions) at EPM level?

    Any help or direction will help us.

  16. Arvind and Saurav says:

    I am working on a requirement which requires updating the actual hour against resources and actual cost against the task for a particular projcet.

    We are using Statusing web service to update the actual hour of the resources on date basis.

    We are using status method to update the actuals.

    We can only invoke this method if the user is an administrator otherwise we encounter General Security Exception. And only the resource can update hisher own actuals. if using some other resource account we try to update the actuals we again get General Security Exception.

    Currently we are using a single dedicated account to call the web service and method. After googling we came up with impersonation to actually update the actuals for all the resources using a single dedicated account. We are trying to achieve impersontaion in PSI using SSP in Project Server.

    But while calling SSP from my .net component which runs on the Project Server where PWA is hosted i am getting HTTP 401 error.

    The account which i am using to call the SSP web service has administrator previliges in Project Web Access.

    Please suggest me the resolution. Please do the needful.

  17. I am working on a requirement which requires updating the actual hour against resources and actual cost against the task for a particular projcet.

    We are using Statusing web service to update the actual hour of the resources on date basis.

    We are using status method to update the actuals.

    We can only invoke this method if the user is an administrator otherwise we encounter General Security Exception. And only the resource can update hisher own actuals. if using some other resource account we try to update the actuals we again get General Security Exception.

    Currently we are using a single dedicated account to call the web service and method. After googling we came up with impersonation to actually update the actuals for all the resources using a single dedicated account. We are trying to achieve impersontaion in PSI using SSP in Project Server.

    But while calling SSP from my .net component which runs on the Project Server where PWA is hosted i am getting HTTP 401 error.

    The account which i am using to call the SSP web service has administrator previliges in Project Web Access.

    Please suggest me the resolution. Please do the needful.

  18. The article on Impersonation in the SDK covers full details.  Please read this as impersonation in the context of Project Server may not be the same as you think it is from other .NET development.  Key things are creating derived classes, accessing the Web Service from the SSP and identifying the calling PWA instance and finally using the account that is running the SSP.

  19. Esfer says:

    Hi!!

    I’m having similar problem to this but trying to remove a Line Row from the TimeSheet.

    When I call the QueueUpdateTimesheet everything seems to be ok (in the cool data visualizer I can see the row has disappeared) but after the call every thing remains (no row deleted…).

    Do you know how should I do?

    Thanks 😉

  20. Hi Esfer,

    Do you see any errors or messages in the ULS logs?  What code are you using to remove the line?

    Best regards,

    Brian

  21. Laura says:

    Hi brian,

    I have an error when updating a customfield a project. The error is "LastError = ProjectHasWriteLock Instructions" and appears in the following line of code:

    projectDs = myproject.ReadProjectEntities (ProjGuid, 32, WebSvcProject.DataStoreEnum.WorkingStore);

    You know what is this error?

    Thanks

  22. Hi Laura,

    I am not familiar with this error.  Is the project checked out in another session?  Do you get this with all projects – all custom fields?

    Best regards,

    Brian.

  23. nunopostura says:

    Hi!

    I have a problem that i can’t resolve. I have to create a new line in a timesheet. To do that I use the msdn example but when a call PrepareTimesheetLine method, i always have GeneralObjectReferenceAlreadyExists error. When I pass this into PSIerror the UID concerned with the error is the UID created with this line:

    newLine.TS_LINE_UID = Guid.NewGuid();

    I tried to create a new project and just use the msdn code but i get an error when I execute this line:

    AdminWebSvc.TimesheetLineClassDataSet tsLineClassDs = adminSvc.ReadLineClasses(WindowsFormsApplication1.AdminWebSvc.LineClassType.AllNonProject, WindowsFormsApplication1.AdminWebSvc.LineClassState.Enabled);

    I have to use impersonation???

    The msdn code example should work well, shouldn’t?

    Thks

    Nuno Coelho – PT

  24. Hi Nuno,

    The MSDN code should certainly work – although it will rely on the user context in some cases, and other PWA settings such as the configured line classes for timesheets.  Are these things that work fine for you as a user through the UI?

    Best regards,

    Brian.

  25. nunopostura says:

    Hi Brian!,

    Thanks for the response.

    I can create timesheet lines throw PWA.

    In my code everything is cool with the timesshet dataset. The new line is sucessfully created at dataset but when I call PrepareTimesheetLine method I get GeneralObjectReferenceAlreadyExists error.

    The code is that on:

    //TIMESHEET DATASET fill

    line.TS_UID = LinhaTimeSheet.TS_UID;

    line.TS_LINE_UID = Guid.NewGuid();

    line.TS_LINE_CLASS_UID = tsLineClassDs.LineClasses[0].TS_LINE_CLASS_UID;

    line.TS_LINE_COMMENT = "Added by code sample.";

    line.TS_LINE_STATUS = (byte)PSLib.TimesheetEnum.LineStatus.NotApplicable;                         line.TS_LINE_VALIDATION_TYPE = (byte)PSLib.TimesheetEnum.ValidationType.Unverified;

    line.TS_LINE_CACHED_ASSIGN_NAME = tsLineClassDs.LineClasses[0].TS_LINE_CLASS_DESC;

                                   timeSheet.Lines.AddLinesRow(line);

                                   Report.Program.timesheet.PrepareTimesheetLine(LinhaTimeSheet.TS_UID, ref timeSheet, new Guid[] { line.TS_LINE_UID });

    Thks

    Nuno Coelho

  26. nunopostura says:

    Thks Brian!

    I’ve discover the issue.

    In the msdn example we have that line:

    line.TS_LINE_CLASS_UID = tsLineClassDs.LineClasses[0].TS_LINE_CLASS_UID;

    This retrieve the LinaCLassType "Administrative".

    I think that we just can have 1 Administrative time line, so, I have changed to Standart time (type of project tasks) and then everything works fine.

  27. Excellent!  Glad you worked it out Nuno – and thanks for the feedback.  If you think this will help others then feel free to post some community comments to MSDN.

    Best regards,

    Brian.

  28. nunopostura says:

    Hi one more time!

    I’m back 🙂

    I have a question related with "The number of hours in a standard timesheet day" that we can define in Timesheet Settings and Defaults.

    Can we access to thtat value programatically??

    Until now I can’t find a way to do that.

    Thanks

    Nuno Coelho

    PT

  29. Sorry Nuno,

    That setting isn’t available programmatically.  The best solution for these types of things is a PSI extension and getting it from the DB.  But don’t tell anyone I told you to access the DB directly…

    Best regards,

    Brian.

  30. nunopostura says:

    Thks Brian!

    An option, and maybe more correct, is access enterprise calendar to retrieve hours per day but I think that calendar information is just binary data and I can’t find a way to read that information.

    Can you help me?

    Thks

    Nuno Coelho

    PT

  31. nunopostura says:

    Hi Brian, one more time!

    I’m having problems with calendars because I want to read some information to make an integration with a human resource software.

    You know how to read that information or a place were some one can help me?

    Thks one more time

    Nuno Coelho

    PT

  32. Sorry Nuno,

    There isn’t a way to crack the binary for calendar information.  You may be able to do something via VBA in the client, and then push the data into a more readable format, but I haven’t tried this.

    Best regards,

    Brian.

  33. nunopostura says:

    Hi Brian!

    Are you saying that we cannot access any calendar information programatically?

    That’s a huge flaw in my opinion…

    Thks

    Nuno Coelho

    PT

  34. You can access the calendar exceptions Nuno – just you can’t tell what they are exceptions from…  And I don’t disagree with you.

    Best regards,

    Brian.

  35. nunopostura says:

    Hi Brian one more time!

    I have made a standalone windows form application and I want to make acessible from an activex.

    When a user acess to an option on pwa an alert will ask user to download the application.

    You know any tutorial with that type of informations?

    Thks

    Nuno

    PT

  36. Greg says:

    Hi,

    I’ve been looking all over the net and SDK’s but can’t find out how to insert items into a resource calendar programatically.

    Basically we have a leave system, when someone books leave, we’d like to update the resource calendar and make that resource as not available for the time period in which they are on leave.

    A code sample or some help on this will be great.

  37. Hi Greg, I don’t have a code sample to hand but can give some quick pointers.  When entering non-working time through the timesheet then this goes into the resources calendar as a calendar exception.  So doing this programmatically is one option.  Also this note is from the SDK about the Calendars web service:

    The UpdateCalendars method supports only calendar exceptions for enterprise calendars, not all enterprise calendar functionality in Microsoft Office Project Server 2007. You can add or delete time off for Project Server resources as calendar exceptions by using the [Resource Web service] namespace.

    This method does not modify enterprise calendar exceptions. If updates are required, you must delete and recreate calendar exceptions.

    Work weeks in enterprise calendars are not normalized in the Published database. Work week information is stored as binary data, so there are no direct queries available to load all calendar information to a CalendarDataSet.

    So the Resource web service is probably the best way to go.

    Best regards,

    Brian.

  38. Malik Al-Shayeb says:

    Hi

    I dont that my comment is much related to this topic but im hitting a dead ends , i want to create Material resources and i want to set the standard rate for this resource or i want to loop through the resources i already have and update the standard rate for them ,i tried to look for the property RES_Cost or RES_StandardRate but i found nothing can you help me with this please .

    Best Regards

    Malik Al-Shayeb

  39. S. Kochar says:

    I wish to understand if we could integrate Hyperion with Project server 2007 for time management. Client wants to use Hyperion for time management and import export within these systems. my email id is sabby777@gmail.com

  40. Cheers,

    Anyone know of the proper way to edit Resource Plan assignments using the PSI?

    I can retrieve the resource plan using something like this:

    ResourcePlanDataSet resplans = planService.ReadResourcePlan(String.Empty,

                       new Guid(e.CommandArgument.ToString()), DateTime.Now, DateTime.Now.AddMonths(1), (short)TimeScaleClass.TimeScale.Days, true, false);

    But question #1: what is the proper way to access the actual assignments? I can find the assignments in this array: resplans.PlanResources[0].ItemArray (first resource), but is this the only way?

    Question #2: what if I want to update the values? Making changes to the values in ItemArray doesn’t work.. nothing gets changed and nothing changes when looking at the object in the data visualizer.

    Best regards 🙂

  41. Christian says:

    To Maik:

    I had the exact same problem with the RemoveCalendarExceptionsRow method and finally worked out a solution for it, i created a small blogpost about it here if you (and others) are interested:

    technicaltrix.blogspot.dk/…/project-server-2010-psi-calendar.html

    –Reply to

    –Maik:

    –i´m trying to delete a CalendarExceptionsRow from the ResourceDataSet.CalendarExceptions table. But the

    –RemoveCalendarExceptionsRow() and Delete() methods don´t work for me.