Welcome to MSDN Blogs Sign in | Join | Help

Larry's Project Dev Blog

The musings of developing for Microsoft Project.
Larry Has Left the Building...

Last April I took a new job at Microsoft as a consulting manager.  This means my Project Server development has been shrinking toward zero (obviously you can't let managers write code).  I still get questions from people periodically from my blog.  I realized that I never really announced that I wasn't maintaining this blog anymore. 

So here is the announcement... Larry Has Almost Left the Building.  OK, why almost? 

One of the last things I did for the Project team was to write a solution starter.  Hopefully it will be posted to CodePlex very soon, I understand there are some bureaucracy to get through before it gets posted.  But I was asked to do a session at the Project Conference on Line of Business Integration with EPM.  Part of this session will be to review the solution starter that I wrote.  After Project Conference in October (or December if I go to the European Project Conference) I will be leaving the building.

I've enjoyed watching Project Server go from 25 methods (Project Server 2002), to a full blown API with eventing (Project Server 2007).  Most of all I've enjoyed working with the hundreds (maybe thousands) of partners and customers around their development issues over the last five years.  I'm confident the base we laid with Project Server 2007 will only be enhanced with the next release.  I wish everyone the best... stop by and say hi if you're at Project Conference.

 P.S. The link section on my blog has some of the other Project related blogs listed that you should find helpful.

 

TechEd 2007 Presentation

I got a request over a month ago for my presentation from TechEd.  I missed the request buried in the thousands of spam comments I get :(.  So attached is the deck, you already have the samples in previous posts.

Under the Godfather heading of "Everytime I get out they pull me back in" I thought TechEd 2007 was my last speaking engagement for the Project team.  Well as it turns out I'll be speaking at the Project Conference 2007 in Seattle, and possibly and the European Project Conference in Madrid.  So I'll see you everyone at Project Conference.

 

TechEd 2007 - Sample 3
This is the final sample from my TechEd presentation.  It's an event that captures the Project Published.  When the event is triggered, the project being published is read, then output as an Xml file.
TechEd 2007 - Sample 2
Here we go with the second sample, the Project Server Explorer.  This sample opens a list of projects.  Then you can look through all the propoerties and DataSets for a selected project.  The key was binding the columns in the DataSets to controls.
TechEd 2007 - Sample 1

This year at TechEd I'm delivering the following session:

Code

Title

Date/Time

OFC339

Enterprise Project Management: Developer Options

6/8/2007 10:45AM-12:00PM

As Project and Portfolio Server are deployed in many enterprise scenarios it is important to understand their integration capabilities with line-of-business systems (like SAP). This session provides you with an overview of Project and Portfolio Server 2007 Development features like PPSI (Project Portfolio Server Interface), PSI (Project Server Interface), Server Side events, and Workflows developed with Windows Workflow Foundation.

 

While giving this session I’ve added in the following code demos:

Demo

Description

From SDK?

PPSI General

Looking at what is available through the PPSI

Yes

PSI General

Creating and updating a project

No

PSI Dataset

Spelunking through the custom datasets

No

Events

A custom event handler

No

PWA Customization

A custom web part for PWA

Yes

 

It would be silly for me to post code for SDK samples.  So I’ll leave finding them in the SDK as an exercise for the reader.  BTW all my samples are designed to run against the Litware demo database included in the EPM VM.

In this post I’m putting the PSI General sample, CreateProject.  The sample creates a project with some tasks, then publishes it.  Finally it adds some enterprise resources to the project.  As with all samples, the code is not production ready, is meant to illustrate concepts not necessarily best code practices, and should not be deployed as is or Mr Biggins will put you in the comfy chair.***  Most of the calls are standard faire for PSI, but some of the utility methods I put in may prove useful for your work.  The C# project is attached in a zip file.

 

*** (Watch some Monty Python’s Flying Circus if you don’t understand the reference)

Hanging at TechEd This Week

Hi All,

It's been a while since I posted.  Well there are two really good reasons for that

1)      I've was working on two really big development projects

2)      I left the Project team a few months back.

