Custom Field and Lookup Table Webcast

Custom Field and Lookup Table Webcast

Rate This
  • Comments 6

Hello,

Attached is my source code and power point presentation of today's webcast on custom fields and lookup tables:

  • CustomFieldCRUD - This a very simple application that shows how to create, read, update and delete custom field definitions on Project Server 2007 using the PSI.
  • PublishProjects - This is an application that was written for our internal dogfood effort. We use this application to publish all the Project team's project plans on our Project Server. It shows how to read project custom fields and lookup table values from the Project PSI.
  • Custom Fields and Lookup Tables - This is a PDF version of the slide deck used for the presentation.

We will be publishing the presentation to the web in the next few days. Once it is available, I will post a link to it.

 

Chris Boyd

 

Attachment: CF Webcast.zip
Leave a Comment
  • Please add 6 and 2 and type the answer here:
  • Post
  • Hello Chris,

    Will this Webcast become available on the MS On-Demand webcast ?

  • Hey,

    We will be posting the webcast online. Once it is available, I will post a link to it.

    Chris

  • Hey,

    We will be posting the webcast online. Once it is available, I will post a link to it.

    Chris

  • When are you going to post the webcast online?

    The examples for a newbie like me are FANTASTIC!!!

    Thanks

  • I am having a problem while updating a custom field value of a specific project when OnPublishing event of project server raises. When I log on the Project Web Access with svc-emp user then it works fine and value of custom field updates, but when I log on on Project web access with different user it raises an exception that CICOCheckedOutToOtherUser. Following is my code, please any solution...

    using System;

    using System.Diagnostics;

    using Microsoft.Office.Project.Server.Events;

    using System.Collections.Generic;

    using System.Text;

    using System.Net;

    using System.Web.Services.Protocols;

    using System.Data;

    using System.Threading;

    using PSLibrary = Microsoft.Office.Project.Server.Library;

    namespace SaveProjectAttribute

    {

       public class AddAttributeOnSave : ProjectEventReceiver

       {

           public override void OnPublishing(Microsoft.Office.Project.Server.Library.PSContextInfo contextInfo, ProjectPrePublishEventArgs e)

           {

               base.OnPublishing(contextInfo, e);

               const string ls_projURL = "http://ruh-003-cr-001/pmo/";

               const string ls_CustomField = "TestCF";

               const string ls_LookupTableValue = "";

               bool verbose = true;

               const string PROJECT_SERVICE_PATH = "_vti_bin/psi/Project.asmx";

               const string LOGIN_SERVICE_PATH = "_vti_bin/psi/LoginWindows.asmx";

               bool isWindowsAccount = contextInfo.IsWindowsUser;

               Guid trackingGuid = new Guid(contextInfo.TrackingGuid.ToByteArray());

               string lcid = contextInfo.Lcid;

               string userNTAccount = contextInfo.UserName;

               Guid resourceGuid = new Guid(contextInfo.UserGuid.ToByteArray());

               Guid siteId = new Guid(contextInfo.SiteGuid.ToByteArray());

               ProjectDerived ws_Project = new ProjectDerived();

               LoginWindowsDerived loginWindows = new LoginWindowsDerived();

               LoginWindowsDerived.SetImpersonationContext(isWindowsAccount, userNTAccount, resourceGuid, trackingGuid, siteId, lcid);

               ProjectDerived.SetImpersonationContext(isWindowsAccount, userNTAccount, resourceGuid, trackingGuid, siteId, lcid);

               loginWindows.Url = ls_projURL + LOGIN_SERVICE_PATH;

               loginWindows.Credentials = CredentialCache.DefaultCredentials;

               ws_Project.Url = ls_projURL + PROJECT_SERVICE_PATH;

               ws_Project.Credentials = CredentialCache.DefaultCredentials;

               WSProject.ProjectDataSet lo_projs = null;

               WSProject.ProjectDataSet lo_projDS;

               Guid lo_projGUID;

               string ls_projName;

               CustomField cf = new CustomField(ls_projURL, ls_CustomField);

               LookupTable lt = new LookupTable(ls_projURL, cf.LookupTableGUID);

               try

               {

                   // Read all the projects on the server

                   lo_projs = ws_Project.ReadProjectList();

                   DataRowCollection lo_projects = lo_projs.Tables[lo_projs.Project.TableName].Rows;

                   lo_projDS = ws_Project.ReadProjectEntities(e.ProjectGuid, 32, WSProject.DataStoreEnum.WorkingStore);

                   foreach (WSProject.ProjectDataSet.ProjectCustomFieldsRow row in lo_projDS.ProjectCustomFields)

                   {

                       if (row.MD_PROP_UID == cf.CustomFieldGUID)

                       {

                           row.TEXT_VALUE = "Finally Got You!";

                           Guid jobid = Guid.NewGuid();

                           ws_Project.QueueUpdateProject(jobid, contextInfo.UserGuid, lo_projDS, false);

                       }

                   }

               }

               catch (SoapException lo_ex1)

               {

                   if (verbose)

                       System.Console.WriteLine("Error: " + lo_ex1.Message);

               }

               catch (WebException lo_ex)

               {

                   if (verbose)

                       System.Console.WriteLine("Error: " + lo_ex.Message);

               }

               catch (Exception lo_ex)

               {

                   if (verbose)

                       System.Console.WriteLine("Unknown Error: " + lo_ex.Message);

               }

               System.Console.WriteLine("Done!");

           }

       }

       class LoginWindowsDerived : WSLoginWindows.LoginWindows

       {

           private static String ContextString = String.Empty;

           protected override WebRequest GetWebRequest(Uri uri)

           {

               //here we are overriding the GetWebRequest method and adding the 2 web request headers

               WebRequest webRequest = base.GetWebRequest(uri);

               if (ContextString != String.Empty)

               {

                   webRequest.UseDefaultCredentials = true;

                   bool isImpersonating = (System.Security.Principal.WindowsIdentity.GetCurrent(true) != null);

                   webRequest.Credentials = CredentialCache.DefaultNetworkCredentials;

                   webRequest.Headers.Add("PjAuth", ContextString);

                   webRequest.Headers.Add("ForwardFrom", "/_vti_bin/psi/LoginWindows.asmx");

                   webRequest.PreAuthenticate = true;

               }

               return webRequest;

           }

           public static void SetImpersonationContext(bool isWindowsUser, String userNTAccount, Guid userGuid, Guid trackingGuid, Guid siteId, String lcid)

           {

               ContextString = GetImpersonationContext(isWindowsUser, userNTAccount, userGuid, trackingGuid, siteId, lcid);

           }

           private static String GetImpersonationContext(bool isWindowsUser, String userNTAccount, Guid userGuid, Guid trackingGuid, Guid siteId, String lcid)

           {

               PSLibrary.PSContextInfo contextInfo = new PSLibrary.PSContextInfo(isWindowsUser, userNTAccount, userGuid, trackingGuid, siteId, lcid);

               String contextString = PSLibrary.PSContextInfo.SerializeToString(contextInfo);

               return contextString;

           }

       }

       class ProjectDerived : WSProject.Project

       {

           private static String ContextString = String.Empty;

           protected override WebRequest GetWebRequest(Uri uri)

           {

               //here we are overriding the GetWebRequest method and adding the 2 web request headers

               WebRequest webRequest = base.GetWebRequest(uri);

               if (ContextString != String.Empty)

               {

                   webRequest.UseDefaultCredentials = true;

                   bool isImpersonating = (System.Security.Principal.WindowsIdentity.GetCurrent(true) != null);

                   webRequest.Credentials = CredentialCache.DefaultNetworkCredentials;

                   webRequest.Headers.Add("PjAuth", ContextString);

                   webRequest.Headers.Add("ForwardFrom", "/_vti_bin/psi/project.asmx");

                   webRequest.PreAuthenticate = true;

               }

               return webRequest;

           }

           public static void SetImpersonationContext(bool isWindowsUser, String userNTAccount, Guid userGuid, Guid trackingGuid, Guid siteId, String lcid)

           {

               ContextString = GetImpersonationContext(isWindowsUser, userNTAccount, userGuid, trackingGuid, siteId, lcid);

           }

           private static String GetImpersonationContext(bool isWindowsUser, String userNTAccount, Guid userGuid, Guid trackingGuid, Guid siteId, String lcid)

           {

               PSLibrary.PSContextInfo contextInfo = new PSLibrary.PSContextInfo(isWindowsUser, userNTAccount, userGuid, trackingGuid, siteId, lcid);

               String contextString = PSLibrary.PSContextInfo.SerializeToString(contextInfo);

               return contextString;

           }

       }

    }

  • I'm not certain about custom fields but when I have updated Actual times in Assignments - using impersonation - I had to log onto windows as the "farm admin" user. Even another admin user with identical privs did not help. A MS tech support person confirmed that the "SSP-level" impersonation (using the derived classes) required being logged in as the Farm Admin.

    At one site, I was able to get around that restriction by using "windows-level" impersonation (using the Win32 API) to impersonate to the farm admin in the program before calling the PSI call.

    Hope this helps.

    Ken Henderson

Page 1 of 1 (6 items)