PDS and PSI Code Examples

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Porting Project Data Service (PDS) applications for Microsoft Office Project Server 2003 to the PSI in Microsoft Office Project Server 2007 requires planning before you start to make code changes. As the tables in Equivalent PSI Methods show, there is not a 1:1 correspondence between PDS and PSI methods, and the functionality of several PDS methods are obsolete for Office Project Server 2007. This topic shows examples of PDS requests and the equivalent PSI code using Microsoft Visual C#.

In the following sections, the first five examples use the PSI Project Web service and the last example uses the CustomFields Web service and the Resource Web service.

  • Creating a Project

  • Project Types and Checking Out Projects

  • Creating a Task

  • Adding a Resource

  • Creating an Assignment

  • Creating and Using a Resource Text Custom Field

The PSI uses DataSet objects to specify or return information about business objects such as projects, tasks, resources, and other entities. The DataSet is a Microsoft ADO.NET class that represents a disconnected subset of a database. A DataSet can include multiple DataTable and DataRelation objects. The PSI and datasets provide a logical abstraction of the Project Server business objects. Applications access the Project Server business objects through the PSI, and the business objects in turn access the Project Server databases through the data access layer (DAL). For more information about business objects and the Project Server databases, see Project Server Architecture and Programmability.

The examples contain code snippets only, and do not show all the development steps. For information about finding the PSI Web services and using them in Microsoft Visual Studio 2005, see Working with the PSI and DataSets.

Creating a Project

It is helpful to compare actions using the PDS with using the PSI. For example, you can send the following XML request to the PDS to create and publish a simple project in Project Server 2003.

<Request>
   <ProjectCreate>
      <AutoPublish>1</AutoPublish>
      <Project>
         <ProjectName>Test Project</ProjectName>
         <StartDate>20051024</StartDate>
      </Project>
   </ProjectCreate>
</Request>

The PDS example shows only the XML request, not all of the code you need to create an object from the PDS Web service and to send the request or handle the reply. When you are developing an application using the PDS, the PDS does not check the XML syntax of the ProjectCreate request until run time. If there is an error in the method name or one of the parameter names, the PDS returns an XML reply with the status code 7 for rsNodeNameInvalid, 1 for rsRequestUnknown, or 6 for rsRequestInvalidParameter.

If the data contains an error, the PDS returns a different status code that depends on the type of error. For example, the PDS returns status code 21 (rsDateFormatInvalid) for the parameter <StartDate>10-24-2005</StartDate>. To debug a PDS request, you might need to compile and run your application several times just to get the correct syntax.

The PSI example shows the basic steps to create and publish a project programmatically. The PSI includes many Web services. For example, the Project.asmx file describes the Project Web service, the Admin.asmx file describes the Admin Web service, the Calendar.asmx file describes the Calendar Web service, and so forth. In a default installation of Office Project Server 2007, for example, you can see all of the public methods of the Project Web service when you open a browser to the following URL (ServerName and ProjectServer depend on your installation).

http://ServerName/ProjectServer/_vti_bin/psi/project.asmx

To create a project with the PSI:

  1. In Visual Studio, set a Web reference to the Project Web service of the PSI and name the reference, for example, WebSvcProject (an arbitrary name). If your application namespace is TestApp, then the Project Web service namespace is TestApp.WebSvcProject.

  2. Initialize a variable for the WebSvcProject.Project object, for example project. Set the Credentials, CookieContainer, and Url properties from your Project Server logon.

    For a complete example, see How to: Log on to Project Server Programmatically.

  3. Create a ProjectDataSet object, for example dsProject. Create a new row with the NewProjectRow method, for example projectRow.

  4. Set the projectRow properties.

  5. Using the AddProjectRow method, add the row to the ProjectDataTable.

  6. Call QueueCreateProject to save the new project to the Draft database.

  7. If you want to publish the saved project to the Published database, call QueuePublish on the project object.

    NoteNote

    Project Server 2007 uses four databases: Draft, Published, Archive, and Reporting.

