none
upload files to sharepoint using chunks method

    Question

  • Hi,

    I am trying to upload files in every iteration within a script task of ssis and there is an error at the line ctx.executeQuery() within if (fileSize <= blockSize) block that says "URL is not web relative".I am not sure how to fix it and what is wrong.I attach the below code and it is available in the Microsoft site.


      public Microsoft.SharePoint.Client.File UploadFileSlicePerSlice(ClientContext ctx, string libraryName, string fileName, int fileChunkSizeInMB)
            {
                // Each sliced upload requires a unique ID.
                Guid uploadId = Guid.NewGuid();

                // Get the name of the file.
                string uniqueFileName = fileName;


                // 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 + 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;
            }

    Wednesday, May 22, 2019 3:55 PM

All replies

  • Hi

    According to the error message, try to modify below line.

    fileInfo.Url = uniqueFileName;

    Build a relative URL for the file's Url property.


    Justin Liu Office Apps & Services MVP, MCSE
    Senior Software Engineer
    Please Vote and Mark as Answer if it helps you.

    Thursday, May 23, 2019 1:07 AM
  • Hi,

    I did test for root site/child site, the code works fine.

    May I know your test parameter?

     private static bool LibraryExists(ClientContext ctx, Web web, string libraryName)
            {
                ListCollection lists = web.Lists;
                IEnumerable<List> results = ctx.LoadQuery<List>(lists.Where(list => list.Title == libraryName));
                ctx.ExecuteQuery();
                List existingList = results.FirstOrDefault();
    
                if (existingList != null)
                {
                    return true;
                }
    
                return false;
            }
    
    
            private static void CreateLibrary(ClientContext ctx, Web web, string libraryName)
            {
                // Create library to the web
                ListCreationInformation creationInfo = new ListCreationInformation();
                creationInfo.Title = libraryName;
                creationInfo.TemplateType = (int)ListTemplateType.DocumentLibrary;
                List list = web.Lists.Add(creationInfo);
                ctx.ExecuteQuery();
            }
            public static 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;
            }
            static void Main(string[] args)
            {
    
                ClientContext context = new ClientContext(@"http://sp13/subsite2");
    
                UploadFileSlicePerSlice(context, "mydoc", @"C:\testdoc.docx");
                Console.ReadKey();
            }

    Best Regards,

    Lee


    Please remember to mark the replies as answers if they helped. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    SharePoint Server 2019 has been released, you can click here to download it.
    Click here to learn new features. Visit the dedicated forum to share, explore and talk to experts about SharePoint Server 2019.

    Thursday, May 23, 2019 1:56 AM
  • Lee,

    Thanks for the help.I dont know if the error talks about sharepoint site/library URL or file URL.It more seeme like the problem with the local file path.If so,then i dont know how to convert the file to relative.I tried along the following lines,but get the same exception-

    Uri uri1 = new Uri(@"C:\" + file);

                Uri uri2 = new Uri(fileName);

                Uri relativeUri = uri2.MakeRelativeUri(uri1); 

    Below is how i am reading values as parameters into script:

      public void Main()
            {
                var site = (string)Dts.Variables["$Package::Site"].Value;
                var library = (string)Dts.Variables["$Package::Library"].Value;

    }

    Test values look like this:

    • site- https://abc.sharepoint.com/sites/dev
    • library- Inventory Reports



    Thursday, May 23, 2019 5:49 PM
  • Lee,

    Actually fixed it.Had to just use the filename instead of the path ,so replaced fileinfo.URL=file and it uploaded the file

    Thursday, May 23, 2019 8:30 PM
  • Hi,

    Thanks for your feedback, you could mark the solution as answer so it would help other community members find the helpful information quickly.

    Best Regards,

    Lee


    Please remember to mark the replies as answers if they helped. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    SharePoint Server 2019 has been released, you can click here to download it.
    Click here to learn new features. Visit the dedicated forum to share, explore and talk to experts about SharePoint Server 2019.

    Friday, May 24, 2019 12:56 AM