Friday, March 26, 2010

Project Server 2010 - Accessing Intrinsic Fields

MS Project Server (PS) product allows to store and manage three main types of entities: Project, Resource and Task. These entities have out-of-box descriptive (instrinsic) fields, i.e., Name, Unique ID, Start Date etc. If the user needs to extend any of these entities with some additional attribute, it is possible to do this with Custom Field – the field related to the entity. This can be done manually through the PWA site or using the CustomFields.asmx PSI web service. The values stored in these fields can be shown on Project Details Page (PDP) with help of the Project Fields Part webpart. In Edit mode user can select which fields should be shown in it. The goal of this article is to show the way how to access the list of all project-related intrinsic and custom fields as it is done in the Project Fields Editor Part.

The CustomFields.asmx PSI web service allows users to access the list of all custom fields related to PS entity. But if the user needs to get the information regarding intrinsic field (to read its name, type, to check whether it is required etc.), he has to go other way. One of non-public PSI web services is named View.asmx. It can be reached by the following URL:


The list of both intrinsic and custom fields can be received using ReadPortfolioFields web method. Anyway it won’t tell if the fields are globally required, so in case of custom field it is possible to use the CustomFields.asmx service for this purpose; in case of intrinsic fields you should hardcode them (Name and StartDate project native fields are required). For some reason the Description intrinsic field is not returned by ReadPortfolioFields method, so it has to be manually added to the results list.

Here is the code sample how these actions can be performed with the View PSI web service:

var pwaView = new View();
pwaView.Url = "http://server/pwa/_vti_bin/View.asmx";
pwaView.Credentials = System.Net.CredentialCache.DefaultCredentials;
using (var dsViewFields = _pwaView.ReadPortfolioFields())
    var requiredNativeFields = new List<Guid>
        new Guid("{8452F6A8-BC6C-4367-8836-A6AE55BBDDA4}"),
        new Guid("{3317C796-5FA1-4231-9212-A4C90A2CE05F}")

    var fields = dsViewFields.ViewFields.Rows
        .Select(row =>
                Uid = row.WFIELD_UID,
                Name = !row.IsMD_PROP_NAMENull()
                       ? row.MD_PROP_NAME
                       : !row.IsCONV_STRINGNull()
                           ? row.CONV_STRING
                           : "UNKNOWN FIELD",
                IsGloballyRequired = requiredNativeFields.Contains(row.WFIELD_UID)
                                     || IsCustomAndGloballyRequired(row.WFIELD_UID)

            Uid = new Guid("837AAFA9-FA1A-49C0-8A08-6B007865991B"),
            Name = PJUtility.GetLocalizedString(
                 new object[0]),
            IsGloballyRequired = false

The implementation of IsCustomAndGloballyRequired method is expected to use the CustomFields.asmx PSI web service. ReadCustomFieldsByEntity web method can be used there. Read more...

Tuesday, March 9, 2010

FluentPS Quick Start Videos created

Hello Everyone,

We've created a Quick Start video on how to use FluentPS library to operate with Project Server 2010 PSI (Project Server Interface). We'll show how to perform READ/UPDATE operations of project Native and Enterprise Custom fields with help of simple .NET class.

The source code and binaries of FluentPS project can be downloaded here:

Quick Start video:

Enterprise Custom Fields mapping:


Wednesday, March 3, 2010

Programmatic deployment of Workflow-controlled EPT

In the previous article we’ve shown the way how to programmatically create a Workflow Association. Here you can find the description of programmatic creation of Workflow-controlled EPT.

When you have deployed the Workflow Association, it is possible to create an EPT programmatically. This action can be performed in FeatureActivated overridden SharePoint feature method as well. The Workflow PSI web service should be used for this purpose. Here is the code sample:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
    var site = (SPSite)properties.Feature.Parent;
    var pwaWorkflow = new Workflow();
    pwaWorkflow.Url = string.format("{0}/_vti_bin/psi/Workflow.asmx"),site.Url);
    pwaWorkflow.Credentials = System.Net.CredentialCache.DefaultCredentials;

    using (var dsProjectType = pwaWorkflow.ReadEnterpriseProjectType(Guid.Empty))
        WorkflowDataSet.EnterpriseProjectTypeRow row = 

        //Fill EPT Row
        var wfAssociationName = "[Your_WF_Association_Name]";
        row.WORKFLOW_ASSOCIATION_UID = GetWorkflowUidByName(wfAssociationName);
                row.WORKFLOW_ASSOCIATION_NAME = wfAssociationName;



private Guid GetWorkflowUidByName(Workflow pwaWorkflow, string workflowName)
    using (var dsWorkFlow = pwaWorkflow.ReadWorkflows())
        return dsWorkFlow.WorkflowAssociation.Rows
            .First(row =>
                   row.WORKFLOW_ASSOCIATION_NAME == workflowName)

As it is shown in the code, you should use the ReadWorkflows method of Workflow.asmx web service to reach the ID of Workflow Association. Then you should set the WORKFLOW_ASSOCIATION_UID and WORKFLOW_ASSOCIATION_NAME properties of the EPT row. All other EPT properties should be filled out as usual.

IMPORTANT: If you have your EPT Workflow-controlled, it should have no PDPs attached. If you have to make existent EPT Workflow-controlled, you should first remove PDPs associations for this EPT, and then set WORKFLOW_ASSOCIATION_UID / WORKFLOW_ASSOCIATION_NAME properties.