I am trying to set the value of a task level custom field using CSOM and I am running into a problem when there is no existing value and therefore no custom field object.
I have created three Task entity custom fields by going to Server Settings -> Enterprise Custom Fields and Lookup Tables.
If I add values to the custom fields when editing the project in the browser, the custom field objects exist for those tasks; all with the same id as the original ones I created and I can modify them through code.
If I try to set a custom field value in code for a task for the first time, it does not work and I get an "unknown error" (more below).
In my code I am trying to update these fields for the tasks as such:
private static DraftTask UpdateTaskCustomFields(DraftTask task, string taskDescription, string resourceId, double estRunHours, double actRunHours)
{
if (task == null) return null;
projectContext.Load(task.CustomFields);
projectContext.ExecuteQuery();
task["Custom_0000740fd5a8e41180e0005056823bd3"] = taskDescription;
task["Custom_85e91d7fd5a8e41180e0005056823bd3"] = estRunHours;
task["Custom_a178dc8bd5a8e41180e0005056823bd3"] = actRunHours;
task.CustomFields.Update();
return task;
}
I call this method from another in the following block:
foreach (DataRow parentTask in parentTasks.Tables[0].Rows)
{
var parentTaskName = "";
var taskName = string.Format("{0}.{1}", parentTask["LOT_ID"], parentTask["SPLIT_ID"]);
var taskDescription = parentTask["WO_DESCRIPTION"].ToString();
var estRunHours = Convert.ToDouble(parentTask["RUN_HRS"]);
var actRunHours = Convert.ToDouble(parentTask["ACT_RUN_HRS"]);
var resourceId = "";
var task = GetTask(tasks, taskName);
if (task != null)
{
UpdateTaskCustomFields(task, taskDescription, resourceId, estRunHours, actRunHours);
itemCount += 3;
}
if (itemCount++ < batch) continue;
itemCount = 0;
if (!UpdateDraft(projectDraft)) ExitApp();
}
On the very first task, it calls the UpdateTaskCustomFields method without any errors but on the second task, the following error is thrown on the projectContext.ExecuteQuery() call:
Microsoft.SharePoint.Client.ServerException was unhandled
HResult=-2146233088
Message=Unknown Error
Source=Microsoft.SharePoint.Client.Runtime
ServerErrorCode=-1
ServerErrorTraceCorrelationId=b58ee69c-a7fb-40f8-19b2-171646b3a6c8
ServerErrorTypeName=Microsoft.SharePoint.Client.UnknownError
ServerStackTrace=""
StackTrace:
at Microsoft.SharePoint.Client.ClientRequest.ProcessResponseStream(Stream responseStream)
at Microsoft.SharePoint.Client.ClientRequest.ProcessResponse()
at Microsoft.SharePoint.Client.ClientRequest.ExecuteQueryToServer(ChunkStringBuilder sb)
at Microsoft.SharePoint.Client.ClientRequest.ExecuteQuery()
at Microsoft.SharePoint.Client.ClientRuntimeContext.ExecuteQuery()
at Microsoft.SharePoint.Client.ClientContext.ExecuteQuery()
at QueueCreateProject.Program.UpdateTaskCustomFields(DraftTask task, String taskDescription, String resourceId, Double estRunHours, Double actRunHours) in c:\Projects\ProjectServerApp\ProjectServerApp\Program.cs:line 617
at QueueCreateProject.Program.ImportTasksFromVisual() in c:\Projects\ProjectServerApp\ProjectServerApp\Program.cs:line 208
at QueueCreateProject.Program.Main(String[] args) in c:\Projects\ProjectServerApp\ProjectServerApp\Program.cs:line 41
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
I thought maybe I also needed to add the custom field directly to the task first but that gave me an error about the field already existing/reserved.
I am assuming that either my whole process is wrong or I need to instantiate the custom field for the task in some manner or something similar but I have no clue as to what to do.
Any help would be appreciated.
Thanks!
Wg
Peter Holpar, MVP was able to sort out my issue here.
He provided me with an example and I used it to figure out what I was doing wrong.
The internal name of the custom field was invalid so I got the custom field object by name first (from the projectContext.CustomFields collection, not the task CustomFields collection) and then set the value.
The thread shows the process I went through but here's the final working code; I hope it helps someone else in the same boat.
using (projectContext = new ProjectContext(pwaPath))
{
projectContext.Load(projectContext.Projects, ps => ps.Include(p => p.Name));
projectContext.Load(projectContext.CustomFields);
projectContext.ExecuteQuery();
var proj = projectContext.Projects.FirstOrDefault(p => p.Name == projectName);
var cfInternalName = projectContext.CustomFields.FirstOrDefault(q => q.Name == "Task Description").InternalName;
var draftProj = proj.CheckOut();
projectContext.Load(draftProj, p => p.Tasks.Include(t => t.Id, t => t.Name, t => t.Parent));
projectContext.ExecuteQuery();
var tasks = draftProj.Tasks;
var draftTask = tasks.FirstOrDefault(q => q.Name == "1.0");
draftTask[cfInternalName] = "My Description";
draftProj.Publish(true);
projectContext.ExecuteQuery();
}
Wg