Adding a Project to a Category
Brian Smith from PSS has passed along this sample that we thought might be helpful:
The scenario here is that you have a lookup table that shows the categories you want users to select from when creating a project, and then the GUID for the "real" security category is held in the description for the lookup table value. You make the CF that feeds from the Lookup Table a required Project Level text field. The Project.Created event fires and the dataset is read - the custom field identified and the GUID of the security category is then used to add the project to the security category.
No error checking or exception handling is shown - you can do this bit. You would also need to set the categories to the rule "only projects...". I've hardcoded my lookup table and a reference required to the Microsoft.Office.Project.Server.Library and Events. A Web References to LookupTable, Project, Security and LoginWindows is also required.
The code will run as the user running the services - so you will either need that account to have PWA permissions or to change to use impersonation.
using System;
using System.Collections.Generic;
using System.Net;
using System.Diagnostics;
using System.Text;
using Microsoft.Office.Project.Server.Events;
using Microsoft.Office.Project.Server.Library;
namespace TestEventHandler
{
public class AutoCategory:ProjectEventReceiver
{
public override void OnCreated(PSContextInfo contextInfo, ProjectPostEventArgs e)
{
// cfGuid holds CF for Project Category
Guid cfGuid = new Guid("9bbc698f-5c1d-4f8d-a3d0-163006416bf2");
// ltGuid holds LT for Categories
Guid ltGuid = new Guid("625bab60-4427-4f0b-941b-9860d1293338");
// lt_Struct_Uid gets the id for the selected LT value
Guid lt_Struct_Uid = new Guid("00000000-0000-0000-0000-000000000000");
// securityCategoryGuid gets the Security Categorty Guid from the Descriptio field in the lookup table
Guid securityCategoryGuid = new Guid("00000000-0000-0000-0000-000000000000");
// 32 is used to just get the CF entities from the readProjectEntities
const int PROJECT_ENTITY_TYPE_PROJECTCUSTOMFIELD = 32;
Guid SECURITY_CATEGORY_OBJECT_TYPE_PROJECT = new Guid("1771B1C0-6E26-4FB3-A480-C798AB506E82");
WebSvcLoginWindows.LoginWindows loginWindows = new TestEventHandler.WebSvcLoginWindows.LoginWindows();
WebSvcProject.Project project = new TestEventHandler.WebSvcProject.Project();
WebSvcSecurity.Security security = new TestEventHandler.WebSvcSecurity.Security();
WebSvcLookupTable.LookupTable lookupTable = new TestEventHandler.WebSvcLookupTable.LookupTable();
//login to Project Server - this assumes the event service has a login with permissions
// Impersonation would be better
loginWindows.Url = @"https://SERVER_NAME/ProjectServer/_vti_bin/PSI/LoginWindows.asmx";
loginWindows.Credentials = CredentialCache.DefaultCredentials;
loginWindows.Login();
// Get the dataset
project.Url = @"https://SERVER_NAME/ProjectServer/_vti_bin/PSI/Project.asmx";
project.Credentials = CredentialCache.DefaultCredentials;
lookupTable.Url = @"https://SERVER_NAME/ProjectServer/_vti_bin/PSI/LookupTable.asmx";
lookupTable.Credentials = CredentialCache.DefaultCredentials;
security.Url = @"https://SERVER_NAME/ProjectServer/_vti_bin/PSI/security.asmx";
security.Credentials = CredentialCache.DefaultCredentials;
WebSvcProject.ProjectDataSet dsProjectDataSet = new TestEventHandler.WebSvcProject.ProjectDataSet();
dsProjectDataSet = project.ReadProjectEntities(e.ProjectGuid, PROJECT_ENTITY_TYPE_PROJECTCUSTOMFIELD, TestEventHandler.WebSvcProject.DataStoreEnum.WorkingStore);
for (int i = 0; i < dsProjectDataSet.ProjectCustomFields.Count; i++)
{
if (dsProjectDataSet.ProjectCustomFields[i].MD_PROP_UID == cfGuid)
{
lt_Struct_Uid = dsProjectDataSet.ProjectCustomFields[i].CODE_VALUE;
}
}
Guid[] arrayLtUid = new Guid[1]{ltGuid};
WebSvcLookupTable.LookupTableDataSet dsLookupTable = new TestEventHandler.WebSvcLookupTable.LookupTableDataSet();
dsLookupTable = lookupTable.ReadLookupTablesByUids(arrayLtUid, false, 1033);
for (int i = 0; i < dsLookupTable.LookupTableTrees.Count; i++)
{
if (dsLookupTable.LookupTableTrees[i].LT_STRUCT_UID == lt_Struct_Uid)
{
securityCategoryGuid = new Guid(dsLookupTable.LookupTableTrees[i].LT_VALUE_DESC.ToString());
}
}
WebSvcSecurity.SecurityCategoriesDataSet dsSecurityCategories
= new TestEventHandler.WebSvcSecurity.SecurityCategoriesDataSet();
// Read the existing values for the security category into the dataset
dsSecurityCategories = security.ReadCategory(securityCategoryGuid);
// Get a new objects row to put the created project into
WebSvcSecurity.SecurityCategoriesDataSet.SecurityCategoryObjectsRow dsSecurityCategoryObjectsRow
= dsSecurityCategories.SecurityCategoryObjects.NewSecurityCategoryObjectsRow();
//Set the values
dsSecurityCategoryObjectsRow.WSEC_OBJ_TYPE_UID = SECURITY_CATEGORY_OBJECT_TYPE_PROJECT;
dsSecurityCategoryObjectsRow.WSEC_CAT_UID = securityCategoryGuid;
dsSecurityCategoryObjectsRow.WSEC_OBJ_UID = e.ProjectGuid;
// Add the row to the dataset and then pass to SetCategories to update
dsSecurityCategories.SecurityCategoryObjects.AddSecurityCategoryObjectsRow(dsSecurityCategoryObjectsRow);
// Create an EventLog instance and assign its source.
EventLog myLog = new EventLog();
myLog.Source = "Project Event Handler";
// Get information from the event arguments, and
// write an entry to the Application event log.
string userName = contextInfo.UserName.ToString();
string projectName = e.ProjectName.ToString();
string secCatUid = securityCategoryGuid.ToString();
int eventId = 3652;
string logEntry;
logEntry = "User: " + userName +
"\nProject: " + projectName +
"\nSecurity Category Uid: " + secCatUid;
myLog.WriteEntry(logEntry, EventLogEntryType.Information, eventId);
security.SetCategories(dsSecurityCategories);
}
}
}
Comments
Anonymous
March 01, 2007
Hi! Thanx for an excellent article! I have a question that I was hoping you could answer. I'm wondering how to retrieve the different webservice-urls that you have hardcoded in you examplecode, from within the eventhandler? What I'd like to do is to "re-use" the logic that (I guess) allready is in use within the applicationlogic today. English is not my native language, so just to clearify what I mean; When for instance a project is saved, the client makes a call to the PSI by referencing the correct url. My question is simply, in what way does the client retrieve the url? Regards, YonZoAnonymous
June 01, 2007
You may already have found an answer - but if not the blog at http://blogs.msdn.com/brismith/archive/2007/02/02/one-event-handler-and-multiple-pwa-sites-where-did-that-event-come-from.aspx should helpAnonymous
October 15, 2008
The comment has been removed