WebDav.NET libtary в SharePoint действие копировать / переместить в другое семейство сайтов приводит к 409
Я столкнулся с проблемой с WebDav на SharePoint. Я сделал хорошую библиотеку WebDav в .NET для поддержки копирования и перемещения файлов и папок структур, однако я не могу пройти мимо следующей проблемы.
Я использую .NET 4.0, подключаясь к SharePoint 2010.
При выполнении копирования в пределах одного семейства сайтов это работает нормально:
Так что копируй
http://my-sps-server/sc1/folder1/file1.txt
К
http://my-sps-server/sc1/folder2/file1.txt
Нет проблем, но
http://my-sps-server/sc1/folder1/file1.txt
К
http://my-sps-server/sc2/folder2/file1.txt
Выдает мне исключение и ответ статус говорит мне, что я получил 409 назад от сервера. Интересно, что перед копированием я удостоверяюсь, что папка "folder2" существует, если нет, она создается, и это работает без каких-либо проблем. Но детали ответа 409 говорят мне, что путь "folder2" не существует.
Я искал аутентификацию, я использую сетевые учетные данные по умолчанию, прекрасно работает для копирования в том же sitecollection и при создании папки. Также эмулировал http-запрос с fiddler, давая мне тот же ответ 409, так что, скорее всего, это не .NET-код.
Мне интересно, есть ли что-нибудь глючное в SharePoint 2010.Надеюсь, кто - нибудь сможет пролить свет или дать мне несколько советов здесь?
Закончили тем, что выполнили загрузку из источника и выгрузку в целевой объект (в память), код:
private byte[] DownloadFile(Uri uri)
{
var request = GetRequest(uri);
request.Method = "GET";
request.Headers.Add("Translate", "f");
var response = request.GetResponse();
using (var stream = response.GetResponseStream())
{
return ReadFileBytes(stream, (int)response.ContentLength);
}
}
private void UploadFile(Uri uri, byte[] bytes)
{
var request = GetRequest(uri);
request.Method = "PUT";
request.ContentLength = bytes.Length;
request.Headers.Add("Translate", "f");
using (var stream = request.GetRequestStream())
{
stream.Write(bytes, 0, bytes.Length);
stream.Close();
}
request.GetResponse();
}
/// <summary>
/// Reads data from a stream until the end is reached. The
/// data is returned as a byte array. An IOException is
/// thrown if any of the underlying IO calls fail.
/// </summary>
/// <param name="stream">The stream to read data from</param>
/// <param name="initialLength">The initial buffer length</param>
private static byte[] ReadFileBytes(Stream stream, int initialLength)
{
// If we've been passed an unhelpful initial length, just
// use 32K.
if (initialLength < 1)
{
initialLength = 32768;
}
byte[] buffer = new byte[initialLength];
int read = 0;
int chunk;
while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
{
read += chunk;
// If we've reached the end of our buffer, check to see if there's
// any more information
if (read == buffer.Length)
{
int nextByte = stream.ReadByte();
// End of stream? If so, we're done
if (nextByte == -1)
{
return buffer;
}
// Nope. Resize the buffer, put in the byte we've just
// read, and continue
byte[] newBuffer = new byte[buffer.Length * 2];
Array.Copy(buffer, newBuffer, buffer.Length);
newBuffer[read] = (byte)nextByte;
buffer = newBuffer;
read++;
}
}
// Buffer is now too big. Shrink it.
byte[] ret = new byte[read];
Array.Copy(buffer, ret, read);
return ret;
}
Обратите внимание, что загрузка и выгрузка будет стоить вам производительности, которая может быть заметна при работе с большими файлами.
Вы можете выполнить весь операция копирования выглядит следующим образом:
UploadFile (to, DownloadFile (from));
1 ответ:
В последнее время мы потратили немало времени на попытки решить эту проблему, но, к сожалению, ничего не добились. Есть несколько старых сообщений StackExchange на эту тему, и результат почти тот же - никто на самом деле не понимает, что вызывает этот конфликт, и никто, кажется, не решил его должным образом. То, что я могу сказать вам, что вы, кажется, еще не нашли, - это то, что этого часто не произойдет, если вы создадите новые библиотеки документов для перемещения файлов между ними и только с более старыми. Это указывает на то, что проблема вызвана каким-то видом коррупции.
То, что мы сделали и что может быть полезно для вас, - это отказаться и подойти к этому с помощью объектной модели SharePoint. Класс, который я написал для этого, находится ниже:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.SharePoint; using System.Diagnostics; // todo: Lists // DeleteListItem // WriteFileMetadata // AddListEntry // Throttling on copy methods namespace RE.SharePoint { /// <summary> /// Class to encapsulate methods that interact with SharePoint Lists and Libraries /// </summary> public class ListsAndItems { /// <summary> /// Move items from a list to another list in the same site /// </summary> /// <param name="siteURL">URL to the host site collection</param> /// <param name="sourceList">URL to the source list</param> /// <param name="destinationList">URL to the destination list</param> /// <param name="retainMeta">Option to retain meta data (created/modified dates) or create new ones</param> /// <returns>Boolean value, true for successful copy, false for a failed copy</returns> public bool MoveListItems(string siteURL, string sourceList, string destinationList, bool retainMeta) { OnSharePointOpeningSite(siteURL); using (var site = new SPSite(siteURL)) { OnSharePointOpenedSite(siteURL); using (var web = site.OpenWeb()) { OnSharePointGetRelativeURL(web.ServerRelativeUrl); try { // Get your source and destination libraries var source = web.GetList(web.ServerRelativeUrl + sourceList); var destination = web.GetList(web.ServerRelativeUrl + destinationList); OnSharePointSourceSet(source); OnSharePointDestinationSet(destination); // Get the collection of items to move, use source.GetItems(SPQuery) if you want a subset SPListItemCollection items = source.Items; // Get the root folder of the destination we'll use this to add the files SPFolder folder = web.GetFolder(destination.RootFolder.Url); OnSharePointProcessItem(items.Count, source.ToString(), destination.ToString()); var fileCount = 0; // Now to move the files and the metadata foreach (SPListItem item in items) { //Get the file associated with the item SPFile file = item.File; OnSharePointProcessFile(folder.Url + "/" + file.Name); // Create a new file in the destination library with the same properties SPFile newFile = folder.Files.Add(folder.Url + "/" + file.Name, file.OpenBinary(), file.Properties, true); if (retainMeta) { SPListItem newItem = newFile.Item; WriteFileMetaDataFiletoFile(item, newItem); } file.Delete(); SharePointRecycleBin.EmptyRecycleBinItem(site.ToString(), source.ToString(), file.Name); fileCount++; } OnSharePointProcessList(fileCount, source.ToString(), destination.ToString()); } catch (System.IO.FileNotFoundException fex) { OnError("Unable to set a location. Please check that paths for source and destination libraries are correct and relative to the site collection. \n\nSite URL: " + siteURL + " \nSource List: " + sourceList + " \nDestination List: " + destinationList + "\n", false, fex); return false; } catch (Exception ex) { OnError("General Exception: ", true, ex); return false; } return true; } } } /// <summary> /// Move items from one SharePoint list to another in another site /// </summary> /// <param name="sourceSiteURL">The URL to the source site collection</param> /// <param name="sourceList">The URL to the source list</param> /// <param name="destinationSiteURL">The URL to the destination site collection</param> /// <param name="destinationList">The URL to the destination list</param> /// <param name="retainMeta">Option to retain meta data (created/modified dates) or create new ones</param> /// <returns>Boolean value, true for successful copy, false for a failed copy</returns> public bool MoveListItemsSiteToSite(string sourceSiteURL, string sourceList, string destinationSiteURL, string destinationList, bool retainMeta) { OnSharePointOpeningSite(sourceSiteURL); using (SPSite sourceSite = new SPSite(sourceSiteURL)) { OnSharePointOpenedSite(sourceSiteURL); using (SPWeb sourceWeb = sourceSite.OpenWeb()) { OnSharePointGetRelativeURL(sourceWeb.ServerRelativeUrl); try { // Get your source library var source = sourceWeb.GetList(sourceWeb.ServerRelativeUrl + sourceList); OnSharePointSourceSet(source); // Get the collection of items to move, use source.GetItems(SPQuery) if you want a subset SPListItemCollection items = source.Items; int fileCount = 0; OnSharePointOpeningSite(destinationSiteURL); using (var destSite = new SPSite(destinationSiteURL)) { OnSharePointOpenedSite(destinationSiteURL); using (var destinationWeb = destSite.OpenWeb()) { OnSharePointGetRelativeURL(destinationWeb.ServerRelativeUrl); // get destination library SPList destination = destinationWeb.GetList(destinationWeb.ServerRelativeUrl + destinationList); OnSharePointDestinationSet(destination); // Get the root folder of the destination we'll use this to add the files SPFolder destinationFolder = destinationWeb.GetFolder(destination.RootFolder.Url); OnSharePointProcessItem(items.Count, source.ToString(), destination.ToString()); // Now to move the files and the metadata foreach (SPListItem item in items) { //Get the file associated with the item SPFile file = item.File; // Add event handler OnSharePointProcessFile(destinationFolder.Url + "/" + file.Name); // Create a new file in the destination library with the same properties SPFile newFile = destinationFolder.Files.Add(destinationFolder.Url + "/" + file.Name, file.OpenBinary(), file.Properties, true); if (retainMeta) { SPListItem newItem = newFile.Item; WriteFileMetaDataFiletoFile(item, newItem); } file.Delete(); SharePointRecycleBin.EmptyRecycleBinItem(sourceSite.ToString(), source.ToString(), file.Name); fileCount++; } OnSharePointProcessList(fileCount, source.ToString(), destination.ToString()); } } } catch (System.IO.FileNotFoundException fex) { OnError("Unable to set a location. Please check that paths for source and destination libraries are correct and relative to the site collection. \n\nSource Site: " + sourceSiteURL + " \nSource List: " + sourceList + " \nDestination Site: " + destinationSiteURL + " \nDestination List: " + destinationList + "\n", false, fex); return false; } catch (Exception ex) { OnError("General Exception: ", true, ex); return false; } return true; } } } /// <summary> /// overwrites a list items meta data with meta data from another file /// </summary> /// <param name="sourceItem">The source item to take meta data from</param> /// <param name="destinationItem">The destination item to set meta data from the source item to</param> public static void WriteFileMetaDataFiletoFile(SPListItem sourceItem, SPListItem destinationItem) { destinationItem["Editor"] = sourceItem["Editor"]; destinationItem["Modified"] = sourceItem["Modified"]; destinationItem["Modified By"] = sourceItem["Modified By"]; destinationItem["Author"] = sourceItem["Author"]; destinationItem["Created"] = sourceItem["Created"]; destinationItem["Created By"] = sourceItem["Created By"]; destinationItem.UpdateOverwriteVersion(); } #region Events internal void OnSharePointProcessFile(string itemPath) { if (_sharePointProcessedFile == null) return; var e = new SharePointProcessFileEventArgs(itemPath); _sharePointProcessedFile(this, e); } internal void OnSharePointProcessItem(int itemCount, string source, string destination) { if (_sharePointProcessItem == null) return; var e = new SharePointProcessItemEventArgs(itemCount, source, destination); _sharePointProcessItem(this, e); } internal void OnSharePointProcessList(int itemCount, string source, string destination) { if (_sharePointProcessList == null) return; var e = new SharePointProcessListEventArgs(itemCount, source, destination); _sharePointProcessList(this, e); } internal void OnSharePointOpeningSite(string siteName) { if (_sharePointOpeningSite == null) return; var e = new SharePointOpeningSiteEventArgs(siteName); _sharePointOpeningSite(this, e); } internal void OnSharePointOpenedSite(string siteName) { if (_sharePointOpenedSite == null) return; var e = new SharePointOpenedSiteEventArgs(siteName); _sharePointOpenedSite(this, e); } internal void OnSharePointGetRelativeURL(string siteCollection) { if (_sharePointRelativeURL == null) return; var e = new SharePointWebRelativeURLEventArgs(siteCollection); _sharePointRelativeURL(this, e); } internal void OnSharePointDestinationSet(SPList destination) { if (_sharepointDestination == null) return; var e = new SharePointDestinationSetEventArgs(destination); _sharepointDestination(this, e); } internal void OnSharePointSourceSet(SPList source) { if (_sharepointSource == null) return; var e = new SharePointSourceSetEventArgs(source); _sharepointSource(this, e); } internal void OnError(string message, bool showException, Exception exception) { if (_sharePointOnError == null) return; var e = new SharePointOnErrorEventsArgs(message, showException, exception); _sharePointOnError(this, e); } private EventHandler<SharePointProcessFileEventArgs> _sharePointProcessedFile; private EventHandler<SharePointProcessListEventArgs> _sharePointProcessList; private EventHandler<SharePointOpeningSiteEventArgs> _sharePointOpeningSite; private EventHandler<SharePointOpenedSiteEventArgs> _sharePointOpenedSite; private EventHandler<SharePointWebRelativeURLEventArgs> _sharePointRelativeURL; private EventHandler<SharePointDestinationSetEventArgs> _sharepointDestination; private EventHandler<SharePointSourceSetEventArgs> _sharepointSource; private EventHandler<SharePointProcessItemEventArgs> _sharePointProcessItem; private EventHandler<SharePointOnErrorEventsArgs> _sharePointOnError; /// <summary> /// Event for handling exceptions /// </summary> public event EventHandler<SharePointOnErrorEventsArgs> SharePointOnError { add { _sharePointOnError += value; } remove { _sharePointOnError += value; } } /// <summary> /// Event for when a file is being processed /// </summary> public event EventHandler<SharePointProcessFileEventArgs> SharePointProcessFile { add { _sharePointProcessedFile += value; } remove { _sharePointProcessedFile += value; } } /// <summary> /// Event for when a site is attempting to open /// </summary> public event EventHandler<SharePointOpeningSiteEventArgs> SharePointOpeningSite { add { _sharePointOpeningSite += value; } remove { _sharePointOpeningSite -= value; } } /// <summary> /// Event for when a site has been successfully opened /// </summary> public event EventHandler<SharePointOpenedSiteEventArgs> SharePointOpenedSite { add { _sharePointOpenedSite += value; } remove { _sharePointOpenedSite -= value; } } /// <summary> /// Event for when source/destination and filecount are established and a copy is about to initiate /// </summary> public event EventHandler<SharePointProcessItemEventArgs> SharePointProcessItem { add { _sharePointProcessItem += value; } remove { _sharePointProcessItem -= value; } } /// <summary> /// Event for when a list has started processing /// </summary> public event EventHandler<SharePointProcessListEventArgs> SharePointProcessList { add { _sharePointProcessList += value; } remove { _sharePointProcessList -= value; } } /// <summary> /// Event for when a web relative URL has been retreived from the site collection name /// </summary> public event EventHandler<SharePointWebRelativeURLEventArgs> SharePointWebRelativeURL { add { _sharePointRelativeURL += value; } remove { _sharePointRelativeURL -= value; } } /// <summary> /// Event for when a destination location has been assigned /// </summary> public event EventHandler<SharePointDestinationSetEventArgs> SharePointDestinationSet { add { _sharepointDestination += value; } remove { _sharepointDestination -= value; } } /// <summary> /// Event for when a source location has been assigned /// </summary> public event EventHandler<SharePointSourceSetEventArgs> SharePointSourceSet { add { _sharepointSource += value; } remove { _sharepointSource -= value; } } #endregion } }
Я также вознагражу этот пост для вас, как только эта опция будет доступна... Надеюсь, что прошло достаточно времени, чтобы кто-то в сообществе знал, как решить эту проблему.