The following Visual C# code shows the same steps. It is explained with more detail in Using Project Server DataSet Objects.

/* Step 1: Set a Project Web reference in Visual Studio
   Step 2:  Create an instance of the Project class. */
private static WebSvcProject.Project project = 
    new WebSvcProject.Project();

/* NOTE: The logon to Project Server is not shown here. You can use 
 *       the LoginWindows or LoginForms Web services. Then set user 
 *       credentials, logon cookie, and URL for the project object. */

public static void CreateProject() {
/* Step 3: Create a ProjectDataSet and a new row */
WebSvcProject.ProjectDataSet dsProject = new 
    ProjectWebSvc.ProjectDataSet();
WebSvcProject.ProjectDataSet.ProjectRow projectRow = 
    dsProject.Project.NewProjectRow();

/* Step 4: Set the project row properties */
Guid projectGuid = Guid.NewGuid();
projectRow.PROJ_UID = projectGuid;
projectRow.PROJ_NAME = "Test Project";

/* Step 5: Add the row to the DataTable. Here, Project is a property of dsProject, of type ProjectDataSet.ProjectDataTable */
dsProject.Project.AddProjectRow(projectRow);

/* Step 6: Call QueueCreateProject to save the project to the Draft
   database. Set the validateOnly parameter to false. */
Guid jobGuid = Guid.NewGuid();
project.QueueCreateProject(jobGuid, dsProject, false);

// Wait a few seconds for Queue job to complete
System.Threading.Thread.Sleep(3000);

/* Step 7: Call QueuePublish to save to the published database 
   Set fullPublish to true, and publish with a new jobUid. 
   Here, wssUrl specifies the default project workspace site on Windows SharePoint Services. */
bool fullPublish = true;
string wssUrl = "";
Guid jobGuid = Guid.NewGuid();
project.QueuePublish(projectGuid, wssUrl, fullPublish, jobGuid);
} } }

Project Types and Checking Out Projects

The PDS method ProjectsCheckout includes the optional ProjectType parameter. In the PDS, ProjectType is 0 by default for normal projects, 1 for a project template, 2 for the Enterprise Global Template, or 3 for the resource global project. In Project Server 2007, the PROJ_TYPE property of ProjectDataSet.ProjectRow can be 0 or 1. There is no resource global project; the Enterprise Global Template is a series of settings, not a project template.

Project Server maintains resources in a separate table, so you do not need to check out a project to add, deactivate, delete, or modify the enterprise resource pool. To modify resource data, you need to use CheckOutResources and CheckInResources along with PSI methods such as ReadResources that returns a ResourceDataSet and UpdateResources that saves the dataset.

The following PDS request checks out a project with ID = 7.

<Request>
   <ProjectsCheckout>
      <Project>
         <ProjectType>0</ProjectType>  <!-- default type -->
         <ProjectID>7</ProjectID>
      </Project>
   </ProjectsCheckout>
</Request>

To check out a normal project or a project template (PROJ_TYPE = 0 or PROJ_TYPE = 1) using the PSI, you can use CheckOutProject with the project GUID. In the following code, project is a static class variable that represents the WebSvcProject.Project object in the section Creating a Project.

public void ProjectCheckout(Guid projectGuid, string description)
{
   Guid sessionGuid = Guid.NewGuid();
   project.CheckOutProject(projectGuid, sessionGuid, description);
}

You can use ReadProjectStatus to retrieve a list of projects with a specified type. ReadProjectStatus is designed to return information that is comparable to project information in a reply from the PDS ProjectsStatus method. The following code gets a list of all project templates in the Draft database, and returns the GUID of the specified template name.

