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.