SharePoint上的WebDav .NET库将操作复制/移动到不同的网站集,结果为409

时间:2012-09-04 07:52:18

标签: .net sharepoint webdav

我在SharePoint上面临WebDav的问题。我在.NET中创建了一个很好的WebDav库来支持复制和移动文件和文件夹结构,但是我无法解决以下问题。

我正在使用.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中复制以及创建文件夹时正常工作。还使用fiddler模​​拟http请求,给出了相同的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 个答案:

答案 0 :(得分:0)

我们最近花了相当多的时间来尝试解决这个问题,但遗憾的是没有得到任何结果。关于这个主题有很多旧的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 
    }
}

一旦该选项可用,我也会为你提供这个帖子...希望现在已经过了足够的时间,以便社区中的某些人知道如何解决这个问题。