On the leaving, I'm still doing some part time work for the Project team through the end of June till a replacement is in place.  One of the things I agreed to do before I took my new job was speak at TechEd.  I'm here all week in Orlando working the booth, and I speak Friday morning on developing in Portfolio Server and Project Server.  If you are in sunny Orlando for TechEd this week look me up in the Project booth.  Also I'll be posting all my samples that I'm using Friday in some posts later in the week.

On the big projects, the first one is the EPMSync tool.  If you have the EPM virtual machine you may have seen this mysterious tool.  In a nut shell it does an item level sync from Portfolio Server to Project Server.  Final release of the tool should be in the next month if we post it to codeplex (http://www.codeplex.com/) or a bit longer if it gets published as an MSDN solution starter.  In any case there is some pretty detailed code in there for handling Project updates, specifically around custom fields and lookup tables.  Sorry to you VB.Net guys, it's all written in C#.

My second big project is an installation tool for our demo database for Project Server 2007.  This became a really big project because restoring a demo installation is a big job.  Everything from restoring databases, creating shared service providers, relinking SharePoint sites to Project Server, etc... you get the picture.  Doing this by hand takes patience and understanding.  Doing this programmatically is a herculean challenge.  I stalled for a month because the code for restoring WSS sites quit working.  To make a month long story short I found out that some calls to STADM get a new signature when you install MOSS.  Again this will either go with the SDK, TechNet, or Code Plex.  There hasn't been a decision if the source code will be published.  But if it is the code is published, its C# with lots of good tips built in.

It's almost midnight here, and I'm still on Pacific time (i.e. not really tired).  But off I go to try to sleep.  Watch for the TechEd sample in later posts.

 

 

Creating an Extended Project List

Happy New Year all!  I had a really nice holiday break at the end of December, I hope you all did too.  As the New Year has dawned, so have more questions around Project Server 2007 development.  I’ve actually been doing quite a bit of development on Project Server for a solution accelerator to Project Portfolio Server.  Along with the questions, my solution accelerator has given me a number of ideas for posts, it’s just a matter of having time to get them “down on paper.”

One recurring use case is displaying a list of projects with their start and end dates (or any other basic information about a project like owner).  After reading the SDK many people think that you can make just one call to get this information, even though the SDK is pretty good at pointing out you can’t, if you read deep enough.  But heck we’re developers, we only read the whole page after something doesn’t work on the first try ( or after we debug it and can’t tweak it to work).  The truth is you have to make one call to get the list of projects, followed by one call for each project to get the additional information.

So our first call would be the ReadProjectList…  watch out not so quick.  ReadProjectList is more intended for administrative application, it requires pretty high security clearances, ManageQueue and ManageSecurity privileges.  The correct call here would be to ReadProjectStatus, which will return projects based on the current users permissions.  I know, it’s a little convoluted, but don’t shoot the messenger.  Here is an example of what that call might look like:

    ProjectWS.ProjectDataSet readProjDs = projectSvc.ReadProjectStatus(Guid.Empty,

        ProjectWS.DataStoreEnum.PublishedStore, string.Empty,

        (int)PSLibrary.Project.ProjectType.Project);

 

Our second call will be to loop on the returned dataset for each project.  In the loop we will request the specific information for each project.  To get the full dataset for a project we call ReadProject.  Here is a sample:

    foreach (ProjectWS.ProjectDataSet.ProjectRow project in readProjDs.Project)

    {

        currentProjectDS = projectSvc.ReadProject(project.PROJ_UID,

            GetProjectList.ProjectWS.DataStoreEnum.PublishedStore);

        curProj = currentProjectDS.Project[0];

        Console.WriteLine(String.Format("{0} Starts {1}, Completes {2}",

            curProj.PROJ_NAME, curProj.PROJ_INFO_START_DATE.ToLongDateString(),

            curProj.PROJ_INFO_FINISH_DATE.ToLongDateString()));

    }

 

 The issue here is that ReadProject brings back the complete dataset, and we really only want a couple extra pieces of data from the Project table.  There is a solution, use the ReadProjectEntities method.  Think of ReadProjectEntities as ReadProject but with a filter on it, and conveniently a filter that you don’t need to build.  If we modified the above sample to use ReadProjectEntities it might look like this:

    foreach (ProjectWS.ProjectDataSet.ProjectRow project in readProjDs.Project)

    {

        currentProjectDS = projectSvc.ReadProjectEntities(

            project.PROJ_UID, PROJECT_ENTITY_TYPE_PROJECT,

            ProjectWS.DataStoreEnum.PublishedStore);

        curProj = currentProjectDS.Project[0];

        Console.WriteLine(String.Format("{0} Starts {1}, Completes {2}",

            curProj.PROJ_NAME, curProj.PROJ_INFO_START_DATE.ToLongDateString(),

            curProj.PROJ_INFO_FINISH_DATE.ToLongDateString()));

    }

 

We now have an extra parameter to deal with called ProjectEntityType.  The ProjectEntityType is really useful because you can combine the values together to get groups of entities.  For example you could get the project and custom field tables only.  Look in the Project Server 2007 SDK for further information on what values can be used as entity types.

I hope everyone finds this useful.  Attached is the complete code sample for your consumption.

 

Testing Columns in a DataSet

I ran into a nasty little surprise the other day.  I was writing some code to see if a Project has a WSS site associated with it.  So here is the code that I’ve cut down for brevity:

        private string GetWSSSite(Guid projectGuid)

        {

            ProjectWS.ProjectDataSet pds =

              ProjWebSvc.ReadProject(projectGuid,

              ProjectWS.DataStoreEnum.PublishedStore);

            ProjectWS.ProjectDataSet.ProjectRow pr = pds.Project[0];

            string WSSSite = pr.WPROJ_STS_SUBWEB_NAME;

            if (WSSSite.Length == 0)

                return String.Empty;

            else

                return WSSSite;

        }

 

Essentially I read the project, and then either pass back the subweb name or an empty string.  The only problem was the routine was throwing an exception.   I bet you can’t guess which line was throwing the exception…. give up?  It was the assignment of the WSSSite.  I was getting a System.Data.StrongTyping exception.  When I started to debug and dig it thing became a little clearer.  It seems I ran across a project that did not have a subweb associated with it.  Since the DataSet is built directly from the database tables, the column WPROJ_STS_SUBWEB_NAME was DBNull.  The DBNull brought on the StrongTyping exception.  To work around this I modified the code as follows:

        private string GetWSSSite(Guid projectGuid)

        {

            try

            {

                ProjectWS.ProjectDataSet pds =

                  ProjWebSvc.ReadProject(projectGuid,

                  ProjectWS.DataStoreEnum.PublishedStore);

                ProjectWS.ProjectDataSet.ProjectRow pr = pds.Project[0];

                return pr.WPROJ_STS_SUBWEB_NAME;

            }

            catch (System.Data.StrongTypingException ex)

            {

                return String.Empty;

            }

        }

 

So the lesson here is when testing column value be careful they may throw an exception.  To get a better idea of where you may encounter problems you can go into debug mode and put a breakpoint after you fill the DataSet.  If you look through the row in watch mode you will see a number of exceptions.  See the attached picture for illustration.

Also note in the code above you should be testing for exceptions from the ReadProject call, but I removed that to better illustrate the column exception.

 

Project Server 2007 SDK

Sorry I missed posting that the Project Server 2007 SDK is now live... that's what happens you you take some vacation :).

·         SDK Download: http://www.microsoft.com/downloads/details.aspx?FamilyId=2672F6F9-7028-4B30-99A2-18CB1EED1ABE&displaylang=en .
The pj12ProjectSDK.exe download includes:

o   pjSDK2007.chm (conceptual topics and managed code reference)

o   pj12ReportingDB.chm (Reporting database schema reference)

o    OLAPCubeSchemas.xls lists the dimensions, measures, and properties of the Project Server OLAP cubes

o    SDK code samples, including the updated ProjTool source and executable.

·         SDK Online: Project 2007 SDK in MSDN online library: http://msdn2.microsoft.com/en-us/library/ms512767.aspx

·         Portal:  Project Developer Portal in the Office Developer Center on MSDN includes links to the Project 2007 SDK,  Project 2007 blogs, as well as the Project 2003 SDK. Following are the other main pages in the Project Developer Center:

o   What’s New for Developers in Project 2007 includes links to MSDN Webcasts.

o    Project Community includes an RSS feed for the Project 2007 Team Blog, and other Project blogs and sites.

 

How do I Create a Project Server User?

This post started with a pretty innocuous email that I thought had an innocuous answer too.  But you know if I’m writing about it here, it got a little challenging. 

 

The question of the day is what is a Project Server User?  A Project Server user is a resource that has rights to login to Project Server… right?  Not quite, you can be a user, but not a resource.  If I’m coming up to Project Server for the first time what can the administrator do for me in the system?

Type

Capability

Resource

Assigned to tasks

User

Can login in the Project Server, but get no assignments.

Resource & User

I can enter my own time for assignments directly in PWA

 

Setting up a person to interact with Project Server 2007 is pretty straightforward in the user interface.  This shows you were to go for creating the different interactions:

Type

Destination

Notes

Resource

Project Center->New Resource

Uncheck “Resource Can Login to Project Server”

User

Server Settings->Manage Users -> New User

Uncheck “User Can be assigned as Resource”

Resource & User

Project Center->New Resource ()

Be sure to fill in the User Authentication Area

 

That’s is all fine, but this is a development Blog, not a How-to on the UI J.  Resource creation is intuitive and comes quickly, so let’s start there.

 

Resource Only

First you need a web reference to the Resource Web Service:

http://yourserver/pwa/_vti_bin/psi/resource.asmx

 

Adding a Resource consists of:

·         Creating a ResourceDataSet

o   Don’t forget to create a ResourceRow that is added back to the ResourceDataSet

·         Filling the ResourceDataSet

o   What columns are important here?  RES_UID, RES_NAME, RES_TYPE

o   If this is a people resource the RES_TYPE would be WorkResource, find all the resource types in the Project Server Library assembly.

·         Calling the Resource Web Service method CreateResources

 

Here is the code sample for the above workflow:

resDs = new ResourceWS.ResourceDataSet();

ResourceWS.ResourceDataSet.ResourcesRow resourceRow =

  resDs.Resources.NewResourcesRow();

Guid NewResGuid = Guid.NewGuid();

resourceRow.RES_UID = NewResGuid;

resourceRow.RES_NAME = Name;

resourceRow.RES_INITIALS = Name.Substring(0, 1) +

  (Name.IndexOf(" ") > 0 ?

  Name.Substring(Name.IndexOf(" ") + 1, 1) : "");

resourceRow.RES_TYPE = (int)PSLibrary.Resource.Type.WorkResource;

resourceRow.RES_GROUP = "Team Members";

resourceRow.WRES_EMAIL = “test@test.com”;

resDs.Resources.AddResourcesRow(resourceRow);

 

ResSvc.CreateResources(resDs, false, true);

 

Resource & User

I’ve got a resource, now we’ll upgrade them to be a user too.  I’ll be honest that I’ve created 100s of resources for demo purposes, but really never considered how to make them users. 

 

My first try I saw the columns RES_IS_WINDOWS_USER and WRES_ACCOUNT , I figured set them and the resource would now be a user too.  Wrong, they had no effect… in fact they were completely ignored, no error, no exception.  I discovered later those columns are read-only much like the notes field I discussed in an earlier post.

 

From working with some of the other Project custom DataSets I knew that there are “sub” DataSets (tables) that sometime need to be set.  I started looking through there (Rates, Abilities, CustomFields, etc.) with nothing really jumping out.

 

Next I went back to the API.  First looking at the Resource Web Service I see ReadUserList and GetCurrentUserID, both look related this may be promising.  But that’s it… no UpgradeToUser, MakeResourceUser, nada, nothing, zero.  Well there are other web services too.  How about the Admin web service, that could make sense, nope.

 

At this point I got to tell you I’m pretty disappointed that I cannot find a solution.  So I trek down the hall to find someone from the product team to fix my pain.  I encounter three guys that know a ton about the API in the hall heading out the door.  I ask my question, in almost unison they say you have to set the authorization, chuckle, and take off.  I get the feeling they’ve heard this question before and know it wasn’t a readily available answer.

 

Back to the DataSet, I see a ResourceAuthorizationDataSet, but there is no relationship to ResrouceDataSet that I see.  Then I notice in the API SetResourceAthorization.  From that point the heavens opened and the angles sung… and I had a code sample to share with you:

 

private void AddAuthorization(Guid resourceUid, string Account, bool WindowsUser)

{

ResourceWS.ResourceAuthorizationDataSet resourceAuthDs = 

  new ResourceWS.ResourceAuthorizationDataSet();

ResourceWS.ResourceAuthorizationDataSet.ResourcesRow resourceAuthRow =

  resourceAuthDs.Resources.NewResourcesRow();

resourceAuthRow.RES_UID = resourceUid;

resourceAuthRow.RES_IS_WINDOWS_USER = WindowsUser;

resourceAuthRow.WRES_ACCOUNT = Account;

resourceAuthDs.Resources.AddResourcesRow(resourceAuthRow);

ResSvc.SetResourceAuthorization(resourceAuthDs);

}

 

Pairing up creating the resource with adding the authorization… you have a resource that can login.

 

User Only

 

How about a pure user? I’m happy to report that is pretty simple.  Use the same code for resource create and authorization addition, but set the RES_TYPE to PSLibrary.Resource.Type.PureUser.

 

Attached is a sample that does everything described above.  Just change the name of the server to match yours and you’re ready to go.

 

Microsoft Office Project Bug Bash - WINNERS

Thank you to everyone who participated in the Microsoft Office Project Bug Bash Beta 2 Technical Refresh (2TR) Challenge, you have been instrumental in making this contest a great success.  Below are the winners that have been selected in the three Challenge Categories:

 

Most Bugs Submitted

Grand Prize: Winner would like to remain anonymous

1st Prize: T. Simon*

2nd Prize: D. Luis*

3rd Prize: A. Angas

 

Most Interesting/Unique Bug Submitted

Grand Prize: J. Flavin

1st Prize: S. Haffner

2nd Prize: Tim Johnson

3rd Prize: P. vander Borne*

 

Most Critical Bug Submitted

Grand Prize: V. Bogdanov

1st Prize: H. Hoet*

2nd Prize: H. Tifti*

3rd Prize: M Claxton

 

* Please note that these winners are pending verification of eligibility and confirmation of prize acceptance.

Project Server 2007 Beta 2 TR VM

I usually don't announce the availability of the Project Server 2007 VMs on my blog.  But since the beta program is closing down, it hasn't really been announced anywhere else.  So… (trumpets sound)…  the Project Server 2007 Beta 2 TR VM has been available on BetaPlace for all the beta participants for about a week.  Look for it under "Other" files.  For some reason the Beta 2 VM is still available on the main screen and it makes for some confusion in finding the new VM.

Some of you may have heard but BetaPlace for Office 2007 closes at the end of this month.  But fear not there will still be a place to find information, Microsoft Connect.  The Microsoft Connect site is a new post RTM community area and has a dedicated section for Project.  I have been told that the Beta 2 TR VM will be posted for download from Connect in the beginning of November.  If any of you don't have access to BetaPlace, or for beta participants after Nov 1st, this will be your opportunity to grab the VM.

 

PS2007 Project Details (VBA)

Fourth post, I think this is it.  We started with C#, what you normally see the Project Server samples in.  We shifted to VB.Net and realized the difference wasn’t too significant.  Then we moved into JavaScript, which proved to be challenging.  Finally we are moving into VBA/VB6.

The sample I wrote is for VBA in Excel.  I had requests for both VB6 and VBA.  I decided that VBA would get across the point of using the Visual Basic syntax, without having to struggle to get a UI up.  I used the JavaScript sample as the starting point, and ported from there.  There was a bunch of syntactic changes (duh!), but the logic stayed the same.  I replaced writing the data into tables with writing them to worksheets.  To load the sample up in Excel, open the macro editor and add the attached file to it. 

How does the sample work?  First update the server name to reflect your server.  Then run the GetProjectList macro.  It will populate the current sheet with Project names and Guids.  Select the cell of the Guid for the Project you want to see details on, run the DisplayProjectDetails macro.  A new sheet will appear with all the Project detail information.

There isn’t really anything here that isn’t in the JavaScript sample… using XMLHTTP, consuming datasets with XMLDOM, and traversing the DOM to load up the cells.  I did write a neat routine to determine if a string is a Guid (kind-of a waste of time seeing I could have done the same thing in .Net using regular expressions in less than half the code.)