Creating and Updating Work Items via OData for TFS
Join the DZone community and get the full member experience.
Join For FreeIn the last two posts we saw how to consume data via OData Service for TFS. Today we are going to create and update Work Items using the service. Create a new console application project, add a service reference to the OData service and create your context (like in the earlier posts).
Creating Work Items
Work Item is created via the TFSServiceReference.WorkItem.CreateWorkItem method. The method accepts four parameters:
- ID – set to 0 since you are creating a new Work Item
and you cannot specify an ID. If you use an existing ID on the server,
you will get the following error:
TF400276: You have tried to set a value for a field of a work item which is not opened or partial opened. You cannot set a value for a field of a work item which is not opened or partial opened.
If you specify a non-existing ID, you will get an ArgumentNullException on the service side.
- revision – set to 0 since newly created Work Item has revision 1. Value is unused.
- createdDate – Value is unused.
- changedDate – Value is unused.
Once you create a WorkItem, you add it to the context using the AddToWorkItems method and you call SaveChanges to save the changes on the server. However, some fields are required and you should not leave them blank: Title, Type and Project.
The latter two fields are required by the OData Service since they
indicate in which project WI will be created and which type will be used
since there are lot of different types on the server. The former field
is required by the Work Item type and this is specified on the server.
Some Work Item Types may have several required fields, all of which must
be filled before creating.
We can now write a code that will create a Work Item:
private static void CreateWorkItem(TFSData context) { var workItem = WorkItem.CreateWorkItem(0, 2, DateTime.Now, DateTime.Now); workItem.Title = "New Work Item"; workItem.Description = "Created via OData service."; workItem.Type = "Task"; workItem.Project = "BasicScrumProject"; context.AddToWorkItems(workItem); context.SaveChanges(); Console.WriteLine(String.Format("Work item created")); }
When we run the above program, the new Work Item will be created. You
can verify that by checking in the Team Explorer, you should find a
Work Item that looks similar to the image below.
You can check for errors by examining the return values of the SaveChanges method. Unfortunately, there is no way to find out which Work Item ID was assigned to the created Work Item. The local variable workItem is not updated after saving changes.
Asynchronous creating
The SaveChanges method has its asynchronous counterpart which are always preferred to the synchronous version. If you are targeting .NET Framework 4, use the old Begin/End pattern:
context.BeginSaveChanges((ar) => { var response = context.EndSaveChanges(ar); if (!response.Any(item =>item.Error != null)) Console.WriteLine(String.Format("Work item created")); else Console.WriteLine(String.Format("An error occurred")); }, null);
If you are targeting .NET 4.5 or you have Async CTP installed for VS 2010, you can use the new async/await model. The function looks more elegant this way:
private static async Task CreateWorkItem(TFSData context) { // ...code omitted... try { var response = await context.SaveChangesAsync(null); if (!response.Any(item =>item.Error != null)) Console.WriteLine(String.Format("Work item created")); else Console.WriteLine(String.Format("An error occurred")); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }
Updating Work Items
You can retrieve individual resources from the service via specially crafted links. We are going to fetch Work Item by its ID. For example, to fetch Work Item with ID 2 you use the TFSData.Execute method:
var wi = context.Execute<WorkItem>(new Uri(context.BaseUri + "/WorkItems(2)", UriKind.Absolute)).SingleOrDefault();
I will cover the advanced resource retrieval in one of the next posts in the series.
If the value returned is null, that means that Work Item with the specified ID does not exist. Otherwise, you have a valid Work Item object and you can update its fields with the new values. To update the object on the server you must first inform the context that this object has been updated (since there is no tracking by default) and then save the changes. Example code:
wi.Title = "New title for Work Item"; context.UpdateObject(wi); var response = context.SaveChanges(SaveChangesOptions.ReplaceOnUpdate);
The Work Item has been updated and you can see the change on the Work Item Edit form.
The parameter SaveChangesOptions.ReplaceOnUpdate is necessary, without specifying it the sample above does not work.
Asynchronous updating
It is important to note that since there are two overloads of the SaveChanges function, you need to be careful how to write the async code. You must specify both arguments if you wish to save changes since otherwise the overload with the single parameter would be selected.
Example code:
private static async Task UpdateWorkItemAsync(TFSData context) { var wi = (await context.ExecuteAsync<WorkItem>(new Uri(context.BaseUri + "/WorkItems(2)", UriKind.Absolute), null)).SingleOrDefault(); if (wi == null) { Console.WriteLine("No such Work Item"); return; } Console.WriteLine("Work Item with id {0} has title '{1}'", wi.Id, wi.Title); try { wi.Title = "New title for Work Item"; context.UpdateObject(wi); var response = await context.SaveChangesAsync(SaveChangesOptions.ReplaceOnUpdate, null); if (HandleResponseErrors(response)) Console.WriteLine("Title changed"); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }
That is all for managing Work Items. In the next post I will cover creating attachments before covering filtering, projects and advanced resource retrieval.
Entries in this series:- Installing and configuring OData Service for TFS 11
- Consuming OData for TFS using C#
- Consuming OData for TFS using C# from Windows Phone 7 application
- Creating and updating Work Items via OData for TFS
Opinions expressed by DZone contributors are their own.
Comments