using PSLibrary = Microsoft.Office.Project.Server.Library;
. . .
public Guid ReadTemplateGuid(WebSvcProject.Project project, string templateName)
{
    WebSvcProject.ProjectDataSet dsReadProject = new WebSvcProject.ProjectDataSet();
    Guid templateGuid = Guid.Empty;
    string allTemplateNames = "";

    dsReadProject = project.ReadProjectStatus(templateGuid, 
        WebSvcProject.DataStoreEnum.WorkingStore,
        allTemplateNames, (int)PSLibrary.Project.ProjectType.Template);

    for (int row = 0; row < dsReadProject.Project.Count; row++)
    {
        if (templateName == dsReadProject.Project[row].PROJ_NAME.ToString())
        {
            templateGuid = dsReadProject.Project[row].PROJ_UID;
            break;
        }
    }
    return templateGuid;
}

The ReadProjectStatus method returns the PROJ_UID, PROJ_NAME, and PROJ_TYPE fields in the Project table. The ProjectDataSet includes the following tables:

  • Project

  • Task

  • ProjectResource

  • Assignment

  • Dependency

  • ProjectCustomFields

  • TaskCustomFields

  • ProjectResourceCustomFields

  • AssignmentCustomFields

Many of the fields in the ProjectDataSet returned by ReadProjectStatus are empty. To get more complete information about a project, use ReadProject.

Creating a Task

The following PDS request creates a new task in an existing project, and links it to a predecessor task. Unless otherwise specified, by default the PDS creates a task unique ID (UID) and duration of one day.

<Request>
   <ProjectTasksCreate>
      <ProjectID>37</ProjectID>
      <Tasks>
         <Task>
            <Name>Added Task</Name>
            <PredecessorLink>
               <PredecessorID>2</PredecessorID>
            </PredecessorLink>
         </Task>
      </Tasks>
   </ProjectTasksCreate>
</Request>

CreateTaskRow is an example method that uses the PSI Project Web service. The dsProject, taskName, position, and predecessorGuid parameters are assumed to be initialized elsewhere in the application. The Microsoft.Office.Project.Server.Library.Task.AddPositionType enumeration defines the task position as First, Middle, or Last. The Middle position enables a task to have a specified predecessor task.

Important noteImportant

When you create a TaskRow object, you must specify the TASK_DUR_FMT value. Otherwise, opening the project in Project Professional can result in unpredictable behavior, including possible data loss.

You create a new taskRow object with the PSI, set the properties of the new task, and then add the taskRow as a Task item to the existing ProjectDataSet object. Finally, you can link the new task in the ProjectDataSet to another task.

NoteNote

Project Server does not allow duplicate task GUIDs in the same project, but does not check for duplicate task GUIDs in other projects. You should never reuse a GUID when you create tasks, even if the tasks are in different projects. Duplicate task GUIDs break other Project Server functions such as the Cube Build Service and updates of the Reporting database.

using PSLibrary = Microsoft.Office.Project.Server.Library;
. . .
public static void CreateTaskRow(
   WebSvcProject.ProjectDataSet dsProject, 
   string taskName, 
   PSLibrary.Task.AddPositionType position,
   Guid predecessorGuid)
{
   WebSvcProject.ProjectDataSet.TaskRow taskRow = 
      dsProject.Task.NewTaskRow();
   taskRow.PROJ_UID = dsProject.Project[0].PROJ_UID;
   taskRow.TASK_UID = Guid.NewGuid();
   taskRow.TASK_DUR_FMT = (int)PSLibrary.Task.DurationFormat.Day;
   taskRow.AddPosition = position;
   if (position == PSLibrary.Task.AddPosition.Middle)
   {
       taskRow.AddAfterTaskUID = predecessorGuid;
   }
   taskRow.TASK_NAME = taskName;
   dsProject.Task.AddTaskRow(taskRow);
   // You can set the task predecessor before or after you add the row.
   // dsProject.Task[taskName].AddPosition = PSLibrary.Task.AddPosition.Middle;
   // dsProject.Task[taskName].TASK_PARENT_UID = predecessorGuid;
}

Note

