I have been working at Microsoft nearly five months already. It is hard to believe how time flies! Yesterday a colleague made the comment “Your blog…what happened? Since you joined MS…no more blog?“ I didn’t intend to go dark, but I have been nonstop busy for five months. I thought I would take time today to start writing again.
Prior to joining Microsoft, I was busily working on “mpFx”, a PSI encapsulation project to enable IT developers getting started using the PSI quickly. That project has not stopped, but I haven’t been writing about it. In fact, the core mpFx libraries have become the centerpiece of many of my internal projects here at Microsoft.
Today I am going to do part I of an update on where mpFx stands, what scenarios it currently enables, and my future plans for the project.
Introduction to mpFx
Microsoft Project Fx (mpFx) version 1.0 is a class library that wraps the web services exposed by PSI in an effort to ease development of PSI applications, increase developer productivity, and reduce the amount of rework required to perform similar programming tasks across multiple projects. Beyond the 1.0 class library, mpFx is a collection of tools and technologies designed to increase developer productivity and ensure that Microsoft’s investment in Microsoft Project and PSI is embraced by developers tasked with designing solutions around Microsoft Project.
Version 1.0 of mpFx consists of two class libraries and a Windows Presentation Framework application for testing:
Class Library: CodePlex.MicrosoftProject.mpFx – This class library houses the PSI encapsulation
Class Library: CodePlex.MicrosoftProject.mpFx.WinForms – This class library contains a series of WinForms dialogs I created for performing common functions such as checking in a project, selecting custom fields, or editing project properties. The class library is a “common controls” library for PSI. Another class library is forthcoming that will provide these same common controls in WPF
WPF Application: Mops Browser – This Windows Presentation Foundation application is a test harness for the entire suite.
The PSI is implemented as series of web services each housing related methods and types. The CodePlex.MicrosoftProject.mpFx class library exposes PSI data and functionality through an object model, thus obscuring the underlying complexity of rigging and calling the web services directly. The class library also provides logging, object factories, and other services to the developer. While not appropriate for certain development scenarios, the object model pattern provides a concise and easily understood strategy for consuming PSI data and functionality.
Example: Standard PSI Usage Pattern
Here is a sample from the SDK which creates a project and waits for the queued project creation task is complete:
Here is the same thing in mpFx:
First, it is a lot more compact and secondly it is much easier to read. Let’s walk through what is going on under the covers.
- The first constructor in the image to the left is used for constructing an instance of ProjectServer using forms authentication.
The second constructor is used when using the local web service paths (http://server:port/shared service provider/psi/webservice.asmx), typically for impersonation.
The third constructor is used much as the second except rather then querying SharePoint for the site GUID, the site GUID is a parameter. This is useful for achieving a small performance gain.
Finally, the forth constructor and the one used in the sample, constructs an instance of ProjectServer for Windows authentication.
All constructors specify the store (published, draft, etc) on which operations subsequently are executed.
ProjectServer implements IDisposable.
Let’s take a look at the source for the forth constructor.
After inspecting URL, we jump into creating a small object ProjectServerSettings which houses default values for the session description, the number of retries to attempt on a queue wait operation, and the length of time to sleep between calls to query a job status:
Next, a containment object, WebServices, is created that houses a ServiceProxy instance for each PSI web service encapsulated in mpFx. Each web service is accessible as a property. Let’s take a look at the Projects property:
Each property is lazy-loaded to improve performance. Thusly, the first time the property is accessed, the _ProjectWebService (a proxy class) is created and initialized. We will touch on proxy classes in a minute, but first lets look at the calls to ConfigureService on lines 11 and 15. The parent object is inspected to see if the the current ProjectServer instance is being used in an impersonated call. Impersonation, as the name indicates, allows for the call to execute in the context of a specific user and requires that local web service paths be used (impersonating code can only be executed on the server machine). The local web service paths take the form http://server:port/shared service provider/psi/webservice.asmx. In the case of our example, we are not using impersonation so we go with the remote service paths, which take the form http://server/projectwebaccess/_vti_bin/psi/webservice.asmx. So, with that backgrounder, lets take a look at ConfigureService:
Note that the inbound service parameter in line 7 is of type HttpClientProtocol, which is the base class for all PSI web services. The method configures the web service according to the impersonation settings and the inbound service path. For reasons lost to me at this point, the method is actually rather convoluted and needs work but rather than fix it while I blog, I think I need to study why I wrote it that way first! This is one of the best things about blogging your own code: it is a self-analysis/code review for free!
As I mentioned earlier, proxy classes are next on our list. First, when you connect to a .NET XML web service using Visual Studio, the WSDL service description is used to a create a proxy class. These proxies are obscured in Visual Studio’s Solution Explorer, as noted in the image left, but you can easily access the source through File Explorer. In mpFx, the proxy is derived to support impersonation, which requires that an impersonation context be set and the GetWebRequest method must be overridden. Here is the ProjectProxy class:
In an impersonated call, the proxy’s impersonation context is set by calling the SetImpersonationContext on line 26. In an event, this context is an inbound parameter to the event receiver. In other situations, you must craft this context on your own.
Okay, back to our sample. The next thing is the EntityFactory, which offers clean semantics for instantiating the most common of PSI objects. In our sample, we are calling a simple overloaded method CreateProject:
As you can see, it is very simple but in the sample it makes it much more readable.
Okay, that’s it for this evening. Stay tuned for part II where we get in a little deeper.