Hello,
Attached is my source code and power point presentation of today's webcast on custom fields and lookup tables:
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
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
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)
System.Console.WriteLine("Error: " + lo_ex.Message);
catch (Exception lo_ex)
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
webRequest.Headers.Add("ForwardFrom", "/_vti_bin/psi/project.asmx");
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