The example method CreateTaskRow does not create a task; it just creates a task row in a disconnected ProjectDataSet. As the code shows in Creating a Project, you need to call QueueCreateProjector QueueUpdateProjectto actually create a project entity such as a task in the Draft database. When you create or update a project, the PSI can process up to 1000 rows of data at a time. If the total number of rows of new or updated data in all tables of ProjectDataSet exceeds 1000, the PSI returns the ProjectExceededItemsLimit error.

Adding a Resource

The following PDS request creates a new resource in an existing project. Unless otherwise specified, by default the PDS creates a resource unique ID (UID).

<Request>
   <ProjectResourcesCreate>
   <ProjectID>37</ProjectID>
      <Resources>
         <Resource>
            <Name>Guido Pica</Name>
         </Resource>
      </Resources>
   </ProjectResourcesCreate>
</Request>

CreateResourceRow is an example method that uses the PSI Project Web service. The dsProject, resName, and resType parameters are assumed to be initialized elsewhere in the application. Typical resource types you can add to a project include WorkResource, MaterialResource, and CostResources. You can use the Microsoft.Office.Project.Server.Library.Resource.Type enumeration.

You create a new resourceRow object, set the resource properties, and then add the resourceRow as a ProjectResource item to the existing ProjectDataSet object.

public static void CreateResourceRow(
   WebSvcProject.ProjectDataSet dsProject, 
   string resName, int resType)
{
   WebSvcProject.ProjectDataSet.ProjectResourceRow resourceRow = 
      dsProject.ProjectResource.NewProjectResourceRow();
   resourceRow.PROJ_UID = dsProject.Project[0].PROJ_UID;
   resourceRow.RES_UID = Guid.NewGuid();
   resourceRow.RES_NAME = resName;
   dsProject.ProjectResource.AddProjectResourceRow(resourceRow);
}

The following code initializes resType and calls the CreateResourceRow method.

using PSLibrary = Microsoft.Office.Project.Server.Library;
. . .
int resType = (int)PSLibrary.Resource.Type.WorkResource;
string newResourceName = "New Resource";
CreateResource(dsNewProject, newResourceName, resType);

The resource is created in the Draft database after you call QueueCreateProject or QueueUpdateProject with the ProjectDataSet object.

Creating an Assignment

The following PDS request assigns a resource to a task in an existing project.

<Request>
   <ProjectAssignmentsCreate>
   <ProjectID>37</ProjectID>
      <Assignments>
         <Assignment>
            <TaskID>5</TaskID>
            <ResourceID>2</ResourceID>
         </Assignment>
      </Assignments>
   </ProjectAssignmentsCreate>
</Request>

CreateAssignmentRow is an example method that uses the PSI Project Web service. The dsProject, taskGuid, and resGuid parameters are assumed to be initialized elsewhere in the application. You create an assignmentRow object with the PSI, set the assignment properties, and then add assignmentRow as an AssignmentRow item to the existing ProjectDataSet object.

public static void CreateAssignmentRow(
   ProjectWebSvc.ProjectDataSet dsProject, 
   Guid taskGuid, 
   Guid resGuid)
{
   ProjectWebSvc.ProjectDataSet.AssignmentRow assignmentRow = 
      dsProject.Assignment.NewAssignmentRow();
   assignmentRow.PROJ_UID = dsProject.Project[0].PROJ_UID;
   assignmentRow.ASSN_UID = Guid.NewGuid();
   assignmentRow.TASK_UID = taskGuid;
   assignmentRow.RES_UID = resGuid;
   dsProject.Assignment.AddAssignmentRow(assignmentRow);
}

The assignment is created in the Draft database after you call QueueCreateProject or QueueUpdateProject with the ProjectDataSet object.

Creating and Using a Resource Text Custom Field

The following examples use the PSI CustomFields and Resource Web services. The variables customField and resource reference those Web services. For more information about enterprise custom fields and lookup tables, see Local and Enterprise Custom Fields.

In the CreateCustomFields and CreateResources methods, validateOnly is false to save the dataset in the Published database. The autoCheckIn parameter is false in each method to keep the enterprise resource dataset and the custom field in the Enterprise Global Template checked out.

