1

Elmah has recently reported this bug;

Microsoft.SharePoint.Client.ServerException: The request message is too big. The server does not allow messages larger than 5242880 bytes.

The code where it fell over was;

public SharepointFileInfo Save(byte[] file, string fileName)
{
    using (var context = new ClientContext(this.SharepointServer))
    {
        context.Credentials = new NetworkCredential(this.UserName, this.Password, this.Domain);

        var list = context.Web.Lists.GetByTitle(this.DocumentLibrary);
        var fileCreationInformation = new FileCreationInformation
                                          {
                                              Content = file,
                                              Overwrite = true,
                                              Url = fileName
                                          };
        var uploadFile = list.RootFolder.Files.Add(fileCreationInformation);
        var listItem = uploadFile.ListItemAllFields;
        listItem.Update();

        context.ExecuteQuery();

        if (this.Metadata.Count > 0)
        {
            this.SaveMetadata(uploadFile, context);
        }

        return GetSharepointFileInfo(context, list, uploadFile);
    }
}

I am using Sharepoint 2013. How do I fix this?

arame3333
  • 9,887
  • 26
  • 122
  • 205
  • 1
    Have a look at [this](http://stackoverflow.com/questions/18861407/sharepoint-error-the-server-does-not-allow-messages-larger-than-2097152-bytes?rq=1). – diiN__________ Mar 15 '16 at 08:15

2 Answers2

2

It's a normal problme. You use the classic API (new FileCreationInformation [...] context.ExecuteQuery()) which sent a HTTP requet to the server. You file is up to 5 Mb. So, IIS receive a huge request, and reject it. To Upload a file to SharePoint you need to use :

File.SaveBinaryDirect (with this you don't need to change settings ;) )

using (FileStream fs = new FileStream(filePath, FileMode.Open))
{
  Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, string.Format("/{0}/{1}", libraryName, System.IO.Path.GetFileName(filePath)), fs, true);
}

Check this links to see how to upload a file to SharePoint using CSOM : Upload large files sample app for SharePoint

good luck

Nico
  • 448
  • 4
  • 9
  • With my current code I can take a File object (uploadFile) and set it's metadata. I can't see how you do that with your solution so I am having difficulty implementing it. – arame3333 Mar 15 '16 at 15:33
1

There is several approche to do that (upload file with metaData). I propose 2 methods to you (one simple, second more complex)

  1. In 2 Times (simple)

    • Upload the the file with the File.SaveBinaryDirect
    • Get the SPFile with CSOM by the file URL with SP.Web.getFileByServerRelativeUrl and File.listItemAllFields methodes. Here an exemple : get listitem by file URL
  2. With FileCreationInformation but more complex. You need to use : File.StartUpload, File.ContinueUpload and File.FinishUpload The code is from Microsoft the last part of the tuto, not mine

    public Microsoft.SharePoint.Client.File UploadFileSlicePerSlice(ClientContext ctx, string libraryName, string fileName,int fileChunkSizeInMB = 3){
    // Each sliced upload requires a unique ID.
    Guid uploadId = Guid.NewGuid();
    
    // Get the name of the file.
    string uniqueFileName = Path.GetFileName(fileName);
    
    // Ensure that target library exists, and create it if it is missing.
    if (!LibraryExists(ctx, ctx.Web, libraryName))
    {
        CreateLibrary(ctx, ctx.Web, libraryName);
    }
    // Get the folder to upload into. 
    List docs = ctx.Web.Lists.GetByTitle(libraryName);
    ctx.Load(docs, l => l.RootFolder);
    // Get the information about the folder that will hold the file.
    ctx.Load(docs.RootFolder, f => f.ServerRelativeUrl);
    ctx.ExecuteQuery();
    
    // File object.
    Microsoft.SharePoint.Client.File uploadFile;
    
    // Calculate block size in bytes.
    int blockSize = fileChunkSizeInMB * 1024 * 1024;
    
    // Get the information about the folder that will hold the file.
    ctx.Load(docs.RootFolder, f => f.ServerRelativeUrl);
    ctx.ExecuteQuery();
    
    
    // Get the size of the file.
    long fileSize = new FileInfo(fileName).Length;
    
    if (fileSize <= blockSize)
    {
        // Use regular approach.
        using (FileStream fs = new FileStream(fileName, FileMode.Open))
        {
            FileCreationInformation fileInfo = new FileCreationInformation();
            fileInfo.ContentStream = fs;
            fileInfo.Url = uniqueFileName;
            fileInfo.Overwrite = true;
            uploadFile = docs.RootFolder.Files.Add(fileInfo);
            ctx.Load(uploadFile);
            ctx.ExecuteQuery();
            // Return the file object for the uploaded file.
            return uploadFile;
        }
    }
    else
    {
        // Use large file upload approach.
        ClientResult<long> bytesUploaded = null;
    
        FileStream fs = null;
        try
        {
            fs = System.IO.File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            using (BinaryReader br = new BinaryReader(fs))
            {
                byte[] buffer = new byte[blockSize];
                Byte[] lastBuffer = null;
                long fileoffset = 0;
                long totalBytesRead = 0;
                int bytesRead;
                bool first = true;
                bool last = false;
    
                // Read data from file system in blocks. 
                while ((bytesRead = br.Read(buffer, 0, buffer.Length)) > 0)
                {
                    totalBytesRead = totalBytesRead + bytesRead;
    
                    // You've reached the end of the file.
                    if (totalBytesRead == fileSize)
                    {
                        last = true;
                        // Copy to a new buffer that has the correct size.
                        lastBuffer = new byte[bytesRead];
                        Array.Copy(buffer, 0, lastBuffer, 0, bytesRead);
                    }
    
                    if (first)
                    {
                        using (MemoryStream contentStream = new MemoryStream())
                        {
                            // Add an empty file.
                            FileCreationInformation fileInfo = new FileCreationInformation();
                            fileInfo.ContentStream = contentStream;
                            fileInfo.Url = uniqueFileName;
                            fileInfo.Overwrite = true;
                            uploadFile = docs.RootFolder.Files.Add(fileInfo);
    
                            // Start upload by uploading the first slice. 
                            using (MemoryStream s = new MemoryStream(buffer))
                            {
                                // Call the start upload method on the first slice.
                                bytesUploaded = uploadFile.StartUpload(uploadId, s);
                                ctx.ExecuteQuery();
                                // fileoffset is the pointer where the next slice will be added.
                                fileoffset = bytesUploaded.Value;
                            }
    
                            // You can only start the upload once.
                            first = false;
                        }
                    }
                    else
                    {
                        // Get a reference to your file.
                        uploadFile = ctx.Web.GetFileByServerRelativeUrl(docs.RootFolder.ServerRelativeUrl + System.IO.Path.AltDirectorySeparatorChar + uniqueFileName);
    
                        if (last)
                        {
                            // Is this the last slice of data?
                            using (MemoryStream s = new MemoryStream(lastBuffer))
                            {
                                // End sliced upload by calling FinishUpload.
                                uploadFile = uploadFile.FinishUpload(uploadId, fileoffset, s);
                                ctx.ExecuteQuery();
    
                                // Return the file object for the uploaded file.
                                return uploadFile;
                            }
                        }
                        else
                        {
                            using (MemoryStream s = new MemoryStream(buffer))
                            {
                                // Continue sliced upload.
                                bytesUploaded = uploadFile.ContinueUpload(uploadId, fileoffset, s);
                                ctx.ExecuteQuery();
                                // Update fileoffset for the next slice.
                                fileoffset = bytesUploaded.Value;
                            }
                        }
                    }
    
                } // while ((bytesRead = br.Read(buffer, 0, buffer.Length)) > 0)
            }
        }
        finally
        {
            if (fs != null)
            {
                fs.Dispose();
            }
        }
    }
    return null;}
    

hope this help you

Community
  • 1
  • 1
Nico
  • 448
  • 4
  • 9
  • Where I am stuck is that I want to convert a HttpPostedFileBase to a filestream – arame3333 Mar 16 '16 at 16:02
  • you can save the file in a tempory folder, and after use the normal methode with the file Path. Or you can use the Stream of the HttpPostedFileBase, check this link: [Read File from HttpPostedFileBase without save](http://stackoverflow.com/questions/16030034/asp-net-mvc-read-file-from-httppostedfilebase-without-save) – Nico Mar 16 '16 at 16:23
  • To answer my own question, I can use the HttpPostedFileBase property InputStream directly. So this now works with small files. – arame3333 Mar 17 '16 at 12:02
  • Because of the authentication issues I am having to use the second method. I have a very odd exception: "Microsoft.SharePoint.Client.ServerException: Method "StartUpload" does not exist." I look in the documentation and this method does exist, how can this happen? – arame3333 Mar 17 '16 at 12:04
  • Wow... strange ! What is the version of you SharePoint ? 2010/2013/SharePoint Online (Office365) ? – Nico Mar 17 '16 at 17:02
  • I just found that : [File.StartUpload](https://msdn.microsoft.com/library/office/microsoft.sharepoint.client.file.startupload.aspx). At the bottom of page : **This method is currently available only on Office 365.** – Nico Mar 17 '16 at 17:07
  • Ah yes. That means I can't use this method. Look at the other documentation in https://msdn.microsoft.com/en-us/library/office/dn904536.aspx I shouldn't need to. In the code the simple solution should work on Sharepoint 2013 and the if check on the file size is not needed. Interesting to note that the exception refers to 5MB and not 2MB. Is this a setting on Sharepoint that needs to change? – arame3333 Mar 18 '16 at 08:58
  • In SharePoint the limit is defined in Central Admin (Settings of WebApplication) by default the max size is 50MB. The limit of 5Mb is an IIS limit (IIS have a limit of request lenght that why you should use **File.SaveBinaryDirect** which don't use request). You can change this default IIS limit in web.config – Nico Mar 18 '16 at 09:18
  • I found this reference: https://blogs.technet.microsoft.com/praveenh/2012/11/15/issues-uploading-large-files-to-sharepoint/ from which I changed 2 web.config files (in directories C:\inetpub\wwwroot\wss\VirtualDirectories\23292 and C:\inetpub\wwwroot\wss\VirtualDirectories\80) but it made no difference. – arame3333 Mar 18 '16 at 15:29
  • You need to change on every farm server : Font end , application, ...There is also web.config in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\CONFIG. You need to do : iisreset to enable this change. – Nico Mar 18 '16 at 16:12