We don't seem to have done a good job in educating our customers on this topic, so thought I'd put this out there at least as a starting point and I'm sure we can also try and get better samples in the SDK.
One of the tricky things with setting custom fields for any entity (Project, Resource or Task - but also assignment or timesheet) is that you cannot always just call up the dataset, navigate to the custom field row and set the value. In many cases the row may not yet exist, so you need to add it, then set all the required properties and then update back through the PSI.
As an example if you create a project through the PSI it will have no project level custom field rows created by default, (except ones based on Lookup Tables with a default value forced) and any tasks will only have the "Health" special custom field set, and again- any with Lookup Table defaults. If you then open in Project Professional and just save again, you will then have added any calculated fields at the project level, along with any calculated fields at the task level. Also at this stage the project summary task (Task 0) is populated with any task level fields with roll up to summary level set.
As my server does not have all the possible combinations of fields I may be missing something here - but ProjTool is a great way to see just what is in the dataset at any time.
So whenever you are setting custom fields first see if the row already exists - and if not you will need to add a customfieldrow to whatever dataset you are working with. Then the next step is to set the appropriate properties - which will depend on the type of field you are setting (defined by FIELD_TYPE_ENUM), and the dataset you are adding it to. For instance a ProjectCustomFieldsRow will need the PROJ_UID. A TaskCustomFieldsRow will need the PROJ_UID and the TASK_UID. A Timesheet CustomFieldsRow will need the TS_UID to identify the timesheet and a TS_LINE_UID to identify the specific line. Then for any row you need to set a new GUID for the CUSTOM_FIELD_UID, the MD_PROP_UID and/or the MD_PROP_ID to identify the specific custom field and the actual value you want to set in the appropriate property as detailed in the following table.
Set field value in:
Value in 1/COST_MULTIPLIER dollars
A date value. HIWORD contains days off set from 1/1/84. LOWORD contains minute off-set, ranging from 0 to 1440, from 12:00 A.M. (midnight)
Value in 1/DUR_MULTIPLIER minutes
DUR_VALUE and DUR_FMT
A string value
Index into yes/no string table
A number value
FINISHDATE is also listed in the SDK but is not applicable to these custom fields. Lookup Table isn't specifically a custom field type - but I added it for completeness. If the custom field is based on a Lookup Table then the LT_STRUCT_UID of the specific entry in the Lookup Table is entered in the CODE_VALUE property. For those that accept multiple values there will be a row with each CODE_VALUE - not a single row with multiple CODE_VALUES.
Another property you will come across in the datasets is the INDICATOR_VALUE - which will hold the enumeration value for the indicator to be displayed based on the custom field settings.
No code sample just yet on this - but I will try and come up with some shortly. I am looking into a support incident where values are being set for summary tasks (or rather they are not) - these are likely to be read-only if "roll-up" is set, so be aware of that.
*** Update *** Finally got a sample together - hope it is worth the wait - http://blogs.msdn.com/b/brismith/archive/2010/08/25/project-server-adding-custom-fields-to-projects-and-tasks-using-the-psi.aspx
The ProjCFDlg.cs sample in ProjTool and the Add Project Custom Field option on the Project Details pane of ProjTool is a great place to look for an example that covers this well.
Other things to be aware of are that constraints applied to the custom fields will need to be adhered to. If the custom field only allows selection of codes with no subordinate value (leaf nodes) then the PSI cannot over-ride this.
for a customer project, i use custom cost task fields, to synchronize SAP cost values with project tasks in the Project Server 2007 SP1.
Using the following steps, it works well in my test environment and in production environment with about 70% of the real customer projects.
1. Read project
2. Add or update task custom fields (summary, subproject, external ... tasks are filtered out)
3. Get updated task custom fields (DataRowState.Modified)
4. Update project
3. Get added task custom fields (DataRowState.Add)
4. Add to project
Unfortunatelly, i am not able to synchronize several projects, because PSI throws exceptions, like the following two.
If you open these projects with Project Professional, they behave normal.
<error id="9133" name="ProjectSchedulingEngineException"
exception="Microsoft.Office.Project.Scheduling.SchedulingCycleException: Cycle detected.
at Microsoft.Office.Project.Server.BusinessLayer.ProjectMain.HandleProject(ProjectDataSet dataset,
Guid projectUid, Guid userUid, String userName, Boolean isNew, Boolean addColumns, ProjectLocks projectLock,
Boolean fCheckReadOnly, Boolean fCheckProtectedActuals, Boolean fAllowAddEntRes)
Item = c1c05c93-94be-463c-9ec2-7ade4eb0a131,
Link = 00000000-0000-0000-0000-000000000000" />
<error id="9131" name="GeneralQueueException"
exception="System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.Office.Project.Server.DataAccessLayer.SchedulingDal.ReadSchedulingData(SqlDataReader reader)
at Microsoft.Office.Project.Server.DataAccessLayer.SchedulingDal.LoadProjectData(Guid projectID)
at Microsoft.Office.Project.Server.BusinessLayer.SchedulingData.LoadData(Boolean isDelete)
at Microsoft.Office.Project.Server.BusinessLayer.ProjectMain.LoadSchedulingData(Boolean isDelete, Int32 revisionCounter)
Guid projectUid, Guid userUid, String userName, Boolean isNew, Boolean addColumns,
ProjectLocks projectLock, Boolean fCheckReadOnly, Boolean fCheckProtectedActuals,
at Microsoft.Office.Project.Server.BusinessLayer.ProjectMain.HandleProject(ProjectDataSet dataset,
Guid projectUid, Guid userUid, String userName, Boolean isNew, Boolean addColumns, ProjectLocks projectLock)
at Microsoft.Office.Project.Server.BusinessLayer.ProjectQueueDispatch.HandleProject(MessageContext mContext,
ProjectMain project, ServerEventManager sem, ProjectDataSet dataset, Guid projectUid, Guid userUid,
String userName, Boolean isNew, Boolean addColumns, ProjectLocks projectLock)
context, Message msg, Group messageGroup, JobTicket jobTicket, MessageContext mContext)" />
This looks to me, as if the PSI methods use stronger validation rules, than Project Professional does.
Is there any way, only to add/update custom fields, without validating or re-scheduling the whole project?
ANY information would be appreciated!
Thank you very much in advance
Is there any pattern to your errors? If you try and just add - or update - and not use the Modified/Add to filter the dataset does this work?
thank you very much for your time.
Unfortunately i can't see any error pattern at the moment, but next week one of our Project consultants will have closer look on these projects.
Is there any example available, which project structure causes a "SchedulingCycleException"?
I think, it can't be a circular task relationship, because the Project Client doesn't allow this.
In a first software version a tried the following concept:
2. Add or update task custom fields
3. Update project
I discarded it, because i got "CustomFieldRequiredValueNotProvided" exceptions for required enterprise fields on *project* level.
These data were definitely in place, because otherwise the project could not have been created.
Thank you very much
I have seen that error too, when using the Codeplax tool on a server where no custom fields are set as required - so there appears to be a spurious error message.
As for the SchedulingCycleException error the only thing I see is in the SDK (see below). Could any of this apply? I also don;t see any current unfixed bugs relating to the message - but you could have found a new one...
If you try to change the TASK_OUTLINE_LEVEL using QueueUpdateProject, you can get a ProjectSchedulingEngineException error from the Project Server Queuing Service. The error contents include exception="Microsoft.Office.Project.Scheduling.SchedulingCycleException: Cycle detected …. The Project Server scheduling engine does not handle bulk edits where you change the TASK_OUTLINE_LEVEL or change a task with a Start-to-Finish (SF) link into a summary task. A workaround is to check the Project Server Queue and handle the specific value in the QueueStatusDataSet.Status table. For example, return a message to use Project Professional to change the TASK_OUTLINE_LEVEL.
I've noticed issues using CodePlex/sample/SDK code examples to insert values into custom cost fields.
1. When adding to the PSI, Cost values should be multiplied by 100. This was true in previous versions of Project Server as well.
2. Custom duration fields had a multiplier as well.
3. Incoming cost values should always be stripped of non-numeric characters so as not to get the error "Input string was not in a correct format".
The PWA UI/business layer handles this appropriately, but tools like EPMSync on CodePlex, ProjTool in the SDK, and sample code to insert custom cost/duration fields do not do these things. For costs, it results in values displayed in Project Server being 1% of their real value.
In your post above (and in the SDK) I've found the following Description for Cost:
Value in 1/COST_MULTIPLIER dollars
I would assume this is a constant or property somewhere but I have never found it anywhere in the SDK/API. Does it exist somewhere? In the case of U.S. dollars this value would be 0.01
Could someone please inform the SDK team and those responsible for the code samples to correct their information? The incorrect code examples are getting used by everyone else "showing how to code it", albeit incorrectly.
Thanks for this feedback Paul If you haven't already then please go to the MSDN SDK pages and also post this as community content. I will pass it along too.
Thats was a very helpful piece of information about MS Project. I need information about Validation.
A text field is string so it'll accept alphanumeric data as well all the special symbols.
What if I just want only alphanumeric data and not any special symbol.
Is there any way to validate a text field?
Nothing built in - so you would need to do this yourself, but it would be tricky. You could add it as VBA on the client, but then this doesn't stop changes through PWA. You could use event handlers on the server - but you would then need a good feedback mechanism as it you can easily validate - but how do you tell the potentially disconnected client that the value was invalid. Exception reporting would be one way - then correct the problem after the event. A final option is to modify the web page in PWA and add validation there. This takes you into the realms of unsupportability - which doesn't mean you shouldn't do it - just that you need to keep the old clean page in case you have issues - as we would want to be sure issues do not relate to your customization.
Hi All Of You,
How can Create project from project in PSI.Suppose in MSP open project and save it after that how it save as project in psi.
ANy help is appreciated.
Thanks In Advance
I'm not sure what your scenario is here and why you wouldn't just save to the server. You could certainly create an add-in that used the object model to read the current project details and then used PSI to create a project on the server - but can't think why you would ever need to.
You can also use the PSI to create a project from a template - so save as a template and then using the CreateProjectFromTemplate method of the Project web service might work for you.
I have a problem setting task custom field values via PSI having a lookup table and a default value.
If I create a new TaskCustomFieldRow with the correct CODE_UID and send it to the ProjectServer the error message CustomFieldMaxValuesExceeded is thrown.
This message must be wrong. There is also no description for this error on the Microsoft sites.
So I played around with this issue and found out that removing the default value for that custom field successfully creates the task custom field value.
I also installed all available updates and hotfixes without success.
Do you have any idea for a workaround where I can keep this default value and create the custom field value without the error message?
By the way: The problem occurs only for the task custom fields. Project custom field values are created without any errors.
I haven't heard of this issue - but just want to re-state to ensure I have it right. So if you have a Task CF based on a Lookup Table with values Red, Green and Blue where Red is set as the default you cannot set any value for the Task CF. But if you remove the default value you can set it OK to whichever value you require?
Does this only occur for new tasks? Can you update the task CF's that presumably already contain the default value?
It certainly sounds like you have found a bug.
exactly! This only occurs for new tasks.
If I do have a default value set, creating a new TaskCustomFieldRow with any of the loolup table values in CODE_VALUE fails with the error message mentioned above.
If I do not create a new TaskCustomFieldRow on my own, the default value is set for the task automatically.
Updateing the existing TaskCustomFieldRow afterwards with any of the other values works fine.
We added one numeric custom field for each task. This custom field represents the key to the task in our system. Everythig works fine (using PSI) unless we add two or more sub projects into one project. Those sub projects become tasks so we want to link them with our system. But we receive an error (during check-in): GeneralQueueException... SchedulingException: The ITask Table already contains this task.
But there is no custom field on second or third sub project. When we add these custom field in Project Proffesional for both sub projects it works. But this is not a solution.
I am encountering a strange problem in project data set.
In project data set i am getting same Project Custom Field multiple times with the same value.
Is it possible if yes how can can put a constraint so that project custom field should only come once in project data set.
Thanks and Regards,