This is a known limitation (from a user’s perspective that is, obviously Microsoft had a good reason to design it this way) – you cannot edit fields like the Created, Modified, Created By, Modified By, etc using the standard SharePoint Lists web service and its UpdateListItems method (Updated 2011-1-20 – the Created By (Author) and Modified By(Editor) fields can be updated in this manner only for non-library SharePoint lists). On the other hand using the object model with SPListItem.UpdateOverwriteVersion or SPWeb.ProcessBatchData you can easily modify the values of read-only fields. And back to the Lists web service – I recently found a small work-around to this issue – the idea is quite simple – if the problem is with read-only fields why just not change the ReadOnly attribute in the field’s schema and check to see whether this will work. I tested the schema changing and it turned out that the UpdateListItems method was now able to change the values of the modified fields. The next question is whether it is possible to make this field schema change with a web service – the answer is again yes – the Lists web service has the UpdateList method which allows among other things to modify the schema of the fields in the list. So, combining the two methods it is possible to first call UpdateList and change the fields whose values should be modified to non read-only, then call UpdateListItems and update the values in the list items and finally call UpdateList again to have the read-only attribute set back to the original value (check the sample code snippet below). Note here that setting the ReadOnly schema attribute back to TRUE is necessary otherwise you will see some side effects like the fields appearing in the new and edit forms of the list, the Modified field will stop reflecting the last modified date, etc. Another important note – if the field is sealed (its “Sealed” attribute is set to TRUE) – the Lists.UpdateList cannot update its schema so the whole approach is unusable in this case (unless you set the “Sealed” attribute to false with the object model or a tool which further complicates the issue).
And now several words about the disadvantages of this work-around (a little attempt to discourage you from using it) – let me start with the schema changes – it is obviously not natural to change the schema of the list (or its children) to get an update of its list items right, another thing is that these schema changes and reverts will become a real mess if you try to run several updates simultaneously. So my advice would be that this approach should be used only in a one-time batch updates and/or when there is really no alternative to using the standard SharePoint web services (no option for using the object model or to create and deploy a custom web service).
And here is a small sample code snippet that demonstrates this work-around:
public void Test()
{
string webUrl = "http://myserver";
string listName = "docs";
Lists.ListsSoapClient listsClient = this.GetListsClient(webUrl);
// 1st a call to Lists.GetList - we need the list's version - it is returned in the Version attribute
XElement listData = XElement.Parse(listsClient.GetList(listName).OuterXml);
string listID = listData.Attribute("ID").Value;
string version = listData.Attribute("Version").Value;
// in the updateFields parameter of Lists.UpdateList the full schema of the fields should be provided
string updateFields = @"<Fields>
<Method ID='1'>
<Field ID='{28cf69c5-fa48-462a-b5cd-27b6f9d2bd5f}' ColName='tp_Modified' RowOrdinal='0' ReadOnly='FALSE' Type='DateTime' Name='Modified' DisplayName='Modified' StorageTZ='TRUE' SourceID='http://schemas.microsoft.com/sharepoint/v3' StaticName='Modified' FromBaseType='TRUE' Version='4' ShowInNewForm='FALSE' ShowInEditForm='FALSE' />
</Method>
<Method ID='2'>
<Field ID='{8c06beca-0777-48f7-91c7-6da68bc07b69}' ColName='tp_Created' RowOrdinal='0' ReadOnly='FALSE' Type='DateTime' Name='Created' DisplayName='Created' StorageTZ='TRUE' SourceID='http://schemas.microsoft.com/sharepoint/v3' StaticName='Created' FromBaseType='TRUE' Version='4' ShowInNewForm='FALSE' ShowInEditForm='FALSE' />
</Method>
</Fields>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(updateFields);
// Lists.UpdateList: set fields to not read-only
XElement result = XElement.Parse(listsClient.UpdateList(listID, null, null, doc.DocumentElement, null, version).OuterXml);
// get updated version from the result XML - for the second call of Lists.UpdateList
version = result.Elements().Where(el => el.Name.LocalName == "ListProperties").First().Attribute("Version").Value;
// prepare the XML for the list item update
string updateDates = @"<Batch OnError='Continue'>
<Method ID='M0' Cmd='Update'>
<Field Name='ID'>1</Field>
<Field Name='FileRef'>/docs/zt.txt</Field>
<Field Name='Modified'>2010-04-04T22:17:00Z</Field>
<Field Name='Created'>2010-01-01T00:05:00Z</Field>
</Method>
</Batch>";
doc.LoadXml(updateDates);
// Lists.UpdateListItems: update Created & Modified
result = XElement.Parse(listsClient.UpdateListItems(listID, doc.DocumentElement).OuterXml);
// revert the fields' schema
updateFields = updateFields.Replace("ReadOnly='FALSE'", "ReadOnly='TRUE'");
doc.LoadXml(updateFields);
// Lists.UpdateList: set fields back to read-only
result = XElement.Parse(listsClient.UpdateList(listID, null, null, doc.DocumentElement, null, version).OuterXml);
}
The code demonstrates how to update the Created and Modified fields of a document library item (check the comments inside the code for more details). Note that this is a sample quality code and you shouldn’t use it directly without serious improvements – for example using a try-finally block with the second call to the Lists.UpdateList method placed in the “finally” block; adding an extra call to Lists.GetList to get a fresh value of the “Version” attribute of the list, just before the second list update, etc.