Where to place my logic

J

Joachim Jauß

Hi all,

sorry for me second post ... I don't see the first one in the browser.

We work with MOPS 2007 SP2

I should update a projectlevel field when the pm publishes his project. This
action should be server side. So I wrote an eventhandler for the publishing
event, update the projectstatus field an save the project. But the publishing
has no effect.

For tests I use the pwa project center => edit project properties and press
save and publish button.

Can anyone tell me the right place for my logic?


thx

Joachim
 
J

Joachim Jauß

yes i can .. sorry it's more than 200 lines

i'll played something arround and I think i have a solution.
I use the Eventhandler OnPublished .. then I do my updates and publish the
project again. But this is slow because I had to publish a second time.
Is there any other way to do this?

Here's the code:

using System;
using System.Net;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.SharePoint;
using ProjectStatusUpdate.Helpers;
using ProjectStatusUpdate.ProjectWebSvc;
using ProjectStatusUpdate.PSI;
using DataStoreEnum = ProjectStatusUpdate.ProjectWebSvc.DataStoreEnum;
using PSLib = Microsoft.Office.Project.Server.Library;
using System.Diagnostics;
using System.Threading;
using Microsoft.Office.Project.Server.Library;
using System.Web.Services.Protocols;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

namespace ProjectStatusUpdate
{
public class StatusUpdateHandler :
Microsoft.Office.Project.Server.Events.ProjectEventReceiver
{

// Loaded from ApplicationSettings
private string _sspName = "";

private const double MAX_PROJECTSTATUS = 3.0;
private const string IS_DELIVERY_MILESTONE_NAME =
"SMK_IsDeliveryMilestone";
private const string IS_PROJECT_CRITICAL_NAME =
"SMK_IsProjectCritical";
private const string TASK_STATUS_CRITICAL_NAME =
"SMK_TaskStatusCritical";
private const string PROJECT_STATUS_NAME = "Projektstatus";

public override void OnPublished(PSContextInfo contextInfo,
Microsoft.Office.Project.Server.Events.ProjectPostPublishEventArgs e)
{
base.OnPublished(contextInfo, e);

DoWork(contextInfo, e);
}

private void DoWork(IPSContextInfo contextInfo,
Microsoft.Office.Project.Server.Events.ProjectPostPublishEventArgs e)
{
using (new Tracer("StatusUpdateHandler", e.ProjectGuid))
{
Logger.Write("StatusUpdateHandler started...");

LoadSettings();
try
{
ProjectDerived project;
CustomFieldsDerived customFields;
QueueSystemDerived queueSystem;


using (SPSite spSite = new SPSite(contextInfo.SiteGuid))
{
project = new ProjectDerived();
project.Credentials =
CredentialCache.DefaultCredentials;
project.Url = WsUrl(spSite, "project", true);

customFields = new CustomFieldsDerived();
customFields.Credentials =
CredentialCache.DefaultCredentials;
customFields.Url = WsUrl(spSite, "customfields",
false);

queueSystem = new QueueSystemDerived();
queueSystem.Credentials =
CredentialCache.DefaultCredentials;
queueSystem.Url = WsUrl(spSite, "queuesystem", false);
}

Guid taskEntityId = new
Guid(EntityCollection.Entities.TaskEntity.UniqueId);
Guid projectEntityId = new
Guid(EntityCollection.Entities.ProjectEntity.UniqueId);


Guid isDeliveryMilestoneGuid =
FieldNameToGuid.GetGuidUsingFieldName(customFields,

IS_DELIVERY_MILESTONE_NAME,

taskEntityId);
Guid isProjectCriticalGuid =
FieldNameToGuid.GetGuidUsingFieldName(customFields,

IS_PROJECT_CRITICAL_NAME,

taskEntityId);
Guid taskStatusCriticalGuid =
FieldNameToGuid.GetGuidUsingFieldName(customFields,

TASK_STATUS_CRITICAL_NAME,

taskEntityId);
Guid projectStatusGuid =
FieldNameToGuid.GetGuidUsingFieldName(customFields,

PROJECT_STATUS_NAME,

projectEntityId);


bool isWindowsUser = contextInfo.IsWindowsUser ||
contextInfo.UserName.Contains("\\");
project.SetImpersonationContext(isWindowsUser,
contextInfo.UserName,
contextInfo.UserGuid,
contextInfo.TrackingGuid, contextInfo.SiteGuid,
contextInfo.Lcid);
Logger.Write(string.Format("Read Project {0}-{1} from
Server", e.ProjectGuid, e.ProjectName));

ProjectDataSet projectData =
project.ReadProject(e.ProjectGuid, DataStoreEnum.WorkingStore);

decimal projectStatus = 0;

// detect the max task status
foreach (ProjectDataSet.TaskRow task in
projectData.Task.Rows)
{
Guid taskUid = task.TASK_UID;
string taskName = task.TASK_NAME;


ProjectDataSet.TaskCustomFieldsRow
isDeliveryMileStoneField =

CustomFieldsHelper.GetTaskCustomFieldRow(projectData.TaskCustomFields,
taskUid, isDeliveryMilestoneGuid);
ProjectDataSet.TaskCustomFieldsRow
isProjectCriticalField =

CustomFieldsHelper.GetTaskCustomFieldRow(projectData.TaskCustomFields,
taskUid, isProjectCriticalGuid);
ProjectDataSet.TaskCustomFieldsRow
taskStatusCriticalField =

CustomFieldsHelper.GetTaskCustomFieldRow(projectData.TaskCustomFields,
taskUid, taskStatusCriticalGuid);

bool isDeliveryMilestone = isDeliveryMileStoneField
== null
? false
:
isDeliveryMileStoneField.FLAG_VALUE;
bool isProjectCritical = isProjectCriticalField ==
null
? false
:
isProjectCriticalField.FLAG_VALUE;

decimal taskStatus = taskStatusCriticalField == null
? 0 : taskStatusCriticalField.NUM_VALUE;

// Continue Loop when current task ist not
deliveryMilestone or not ProjectCritical
if (!isDeliveryMilestone && !isProjectCritical)
{
LogEntry entry = new LogEntry();
entry.Message =
string.Format(
"Current Task {0}-{1} is not a MileStone
then nor a project critical task", taskUid,
taskName);
entry.Severity = TraceEventType.Verbose;
if (Logger.ShouldLog(entry))
Logger.Write(entry);

continue;
}
// Set ProjectStatus
projectStatus = Math.Max(projectStatus, taskStatus);

// break loop if TaskStatus has max state
if (projectStatus.Equals(MAX_PROJECTSTATUS))
{
LogEntry entry = new LogEntry();
entry.Message = "projectStatus field has already
the max value.";
entry.Severity = TraceEventType.Verbose;
if (Logger.ShouldLog(entry))
Logger.Write(entry);

break;
}
}

// Set Project status field
ProjectDataSet.ProjectCustomFieldsRow projectStatusField =

CustomFieldsHelper.GetProjecctCustomFieldRow(projectData.ProjectCustomFields,
e.ProjectGuid, projectStatusGuid);
if (projectStatusField == null)
{
Logger.Write("Add new custom field
\"Projektstatus\"");
projectStatusField =
projectData.ProjectCustomFields.NewProjectCustomFieldsRow();
projectStatusField.CUSTOM_FIELD_UID = Guid.NewGuid();
projectStatusField.MD_PROP_UID = projectStatusGuid;
projectStatusField.NUM_VALUE = 0;
projectStatusField.PROJ_UID = e.ProjectGuid;
projectStatusField.FIELD_TYPE_ENUM =
(byte)PSDataType.NUMBER;



projectData.ProjectCustomFields.AddProjectCustomFieldsRow(projectStatusField);
}

Logger.Write(string.Format("Current value of
\"Projektstatus\" {0} => {1}. No Action required if the values are equal.",
projectStatusField.NUM_VALUE, projectStatus));


if (!projectStatusField.NUM_VALUE.Equals(projectStatus))
{
projectStatusField.NUM_VALUE = projectStatus;

ProjectDataSet.ProjectRow projectRow =
(ProjectDataSet.ProjectRow)projectData.Project.Rows[0];
Guid sessionId = projectRow.IsPROJ_SESSION_UIDNull()
? Guid.NewGuid()
: projectRow.PROJ_SESSION_UID;
Guid jobId = e.JobGuid;
Logger.Write("Updateing the current Project.");
project.QueueUpdateProject(jobId, sessionId,
projectData, false);

//TODO: Check wait required !?
int waitTime = queueSystem.GetJobWaitTime(jobId);
Thread.Sleep(waitTime * 1000);

Logger.Write("Publishing the current Project.");
project.QueuePublish(jobId, e.ProjectGuid,
e.FullPublish, "");
}
}
catch (SoapException ex)
{
PSClientError error = new PSClientError(ex);
StringBuilder sb = new StringBuilder();
sb.AppendFormat("An error occurred during
StatusUpdateHandler proccessing:\n");
if (error.HasErrors)
{

foreach(PSErrorInfo errorInfo in error.GetAllErrors())
{
sb.AppendFormat("Error Id: {0} - Error Uid: {1}
- Error Name {2} - Attributes: {3}\n",
errorInfo.ErrId, errorInfo.ErrUid,
errorInfo.ErrName, string.Join(";", errorInfo.ErrorAttributes));
}
}
Logger.Write(sb.ToString());
}
catch (Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex,
"Logging Policy");
if (rethrow)
throw;
}
}
}



#region private methods

private string WsUrl(SPSite ss, string wsName, bool impersonate)
{
if (impersonate)
return string.Format("{0}//{1}:56737/{2}/psi/{3}.asmx",
ss.Protocol, ss.HostName, _sspName,
wsName);

return string.Format("{0}/_vti_bin/psi/{1}.asmx",
ss.Url, wsName);
}

private void LoadSettings()
{
// Load settings from
Microsoft.Office.Project.Server.Eventing.exe.config
_sspName = Properties.Settings.Default.PWASSpName;

Logger.Write(string.Format("Current settings from
Microsoft.Office.Project.Eventing.exe.config: PWASSpName:{0}", _sspName));
}
#endregion
}
}
 
S

Stephen Sanderlin

Ah, I understand now. Unfortunately, no. This is the only way to get
your updated values to display in PWA. Also, be careful to ensure that
you don't start any infinite loops due to the save/publish operation.

--
Stephen Sanderlin
VP of Technology
MSProjectExperts

For Project Server Consulting: http://www.msprojectexperts.com
For Project Server Training: http://www.projectservertraining.com

Read my blog at: http://www.projectserverhelp.com
Join the community at: http://forums.epmfaq.com



yes i can .. sorry it's more than 200 lines

i'll played something arround and I think i have a solution.
I use the Eventhandler OnPublished .. then I do my updates and publish the
project again. But this is slow because I had to publish a second time.
Is there any other way to do this?

Here's the code:

using System;
using System.Net;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.SharePoint;
using ProjectStatusUpdate.Helpers;
using ProjectStatusUpdate.ProjectWebSvc;
using ProjectStatusUpdate.PSI;
using DataStoreEnum = ProjectStatusUpdate.ProjectWebSvc.DataStoreEnum;
using PSLib = Microsoft.Office.Project.Server.Library;
using System.Diagnostics;
using System.Threading;
using Microsoft.Office.Project.Server.Library;
using System.Web.Services.Protocols;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

namespace ProjectStatusUpdate
{
public class StatusUpdateHandler :
Microsoft.Office.Project.Server.Events.ProjectEventReceiver
{

// Loaded from ApplicationSettings
private string _sspName = "";

private const double MAX_PROJECTSTATUS = 3.0;
private const string IS_DELIVERY_MILESTONE_NAME =
"SMK_IsDeliveryMilestone";
private const string IS_PROJECT_CRITICAL_NAME =
"SMK_IsProjectCritical";
private const string TASK_STATUS_CRITICAL_NAME =
"SMK_TaskStatusCritical";
private const string PROJECT_STATUS_NAME = "Projektstatus";

public override void OnPublished(PSContextInfo contextInfo,
Microsoft.Office.Project.Server.Events.ProjectPostPublishEventArgs e)
{
base.OnPublished(contextInfo, e);

DoWork(contextInfo, e);
}

private void DoWork(IPSContextInfo contextInfo,
Microsoft.Office.Project.Server.Events.ProjectPostPublishEventArgs e)
{
using (new Tracer("StatusUpdateHandler", e.ProjectGuid))
{
Logger.Write("StatusUpdateHandler started...");

LoadSettings();
try
{
ProjectDerived project;
CustomFieldsDerived customFields;
QueueSystemDerived queueSystem;


using (SPSite spSite = new SPSite(contextInfo.SiteGuid))
{
project = new ProjectDerived();
project.Credentials =
CredentialCache.DefaultCredentials;
project.Url = WsUrl(spSite, "project", true);

customFields = new CustomFieldsDerived();
customFields.Credentials =
CredentialCache.DefaultCredentials;
customFields.Url = WsUrl(spSite, "customfields",
false);

queueSystem = new QueueSystemDerived();
queueSystem.Credentials =
CredentialCache.DefaultCredentials;
queueSystem.Url = WsUrl(spSite, "queuesystem", false);
}

Guid taskEntityId = new
Guid(EntityCollection.Entities.TaskEntity.UniqueId);
Guid projectEntityId = new
Guid(EntityCollection.Entities.ProjectEntity.UniqueId);


Guid isDeliveryMilestoneGuid =
FieldNameToGuid.GetGuidUsingFieldName(customFields,

IS_DELIVERY_MILESTONE_NAME,

taskEntityId);
Guid isProjectCriticalGuid =
FieldNameToGuid.GetGuidUsingFieldName(customFields,

IS_PROJECT_CRITICAL_NAME,

taskEntityId);
Guid taskStatusCriticalGuid =
FieldNameToGuid.GetGuidUsingFieldName(customFields,

TASK_STATUS_CRITICAL_NAME,

taskEntityId);
Guid projectStatusGuid =
FieldNameToGuid.GetGuidUsingFieldName(customFields,

PROJECT_STATUS_NAME,

projectEntityId);


bool isWindowsUser = contextInfo.IsWindowsUser ||
contextInfo.UserName.Contains("\\");
project.SetImpersonationContext(isWindowsUser,
contextInfo.UserName,
contextInfo.UserGuid,
contextInfo.TrackingGuid, contextInfo.SiteGuid,
contextInfo.Lcid);
Logger.Write(string.Format("Read Project {0}-{1} from
Server", e.ProjectGuid, e.ProjectName));

ProjectDataSet projectData =
project.ReadProject(e.ProjectGuid, DataStoreEnum.WorkingStore);

decimal projectStatus = 0;

// detect the max task status
foreach (ProjectDataSet.TaskRow task in
projectData.Task.Rows)
{
Guid taskUid = task.TASK_UID;
string taskName = task.TASK_NAME;


ProjectDataSet.TaskCustomFieldsRow
isDeliveryMileStoneField =

CustomFieldsHelper.GetTaskCustomFieldRow(projectData.TaskCustomFields,
taskUid, isDeliveryMilestoneGuid);
ProjectDataSet.TaskCustomFieldsRow
isProjectCriticalField =

CustomFieldsHelper.GetTaskCustomFieldRow(projectData.TaskCustomFields,
taskUid, isProjectCriticalGuid);
ProjectDataSet.TaskCustomFieldsRow
taskStatusCriticalField =

CustomFieldsHelper.GetTaskCustomFieldRow(projectData.TaskCustomFields,
taskUid, taskStatusCriticalGuid);

bool isDeliveryMilestone = isDeliveryMileStoneField
== null
? false
:
isDeliveryMileStoneField.FLAG_VALUE;
bool isProjectCritical = isProjectCriticalField ==
null
? false
:
isProjectCriticalField.FLAG_VALUE;

decimal taskStatus = taskStatusCriticalField == null
? 0 : taskStatusCriticalField.NUM_VALUE;

// Continue Loop when current task ist not
deliveryMilestone or not ProjectCritical
if (!isDeliveryMilestone && !isProjectCritical)
{
LogEntry entry = new LogEntry();
entry.Message =
string.Format(
"Current Task {0}-{1} is not a MileStone
then nor a project critical task", taskUid,
taskName);
entry.Severity = TraceEventType.Verbose;
if (Logger.ShouldLog(entry))
Logger.Write(entry);

continue;
}
// Set ProjectStatus
projectStatus = Math.Max(projectStatus, taskStatus);

// break loop if TaskStatus has max state
if (projectStatus.Equals(MAX_PROJECTSTATUS))
{
LogEntry entry = new LogEntry();
entry.Message = "projectStatus field has already
the max value.";
entry.Severity = TraceEventType.Verbose;
if (Logger.ShouldLog(entry))
Logger.Write(entry);

break;
}
}

// Set Project status field
ProjectDataSet.ProjectCustomFieldsRow projectStatusField =

CustomFieldsHelper.GetProjecctCustomFieldRow(projectData.ProjectCustomFields,
e.ProjectGuid, projectStatusGuid);
if (projectStatusField == null)
{
Logger.Write("Add new custom field
\"Projektstatus\"");
projectStatusField =
projectData.ProjectCustomFields.NewProjectCustomFieldsRow();
projectStatusField.CUSTOM_FIELD_UID = Guid.NewGuid();
projectStatusField.MD_PROP_UID = projectStatusGuid;
projectStatusField.NUM_VALUE = 0;
projectStatusField.PROJ_UID = e.ProjectGuid;
projectStatusField.FIELD_TYPE_ENUM =
(byte)PSDataType.NUMBER;



projectData.ProjectCustomFields.AddProjectCustomFieldsRow(projectStatusField);
}

Logger.Write(string.Format("Current value of
\"Projektstatus\" {0} => {1}. No Action required if the values are equal.",
projectStatusField.NUM_VALUE, projectStatus));


if (!projectStatusField.NUM_VALUE.Equals(projectStatus))
{
projectStatusField.NUM_VALUE = projectStatus;

ProjectDataSet.ProjectRow projectRow =
(ProjectDataSet.ProjectRow)projectData.Project.Rows[0];
Guid sessionId = projectRow.IsPROJ_SESSION_UIDNull()
? Guid.NewGuid()
: projectRow.PROJ_SESSION_UID;
Guid jobId = e.JobGuid;
Logger.Write("Updateing the current Project.");
project.QueueUpdateProject(jobId, sessionId,
projectData, false);

//TODO: Check wait required !?
int waitTime = queueSystem.GetJobWaitTime(jobId);
Thread.Sleep(waitTime * 1000);

Logger.Write("Publishing the current Project.");
project.QueuePublish(jobId, e.ProjectGuid,
e.FullPublish, "");
}
}
catch (SoapException ex)
{
PSClientError error = new PSClientError(ex);
StringBuilder sb = new StringBuilder();
sb.AppendFormat("An error occurred during
StatusUpdateHandler proccessing:\n");
if (error.HasErrors)
{

foreach(PSErrorInfo errorInfo in error.GetAllErrors())
{
sb.AppendFormat("Error Id: {0} - Error Uid: {1}
- Error Name {2} - Attributes: {3}\n",
errorInfo.ErrId, errorInfo.ErrUid,
errorInfo.ErrName, string.Join(";", errorInfo.ErrorAttributes));
}
}
Logger.Write(sb.ToString());
}
catch (Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex,
"Logging Policy");
if (rethrow)
throw;
}
}
}



#region private methods

private string WsUrl(SPSite ss, string wsName, bool impersonate)
{
if (impersonate)
return string.Format("{0}//{1}:56737/{2}/psi/{3}.asmx",
ss.Protocol, ss.HostName, _sspName,
wsName);

return string.Format("{0}/_vti_bin/psi/{1}.asmx",
ss.Url, wsName);
}

private void LoadSettings()
{
// Load settings from
Microsoft.Office.Project.Server.Eventing.exe.config
_sspName = Properties.Settings.Default.PWASSpName;

Logger.Write(string.Format("Current settings from
Microsoft.Office.Project.Eventing.exe.config: PWASSpName:{0}", _sspName));
}
#endregion
}
}


:

Can you please post your code?

--
Stephen Sanderlin
VP of Technology
MSProjectExperts

For Project Server Consulting: http://www.msprojectexperts.com
For Project Server Training: http://www.projectservertraining.com

Read my blog at: http://www.projectserverhelp.com
Join the community at: http://forums.epmfaq.com
 
J

Joachim Jauß

ok .. thx stephen.

I check the previous saved value before i process the updates. so i can
prevent the infinite loop ..
 
L

Lars Egelund

Hi There

Thanks for some inspiring code for updating custom fields.

How do I get the code for this statement:
CustomFieldsHelper.GetProjecctCustomFieldRow(projectData.ProjectCustomFields,

e.ProjectGuid, projectStatusGuid); ??

Br, Lars

url:http://www.ureader.com/msg/11173528.aspx
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top