1

I am trying to upload file to sharepoint server 2013 from code with HttpClient or some other way. (I don't want to use the "Microsoft.SharePoint.Client" dll) because there are some issues with this dll with large files.

my HttpClient code looks like:

public async Task UploadAsync(string filePath)
{
    string sharePointUrl = "http://codey-sharepoint/sites/codysite";
    string folderUrl = "/Documents";
    string fileNameNotFullPAth = System.IO.Path.GetFileName(filePath);
    var offset = 0L;
    var endpointUrl = string.Format("{0}/_api/web/getfolderbyserverrelativeurl(\'{1}\')/Files/add(url=\'{2}\',overwrite=true)", sharePointUrl, folderUrl, fileNameNotFullPAth);

      using (var handler = new HttpClientHandler { Credentials = new NetworkCredential("codey", "codey123") })
      using (var client = new HttpClient(handler))
      using (var contect=new MultipartFormDataContent("boundry ---"))
      {
         contect.Add(new StreamContent(new MemoryStream(System.IO.File.ReadAllBytes(filePath))), "file", "tst.txt");
         using (var msg = await client.PostAsync(endpointUrl,contect))
         {
             Console.WriteLine(msg.StatusCode);
             Console.WriteLine(msg.IsSuccessStatusCode);
             var input = await msg.Content.ReadAsStringAsync();
             try
             {
               XDocument doc = XDocument.Parse(input);
               Console.WriteLine(doc.ToString());
             }catch { Console.WriteLine("XML Parse error"); }
         }                
      }
}

My output:

Unaouthorized

False

XML Parse error

For now I only want to upload simple and small file without using external DLL

Codey
  • 487
  • 1
  • 8
  • 27

1 Answers1

1

maybe some additional headers in the HttpClient object are required. Try maybe adding this:


    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.DefaultRequestHeaders.Add("Accept", "application/json;odata=nometadata");
    client.DefaultRequestHeaders.Add("binaryStringRequestBody", "true");
    client.DefaultRequestHeaders.Add("X-RequestDigest", tFormDigest.Result.FormDigestValue);
    client.MaxResponseContentBufferSize = 2147483647;

Also instead of using MultipartFormDataContent You could try just sending ByteArray with a PostAsync

Something more or less like this for Your case

    var endpointUrl = string.Format("{0}/_api/web/getfolderbyserverrelativeurl(\'{1}\')/Files/add(url=\'{2}\',overwrite=true)", sharePointUrl, folderUrl, fileNameNotFullPAth);

    using (var handler = new HttpClientHandler { Credentials = new NetworkCredential("codey", "codey123") })
    using (var client = new HttpClient(handler))
    {
        ByteArrayContent content = new ByteArrayContent(new MemoryStream(System.IO.File.ReadAllBytes(filePath)).ToArray());    

        HttpResponseMessage response = await client.PostAsync(endpointUrl, content).ConfigureAwait(false);

    }     

Also... did You consider using CSOM? maybe it would be a better approach since You are already using C#.

for on-prem (2013.. but there is for all versions also) You have

https://www.nuget.org/packages/Microsoft.SharePoint2013.CSOM/

and for online

https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM

UPDATE

I added this nuget to some simple c# console app (so the same as from the link) enter image description here

and the preferred code used for small files under 2MB is



    class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Console.WriteLine("start");
                    byte[] b = System.IO.File.ReadAllBytes(@"[PATH TO FILE LIKE C:\test.png]");
                    using (ClientContext context = new ClientContext("[SITECOLLECTION URL]"))
                    {
                        List list = context.Web.Lists.GetByTitle("[LIB NAME LIKE 'DOCUMENTS']");
                        FileCreationInformation fileInfo = new FileCreationInformation();
                        fileInfo.Content = b;
                        fileInfo.Overwrite = true;

                        fileInfo.Url = "[SITECOLLECTION URL]" + "/[LIB NAME FROM URL LIKE 'DOCUMENTS']/" + "[FILE NAME LIKE 'test.png']";
                        Microsoft.SharePoint.Client.File uploadFile = list.RootFolder.Files.Add(fileInfo);

                        uploadFile.ListItemAllFields.Update();
                        context.ExecuteQuery();
                    }
                    Console.WriteLine("end");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("error -> " +  ex.Message);
                }
                finally
                {
                    Console.ReadLine();
                }
            }
        }

the code for larger files under 2GB (for SP2013) is (I tested for a file that had around 100MB)



    class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Console.WriteLine("start");
                    using (ClientContext context = new ClientContext("[SITECOLLECTION URL]"))
                    {
                        using (FileStream fs = new FileStream(@"[PATH TO FILE LIKE C:\test.png]", FileMode.Open))
                        {
                            Microsoft.SharePoint.Client.File.SaveBinaryDirect(context, "/[LIB NAME FROM URL LIKE 'DOCUMENTS']/" + "[FILE NAME LIKE 'test.png']", fs, true);
                        }
                    }
                    Console.WriteLine("end");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("error -> " +  ex.Message);
                }
                finally
                {
                    Console.ReadLine();
                }
            }
        }

please be aware that I tested it just now and all works BUT on SP2016 (but the nuget was for SP2013 and worked all fine), I don't have access to any SP2013 at the moment to check.

Please be aware that If You have versioning activated on this lib the files will be checked out after upload and You will need to check in with another context.ExecuteQuery().

Please be aware that if You want to run this code as a different user (now it will be the same account as current login) You need to define the networkCredentials giving login, password and domain.

UPDATE

please see the result of this method on SP2016 uploading 470MB file (3 min) enter image description here

BUT I tried the same on SP2013 and the result was not satisfactory... it takes a lot of time and I waited very long (over 2 hours) to upload 0.5GB file, and the upload still didn't finish at the end.

Please be aware in order to extend the upload You have to change:

  1. upload file size in CA
  2. add context.RequestTimeout = -1; to CSOM code
  3. set bigger timeout session time on IIS

please refer to link and link (not all of course is needed for CSOM upload)

Adam
  • 810
  • 7
  • 10
  • Great link for 2013, do you know where I can find the docs? for 2013, I'm trying to upload large files ~2GB... – Codey Jul 07 '19 at 11:26
  • unfortunately in SP2013 the 2GB is a software boundary. By default it is 250 MB like in SP2010 but since it is a threshold limit You can change it BUT the limit cannot be greater then 2GB which is a boundary (cannot be changed). Please refer to: https://learn.microsoft.com/pl-pl/SharePoint/install/software-boundaries-and-limits and here is how to change: https://blogs.technet.microsoft.com/sammykailini/2013/11/06/how-to-increase-the-maximum-upload-size-in-sharepoint-2013/ If I remember well for SP2016 the limit is 10GB and for SP2019 is 15GB. May You consider SP version upgrade? – Adam Jul 07 '19 at 11:29
  • Do you know how can I upload 1 GB from code using [this](https://www.nuget.org/packages/Microsoft.SharePoint2013.CSOM/) dll? I **succeded to upload 1GB manually** but not via code, I tried [UploadFileSlicePerSlice](https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/upload-large-files-sample-app-for-sharepoint), but there is no such method "StartUpload" in the dll – Codey Jul 07 '19 at 11:42