using System;
using System.Net;
using System.Data;
using PSLibrary = Microsoft.Office.Project.Server.Library;
. . .
// Create a text custom field without a lookup table.
public Guid CreateResourceTextCustomField(
    WebSvcCustomFields.CustomFields customFields, 
    string cfName)
{
    WebSvcCustomFields.CustomFieldDataSet dsCustomField =
        new WebSvcCustomFields.CustomFieldDataSet();
     WebSvcCustomFields.CustomFieldDataSet.CustomFieldsRow cfRow =
        dsCustomField.CustomFields.NewCustomFieldsRow();
    byte cfType = (byte)PSLibrary.CustomField.Type.TEXT;

    cfRow.MD_PROP_UID = Guid.NewGuid();
    cfRow.MD_PROP_NAME = cfName;
    cfRow.MD_PROP_TYPE_ENUM = cfType;
    cfRow.MD_ENT_TYPE_UID = 
        new Guid(PSLibrary.EntityCollection.Entities.ResourceEntity.UniqueId);

    dsCustomField.CustomFields.Rows.Add(cfRow);
    bool validateOnly = false;
    bool autoCheckIn = false;
    customFields.CreateCustomFields(dsCustomField, validateOnly, autoCheckIn);
    return cfRow.MD_PROP_UID;
}

The CustomFieldRow property MD_ENT_TYPE_UID specifies the entity type ID of a custom field. A Project Server entity type for an enterprise custom field can be a resource, task, or project. Assignment custom fields are automatically created when a task or resource custom field is created.

To specify the entity, use Microsoft.Office.Project.Server.Library.EntityCollection. For example, the PSLibrary.EntityCollection.Entities.[Entity].UniqueId property, where [Entity] is ProjectEntity, ResourceEntity, or TaskEntity, is a string that you use to create a GUID for the entity type. Similarly, MD_PROP_TYPE_ENUM is the property type enumerator. You cast the CustomField.Type.TEXT value to a byte for assignment to MD_PROP_TYPE_ENUM.

// Create an enterprise resource and add a custom field.
public Guid CreateEntResourceWithCustomField(
    WebSvcResource.Resource resource, 
    string resName, Guid cfUid)
{
    WebSvcResource.ResourceDataSet dsResource = new
        WebSvcResource.ResourceDataSet();
    WebSvcResource.ResourceDataSet.ResourcesRow resRow =
        dsResource.Resources.NewResourcesRow();

    resRow.RES_UID = Guid.NewGuid();
    resRow.RES_NAME = resName;
    dsResource.Resources.Rows.Add(resRow);

    WebSvcResource.ResourceDataSet.ResourceCustomFieldsRow resCfRow =
        dsResource.ResourceCustomFields.NewResourceCustomFieldsRow();

    resCfRow.CUSTOM_FIELD_UID = Guid.NewGuid();
    resCfRow.RES_UID = resRow.RES_UID;
    resCfRow.MD_PROP_UID = cfUid;
    resCfRow.TEXT_VALUE = "Hello, World!";
    dsResource.ResourceCustomFields.AddResourceCustomFieldsRow(resCfRow);

    bool validateOnly = false;
    bool autoCheckIn = false;
    resource.CreateResources(dsResource, validateOnly, autoCheckIn);
    return resRow.RES_UID;
}

If the preceding code is contained in a class named UtilityClass, your application can call the methods as follows.

public static WebSvcCustomFields.CustomFields customFields = 
    new WebSvcCustomFields.CustomFields();
public static WebSvcResource.Resource resource = 
    new WebSvcResource.Resource();
private static ApplicationNamespace.UtilityClass utilityClass = new UtilityClass();
. . .
Guid cfUid = utilityClass.CreateResourceTextCustomField(customFields, "ResText CF");
Guid resUid = utilityClass.CreateEntResourceWithCustomField(resource,
    "Res " + DateTime.Now.ToString(), cfUid);

