CustomFields.UpdateCustomFields2 Method

Creates, modifies, or deletes enterprise custom fields, where formulas are in a language-dependent format.

Namespace:  [CustomFields Web service]
Service reference: http://ServerName:32843/[Project Service Application GUID]/PSI/CustomFields.svc
Web service reference: http://ServerName/ProjectServerName/_vti_bin/PSI/CustomFields.asmx?wsdl

[SoapDocumentMethodAttribute("", RequestNamespace = "", 
	ResponseNamespace = "", 
	Use = SoapBindingUse.Literal, ParameterStyle = SoapParameterStyle.Wrapped)]
public void UpdateCustomFields2(
	CustomFieldDataSet cfds,
	bool validateOnly,
	bool autoCheckIn


Type: [CustomFields Web service].CustomFieldDataSet
CustomFieldDataSet contains the updated custom field definitions.
Type: System.Boolean
If true, validate only the CustomFieldDataSet.
Type: System.Boolean
If true, check in the custom fields after they are updated.

New method in Project Server 2010. UpdateCustomFields2 creates custom fields if the CustomFieldDataSet includes new custom fields, modifies existing custom fields, and deletes custom fields that are not in the CustomFieldDataSet.

Formulas in the CustomFieldDataSet that are used to calculate custom fields or graphical indicators can be written in the locale format specified in the Regional and Language Options control panel of the computer running Project Server. The UpdateCustomFields2 method saves the formulas in a language-independent format. By comparison, the UpdateCustomFields method saves the formulas without regard to the locale format.

Caution noteCaution

The UpdateCustomFields method and the UpdateCustomFields2 method, as well as Project Web App, all allow you to create an enterprise project custom field of type Flag, and set the custom field to be workflow controlled. However, Project Server workflows cannot control Flag custom fields. You should not set project custom fields of type Flag for workflow control.

Project Server Permissions




Allows a user to modify the definitions of enterprise custom fields and lookup table values. Global permission.

If the user did not check out the custom fields, UpdateCustomFields2 also requires administrative permissions to force check in.

The following example uses ReadCustomFieldsByMdPropUids and ReadCustomFieldsByMdPropUids2 to read a custom field, and then writes the customFieldDS contents to CustomFieldDataSet.xml and CustomFieldDataSet2.xml, respectively. Except for MD_PROP_FORMULA, the two methods return the same data.

For more information, including a procedure that shows how to use Project Web App and Project Professional 2010 with the same formula, see Using Formulas and Graphical Indicators with Custom Fields.

The formula field MD_PROP_FORMULA that is returned by ReadCustomFieldsByMdPropUids depends on the locale (the language of the server and the Project installation).and is shown in the following code.

<MD_PROP_FORMULA>Switch(Not ([MSPJ188743724] &gt;= #01/01/1984# And [MSPJ188743724] &lt; #01/01/2050#), 
"No Baseline", ([MSPJ188743685] + 1) / ([MSPJ188743686] + 1) &gt; 1.2, "Overbudget by 20% or more", 
([MSPJ188743685] + 1) / ([MSPJ188743686] + 1) &gt; 1, "Overbudget", True, "Under budget")</MD_PROP_FORMULA>

The formula field MD_PROP_FORMULA that is returned by ReadCustomFieldsByMdPropUids2 (as shown in the following code) is independent of locale. It works the same way on different language installations. For this reason, the ReadCustomFieldsByMdPropUids2 method is preferred over the ReadCustomFieldsByMdPropUids method.

<MD_PROP_FORMULA><MD_PROP_FORMULA>Switch(Not ([Baseline Estimated Finish] &gt;= #1/1/1984# And [Baseline Estimated Finish] &lt; #1/1/2050#), 
"No Baseline", ([Cost] + 1) / ([Baseline Cost] + 1) &gt; 1.2, "Overbudget by 20% or more", 
([Cost] + 1) / ([Baseline Cost] + 1) &gt; 1, "Overbudget", True, "Under budget")</MD_PROP_FORMULA>

Furthermore, the example modifies the formula and calls the UpdateCustomFields2 method to update the custom field, and then writes the updated dataset to UpdatedCustomFieldData.xml

It calls the CheckInCustomFields to check in the custom field after modification, and calls the CheckOutCustomFields to check out the custom fields before modifying them.

The example uses the SvcCustomFields namespace in the ProjectServerServices.dll proxy assembly. The ConfigClientEndpoints method and the SetClientEndpoints method use an app.config file for setting the WCF binding, behavior, and endpoint. For information about creating a PSI proxy assembly and an app.config file, see Prerequisites for WCF-Based Code Samples.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ServiceModel;

namespace Microsoft.SDK.Project.Samples.TestCustomFields
    class CustomFields
        private static SvcCustomFields.CustomFieldsClient customFieldClient;
        private static SvcResource.ResourceClient resourceClient;
        private const string RES_ENDPOINT = "basicHttp_Resource";
        private const string CUST_ENDPOINT = "basicHttp_CustomFields";
        private const string OUTPUT_FILES = @"C:\Projects\Samples\Output\";
        private static string outFilePathCustomFields;
        private static string outFilePathCustomFields2;
        private static string outFilePathCustomFields3;

        static void Main(string[] args)
                Guid[] customFieldID = new Guid[1];
                customFieldID[0] = new Guid("4bfa524a-ce48-4a31-a2d6-5e8baa6c9d29");


                // If directory does not exist, create it.
                if (!Directory.Exists(OUTPUT_FILES))

                // Assign the path where the output XML file will be saved.
                outFilePathCustomFields = OUTPUT_FILES + "CustomFieldData.xml";
                outFilePathCustomFields2 = OUTPUT_FILES + "CustomFieldData2.xml";
                outFilePathCustomFields3 = OUTPUT_FILES + "UpdatedCustomFieldData.xml";

                // Create a custom fields dataset. 
                SvcCustomFields.CustomFieldDataSet customFieldDS =
                    new SvcCustomFields.CustomFieldDataSet();

                // Read the custom fields data by using ReadCustomFieldsByMdPropUids.
                customFieldDS = customFieldClient.ReadCustomFieldsByMdPropUids(
                    new Guid[] { customFieldID[0] }, false);

                // Write the dataset to an XML file.
                Console.WriteLine("\nSee XML output of the CustomFieldDataSet at {0}",

                // Read the custom fields data by using ReadCustomFieldsByMdPropUids2.
                customFieldDS = customFieldClient.ReadCustomFieldsByMdPropUids2(
                    new Guid[] { customFieldID[0] }, false);

                // Write the dataset to an XML file.

                bool checkedOut = false;

                // Get the ID of the user.
                Guid me = resourceClient.GetCurrentUserUid();

                // Check whether the custom field to be updated is checked out.
                foreach (SvcCustomFields.CustomFieldDataSet.CustomFieldsRow custRow in customFieldDS.CustomFields)
                    if (custRow.MD_PROP_UID.ToString() == customFieldID[0].ToString())
                        if (custRow.IsNull("MD_PROP_CHECKOUTBY"))    // If the custom field is not checked out.
                            // Check out the custom field.
                            customFieldClient.CheckOutCustomFields(new Guid[] { custRow.MD_PROP_UID });
                            checkedOut = true;
                            Console.WriteLine("Custom field checked out.....");
                            // Check whether the custom field is checked out by you.
                            if (custRow.MD_PROP_CHECKOUTBY == me)
                                checkedOut = true;
                                Console.WriteLine("The custom field is already checked out by you");
                                // The custom field is checked out by some other user.
                                checkedOut = false;
                                Console.WriteLine("This custom field has already been checked out");
                if (checkedOut)
                    // Modify the formula field of the custom field.
                    // Type the following statement in a single line.
                    customFieldDS.CustomFields[0].MD_PROP_FORMULA =
                        "Switch(Not ([Baseline Estimated Finish] >= #1/1/1984# And [Baseline Estimated Finish] < #1/1/2050#), 
                        \"No Baseline\", ([Cost] + 1) / ([Baseline Cost] + 1) > 1.5, \"Overbudget by 50% or more\", 
                            ([Cost] + 1) / ([Baseline Cost] + 1) > 1, \"Overbudget\", True, \"Under budget\")";

                    // Update the dataset.
                    customFieldClient.UpdateCustomFields2(customFieldDS, false, false);

                    // Write the custom field data to an XML file.
                    Console.WriteLine("\nSee XML output of the CustomFieldDataSet at {0}",

                    // Check in the custom field.
                    customFieldClient.CheckInCustomFields(new Guid[] { customFieldID[0] }, false);
            catch (CommunicationException e)
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write("\r\n\r\nPress any key....");
        // Configure the custom field client endpoints.
        public static void ConfigClientEndpoints(string endpt)
            customFieldClient = new SvcCustomFields.CustomFieldsClient(endpt);
        // Configure the resource client endpoints.
        public static void SetClientEndpoints(string ept)
            resourceClient = new SvcResource.ResourceClient(ept);


The updated dataset, with the modified formula field MD_PROP_FORMULA, is written to UpdatedCustomFieldData.xml and is shown in the following code.

<?xml version="1.0" standalone="yes"?>
<CustomFieldDataSet xmlns="">
<MD_PROP_NAME>Budget Indicator</MD_PROP_NAME>
<MD_PROP_DESCRIPTION>Test for graphical indicator example in SDK</MD_PROP_DESCRIPTION>
<MD_PROP_FORMULA>Switch(Not ([Baseline Estimated Finish] &gt;= #1/1/1984# And [Baseline Estimated Finish] &lt; #1/1/2050#), 
"No Baseline", ([Cost] + 1) / ([Baseline Cost] + 1) &gt; 1.5, "Overbudget by 50% or more", 
([Cost] + 1) / ([Baseline Cost] + 1) &gt; 1, "Overbudget", True, "Under budget")</MD_PROP_FORMULA>
<MD_PROP_GRAPHICAL_INDICATOR>[[==No baseline][5]][[==Overbudget by 50% or more][3]]
[[==Overbudget][2]][[==Under budget][1]]</MD_PROP_GRAPHICAL_INDICATOR>
<MD_PROP_SUMM_GRAPHICAL_INDICATOR>[[==No baseline][5]][[==Overbudget by 50% or more][3]]
[[==Overbudget][2]][[==Under budget][1]]</MD_PROP_SUMM_GRAPHICAL_INDICATOR>
<MD_PROP_PROJ_SUMM_GRAPHICAL_INDICATOR>[[==No baseline][5]][[==Overbudget by 50% or more][3]]
[[==Overbudget][2]][[==Under budget][1]]</MD_PROP_PROJ_SUMM_GRAPHICAL_INDICATOR>