SPWeb.ProcessBatchData вызывает ошибку “Value does not fall within the expected range”
На днях мне надо было удалить все элементы списка и сначала я попробовал удалять их вызывая метод Delete() перебирая каждый из элементов списка.
Function Clear-List([Microsoft.SharePoint.SPList]$list) {
$list.Items | ForEach-Object { $_.Delete() }
}
Заработало, но я был крайне неудовлетворен скоростью работы – на удаление одного элемента уходило 2-3 секунды. Такая низкая производительно вынудила меня начать поиски иных решений, в процессе которых я наткнулся на статью http://merill.net/2008/02/efficiently-delete-purge-all-items-from-a-sharepoint-list/. В статье описан подход, который решал возникшую перед мной проблему и я не долго думая написал свою процедуру, но при этом воспользовался XmlTextWriter вместо StringBuilder для создание строки запроса.
Когда я запустил новоиспеченную процедуру, я был удивлен тем, что она не захотела работать. Метод ProcessBatchData вызывал ошибку Value does not fall within the expected range exception без каких либо видимых причин, мое удивление удвоилось, когда воспользовавшись кодом из оригинальной статью элементы удалились.
Меня это все очень завлекло и я начал сводить отличия между двумя методами к нулю. В итоге я был потрясен, когда причиной ошибки оказалось различие в регистре объявления кодировки XML документа.
Не работающий вариант декларации документа созданный XmlTextWriter.WriteStartDocument():
<?xml version="1.0" encoding="utf-8"?>
Работающий вариант декларации документа созданный кодом из статьи:
<?xml version="1.0" encoding="UTF-8"?>
Выглядит как «баг» в методе ProcessBatchData – возможно, когда-нибудь я открою кейс по этому вопросу, но пока можно либо пользоваться StringBuilder или перед передачей параметра методу ProcessBatchData заменять utf-8 на UTF-8.
Function Clear-List([Microsoft.SharePoint.SPList]$list) {
$requestStream = New-Object System.IO.MemoryStream
$requestWriter = New-Object System.Xml.XmlTextWriter($requestStream, [System.Text.Encoding]::UTF8)
$requestWriter.WriteStartDocument()
$requestWriter.WriteStartElement("Batch")
$list.Items | ForEach-Object {
$requestWriter.WriteStartElement("Method")
$requestWriter.WriteStartElement("SetList")
$requestWriter.WriteAttributeString("Scope", "Request")
$requestWriter.WriteString($list.ID)
$requestWriter.WriteEndElement()
$requestWriter.WriteStartElement("SetVar")
$requestWriter.WriteAttributeString("Name", "ID")
$requestWriter.WriteString($_.ID)
$requestWriter.WriteEndElement()
if($list.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary) {
$requestWriter.WriteStartElement("SetVar")
$requestWriter.WriteAttributeString("Name", "owsfileref")
$requestWriter.WriteString($_.File.ServerRelativeUrl)
$requestWriter.WriteEndElement()
}
$requestWriter.WriteStartElement("SetVar")
$requestWriter.WriteAttributeString("Cmd", "Delete")
$requestWriter.WriteEndElement()
$requestWriter.WriteEndElement()
}
$requestWriter.WriteEndElement()
$requestWriter.WriteEndDocument()
$requestWriter.Flush()
$requestStream.Seek(0, [System.IO.SeekOrigin]::Begin)
$requestReader = New-Object System.IO.StreamReader($requestStream)
$requestText = $requestReader.ReadToEnd()
$requestStream.Close()
$requestText = $requestText.Replace("utf-8", "UTF-8")
$result = $list.ParentWeb.ProcessBatchData($requestText)
}