To see the contents of the new enterprise resource, you can create a ResourceDataSet object and set it to the return value of ReadResource. Set a breakpoint after the dsResource assignment statement in the following code to use the DataSet Visualizer in Visual Studio 2005, or serialize dsResource to a file.

WebSvcResource.ResourceDataSet dsResource = 
    new WebSvcResource.ResourceDataSet();
dsResource = resource.ReadResource(resUid);
dsResource.WriteXml(@"C:\Project\dsResource.xml"); 

For more information about the DataSet Visualizer, see Using Project Server DataSet Objects. The following code shows contents of dsResource.xml after running the preceding code.

<?xml version="1.0" standalone="yes"?>
<ResourceDataSet xmlns="http://tempuri.org/ResourceDataSet.xsd">
  <Resources>
    <RES_UID>66631e12-6318-495f-a858-f88624d63aeb</RES_UID>
    <RES_ID>6</RES_ID>
    <RES_TYPE>1</RES_TYPE>
    <RES_HAS_NOTES>false</RES_HAS_NOTES>
    <RES_CAN_LEVEL>true</RES_CAN_LEVEL>
    <RES_ACCRUE_AT>3</RES_ACCRUE_AT>
    <RES_NAME>Res 2/9/2006 1:46:43 PM</RES_NAME>
    <RES_INITIALS>R</RES_INITIALS>
    <RES_PREVENT_ADSYNC>false</RES_PREVENT_ADSYNC>
    <RES_CHECKOUTBY>4174ce9e-8197-4435-9de5-e400a94e4c61</RES_CHECKOUTBY>
    <RES_CHECKOUTDATE>2006-02-09T13:46:44.03-08:00</RES_CHECKOUTDATE>
    <RES_TIMESHEET_MGR_UID>66631e12-6318-495f-a858-f88624d63aeb</RES_TIMESHEET_MGR_UID>
    <RES_DEF_ASSN_OWNER>66631e12-6318-495f-a858-f88624d63aeb</RES_DEF_ASSN_OWNER>
    <RES_IS_TEAM>false</RES_IS_TEAM>
    <RES_MAX_UNITS>10000</RES_MAX_UNITS>
    <CREATED_DATE>2006-02-09T13:46:44.01-08:00</CREATED_DATE>
    <MOD_DATE>2006-02-09T13:46:44.03-08:00</MOD_DATE>
    <RES_STD_RATE_FMT>2</RES_STD_RATE_FMT>
    <RES_OVT_RATE_FMT>2</RES_OVT_RATE_FMT>
    <BaseCalendarUniqueId>703a2bf1-2c6e-4b24-9ad4-2dd45410f907</BaseCalendarUniqueId>
  </Resources>
  <ResourceCustomFields>
    <CUSTOM_FIELD_UID>96b732d5-52ae-47e0-ac50-a22432f40424</CUSTOM_FIELD_UID>
    <RES_UID>66631e12-6318-495f-a858-f88624d63aeb</RES_UID>
    <MD_PROP_UID>c3fdcbb6-09ca-4735-ac65-28395496967b</MD_PROP_UID>
    <MD_PROP_ID>205553671</MD_PROP_ID>
    <TEXT_VALUE>Hello, World!</TEXT_VALUE>
    <FIELD_TYPE_ENUM>21</FIELD_TYPE_ENUM>
  </ResourceCustomFields>
  <ResourceAvailabilityTables>
    <RES_UID>66631e12-6318-495f-a858-f88624d63aeb</RES_UID>
    <RES_AVAIL_UNITS>100</RES_AVAIL_UNITS>
  </ResourceAvailabilityTables>
</ResourceDataSet>

See Also

Reference

Equivalent PSI Methods

Concepts

PSI Reference Overview

Project Server Architecture and Programmability

Working with the PSI and DataSets

Local and Enterprise Custom Fields

Other Resources

Project Server Interface (PSI) Overview

Project Data Service Reference for Microsoft Office Project Server 2003