CustomFields.ReadCustomFields2 method

Gets enterprise custom field definitions, where formulas are in a language-dependent format.

Namespace:  WebSvcCustomFields
Assembly:  ProjectServerServices (in ProjectServerServices.dll)


<SoapDocumentMethodAttribute("", RequestNamespace := "",  _
    ResponseNamespace := "",  _
    Use := SoapBindingUse.Literal, ParameterStyle := SoapParameterStyle.Wrapped)> _
Public Function ReadCustomFields2 ( _
    xmlFilter As String, _
    autoCheckOut As Boolean _
) As CustomFieldDataSet
Dim instance As CustomFields
Dim xmlFilter As String
Dim autoCheckOut As Boolean
Dim returnValue As CustomFieldDataSet

returnValue = instance.ReadCustomFields2(xmlFilter, _
[SoapDocumentMethodAttribute("", RequestNamespace = "", 
    ResponseNamespace = "", 
    Use = SoapBindingUse.Literal, ParameterStyle = SoapParameterStyle.Wrapped)]
public CustomFieldDataSet ReadCustomFields2(
    string xmlFilter,
    bool autoCheckOut


  • xmlFilter
    Type: System.String

    Limits the amount of data returned.

  • autoCheckOut
    Type: System.Boolean

    If true, check out the custom fields for modification.

Return value

Type: WebSvcCustomFields.CustomFieldDataSet


A new method in Project Server 2010. If a custom field or graphical indicator is calculated by a formula, the ReadCustomFields2 method converts formulas in the returned CustomFieldDataSet to a format that depends on the locale specified in the Regional and Language Options control panel of the computer running Project Server. By comparison, the ReadCustomFields method returns a CustomFieldDataSet where formulas are independent of locale.


For Project Server 2010, the returned CustomFieldDataSet can include the Relative Importance custom field and the Project Impact custom field. Project Web App does not show these custom fields in the Enterprise Custom Fields and Lookup Tables page, because they are built-in for portfolio analyses and cannot be modified or deleted.

. For more information, see How to: Use a Filter Parameter with PSI Methods

Project Server Permissions




You must have either the ManageWorkflow global permission or the ChangeWorkflow global permission. If you have ChangeWorkflow permission, you must also have both the OpenProject category permission and the SaveProject category permission.


Allows a user to connect to the Project Server database from Project Professional. Global permission.


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


Allows a user to manage Project Server users and groups. Global permission.


Allows a user to create a project. Global permission.


Allows a user to view resource allocation data. Global permission.


The ReadCustomFieldsTest sample does the following:

  • Reads all custom fields in the Project Web App installation that is specified by the endpoint address in the app.config file, and then writes an XML file of the CustomFieldDataSet.

  • Reads lookup table data for the specified language LCID, and then writes an XML file of the LookupTableDataSet. The lookup table XML data includes collections of the following tables: LookupTables, LookupTableMasks, and LookupTableTrees.

For information about using the code sample in a Microsoft Visual Studio 2010 project and creating an app.config file for configuration of the WCF endpoints, see Prerequisites for WCF-based code samples in Project 2013.

using System;
using System.Text;
using System.ServiceModel;
using System.Xml;
using PSLibrary = Microsoft.Office.Project.Server.Library;

namespace Microsoft.SDK.Project.Samples.ReadCustomFieldsTest
    class Program
        private const string ENDPOINT_CUSTOMFIELDS = "basicHttp_CustomFields";
        private const string ENDPOINT_LOOKUPTABLE = "basicHttp_LookupTable";
        // Change the output directory for your computer.
        private const string OUTPUT_FILES = @"C:\Project\Samples\Output\";

        private static SvcCustomFields.CustomFieldsClient customFieldsClient;
        private static SvcLookupTable.LookupTable lookupTableClient;

        private static string outFileCustomFieldsDs;
        private static string outFileLookupTableDs;
        private static int language = 1033;         // Use the English LCID by default.

        static void Main(string[] args)
            if (args.Length > 0 && args.Length < 3)
                if (args[0].ToLower() == "-lcid")
                    language = Convert.ToInt32(args[1]);

            outFileCustomFieldsDs = OUTPUT_FILES + "CustomFieldDataSet.xml";
            outFileLookupTableDs = OUTPUT_FILES + "LookupTableDataSet.xml";

                Console.WriteLine("Reading custom fields...");
                SvcCustomFields.CustomFieldDataSet customFieldDs = 
                    customFieldsClient.ReadCustomFields2(string.Empty, false);

                    "\nXML output of the CustomFieldDataSet:\n\t{0}",

                Console.WriteLine("Reading lookup tables...");
                SvcLookupTable.LookupTableDataSet lookupTableDs =
                    lookupTableClient.ReadLookupTables(string.Empty, false, language);

                    "\nXML output of the LookupTableDataSet:\n\t{0}",
            catch (FaultException fault)
                // Use the WCF FaultException, because the ASMX SoapException does not 
                // exist in a WCF-based application.
            catch (EndpointNotFoundException ex)
                Console.WriteLine("\nInnerException: \n" + ex.InnerException.Message);
            Console.Write("\nPress any key to exit... ");

        // Extract a PSClientError object from the WCF FaultException object, and
        // then display the exception details and each error in the PSClientError stack.
        private static void WriteFaultOutput(FaultException fault)
            string errAttributeName;
            string errAttribute;
            string errOut;
            string errMess = "".PadRight(30, '=') + "\r\n"
                + "Error details: " + "\r\n";

            PSLibrary.PSClientError error = Helpers.GetPSClientError(fault, out errOut);
            errMess += errOut;

            if (error != null)
                PSLibrary.PSErrorInfo[] errors = error.GetAllErrors();
                PSLibrary.PSErrorInfo thisError;

                for (int i = 0; i < errors.Length; i++)
                    thisError = errors[i];
                    errMess += "\r\n".PadRight(30, '=') + "\r\nPSClientError output:\r\n";
                    errMess += thisError.ErrId.ToString() + "\n";

                    for (int j = 0; j < thisError.ErrorAttributes.Length; j++)
                        errAttributeName = thisError.ErrorAttributeNames()[j];
                        errAttribute = thisError.ErrorAttributes[j];
                        errMess += "\r\n\t" + errAttributeName
                            + ": " + errAttribute;
            Console.ForegroundColor = ConsoleColor.Red;

        // Use the endpoints defined in app.config to configure the client.
        public static void ConfigClientEndpoints(string endpt)
            if (endpt == ENDPOINT_CUSTOMFIELDS)
                customFieldsClient = new SvcCustomFields.CustomFieldsClient(endpt);
            else if (endpt == ENDPOINT_LOOKUPTABLE)
                lookupTableClient = new SvcLookupTable.LookupTableClient(endpt);

    // Helper methods
    class Helpers
        /// <summary>
        /// Extract a PSClientError object from the ServiceModel.FaultException,
        /// for use in output of the GetPSClientError stack of errors.
        /// </summary>
        /// <param name="e"></param>
        /// <param name="errOut">Shows that FaultException has more information 
        /// about the errors than PSClientError has. FaultException can also contain 
        /// other types of errors, such as failure to connect to the server.</param>
        /// <returns>PSClientError object, for enumerating errors.</returns>
        public static PSLibrary.PSClientError GetPSClientError(FaultException e,
                                                               out string errOut)
            const string PREFIX = "GetPSClientError() returns null: ";
            errOut = string.Empty;
            PSLibrary.PSClientError psClientError = null;

            if (e == null)
                errOut = PREFIX + "Null parameter (FaultException e) passed in.";
                psClientError = null;
                // Get a ServiceModel.MessageFault object.
                var messageFault = e.CreateMessageFault();

                if (messageFault.HasDetail)
                    using (var xmlReader = messageFault.GetReaderAtDetailContents())
                        var xml = new XmlDocument();

                        var serverExecutionFault = xml["ServerExecutionFault"];
                        if (serverExecutionFault != null)
                            var exceptionDetails = serverExecutionFault["ExceptionDetails"];
                            if (exceptionDetails != null)
                                    errOut = exceptionDetails.InnerXml + "\r\n";
                                    psClientError =
                                        new PSLibrary.PSClientError(exceptionDetails.InnerXml);
                                catch (InvalidOperationException ex)
                                    errOut = PREFIX + "Unable to convert fault exception info ";
                                    errOut += "a valid Project Server error message. Message: \n\t";
                                    errOut += ex.Message;
                                    psClientError = null;
                                errOut = PREFIX + "The FaultException e is a ServerExecutionFault, "
                                    + "but does not have ExceptionDetails.";
                            errOut = PREFIX + "The FaultException e is not a ServerExecutionFault.";
                else // No detail in the MessageFault.
                    errOut = PREFIX + "The FaultException e does not have any detail.";
            errOut += "\r\n" + e.ToString() + "\r\n";
            return psClientError;

See also


CustomFields class

CustomFields members

WebSvcCustomFields namespace

ReadCustomFields(String, Boolean)

Other resources

How to: Use a Filter Parameter with PSI Methods