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 3

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 
    }
}

Я также вознагражу этот пост для вас, как только эта опция будет доступна... Надеюсь, что прошло достаточно времени, чтобы кто-то в сообществе знал, как решить эту проблему.