Question

I have decided to use the SaveBinaryDirect Method to upload documents to the sharepoint site due to not having the request/file size limitations that the client object model has.

The application does two things, Adds a folder(using the Client object model) and then uploads a selected file into the folder it has just created (using Save Binary Direct).

This works fine on my setup here. but at our clients site the folder is created fine but the file upload part returns "Unauthorized 401" error.

            SP.ClientContext ctx = new SP.ClientContext(siteurl);
            SP.Web currentWeb = ctx.Web;
            //Pass user details from config (That has owner permissions)
            ctx.Credentials = new NetworkCredential(username, password, domain);   
            //create folder method (checks if the folder exists and creates using Client Object Model)
            CreateFolder(ctx,libraryUrl,folderName)

            //Save Binary Direct Method
            string fileUrl = "/"+ libraryname + "/" + folderName + "/" + fileName;
            using (data)
            {
                //upload by passing the context, file url, file data stream, 
                //set overwrite to true
                SP.File.SaveBinaryDirect(ctx, fileUrl,data, true);
            }

This makes me think one of two things

  1. There is a setting that needs to be changed on the share point or web server in regards to the authorization/authentication.
  2. The way that i am applying the network credentials is incorrect. as it only does it for the client object model but not the save binary direct.

I'm aware that we are able to use the client object model, and we may need to do another release if its not a config/setup issue.

Anyone with more experience with this have some ideas on why its doing this?

Was it helpful?

Solution

If you are using SharePoint 2013 you cannot use SaveBinaryDirect, it does not work with claims authentication. The call made by SaveBinaryDirect does not include the required authorization cookies. Details are discussed in the comments to this blog post: How to do active authentication to Office 365 and SharePoint Online

Update (July 2, 2016):

I took another look at this after seeing the comment by James Love. I'm not sure what changed but my test indicates that SaveBinaryDirect is now working with SharePoint 2013 and SharePoint Online.

Here's the code I used:

// var context = new ClientContext("http://intranet.wingtip.com/sites/demo/");
// context.Credentials = System.Net.CredentialCache.DefaultCredentials;

var context = new ClientContext("https://robwindsor2.sharepoint.com/sites/demo/");
context.Credentials = new SharePointOnlineCredentials(loginName, securePassword);

var web = context.Web;
var lib = web.Lists.GetByTitle("Documents");

context.Load(lib);
context.Load(lib.RootFolder);
context.ExecuteQuery();

var fileName = "Test.docx";
var filePath = @"C:\Users\robwindsor\Desktop\" + fileName;
using (var fs = new FileStream(filePath, FileMode.Open))
{
    Microsoft.SharePoint.Client.File.SaveBinaryDirect(context, lib.RootFolder.ServerRelativeUrl + "/" + fileName, fs, true);
}

var query = new CamlQuery();
query.ViewXml = "<View></View>";
var files = lib.GetItems(query);

context.Load(files, c => c.Include(f => f.File));
context.ExecuteQuery();

foreach(ListItem item in files)
{
    Console.WriteLine(item.File.Name);
}

Console.WriteLine("Done");        

OTHER TIPS

Try this:

FileCreationInformation fci = new FileCreationInformation();

fci.Content = newFile.Bytes;

fci.Url = sourceFile.Url;

fci.Overwrite = true;

Microsoft.SharePoint.Client.File replacedFile = list.RootFolder.Files.Add(fci);

context.Load(replacedFile);

context.ExecuteQuery();

I am able to upload file from file system to SharePoint 2010 using Client Object Model.

If you are getting unauthorized 401 then make sure you are providing the right credentials and correct relative URL of target SharePoint document library folder.

ClientContext ctx = new ClientContext(Siteurl);
ctx.Credentials = new System.Net.NetworkCredential("username", "password", "domain");
var sourceFilePath = @"C:\test\test.xlsx";
var targetUrl = "/Shared%20Documents";
var targetFileUrl = String.Format("{0}/{1}", targetUrl, Path.GetFileName(sourceFilePath));
var fs = new FileStream(sourceFilePath, FileMode.Open);
Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, targetFileUrl, fs, true);
var uploadedFile = ctx.Web.GetFileByServerRelativeUrl(targetFileUrl);
var listItem = uploadedFile.ListItemAllFields;
listItem.Update();
ctx.ExecuteQuery();

I think you must add this:

ctx.RequestTimeout = 3600000;

I encountered the same problem, and found a workaround although I don't know if it is legitimate.

 System.Net.WebClient webClient = new System.Net.WebClient();

 System.Uri uri = new Uri(url); //Create a uri object with the file name but without extension

 webClient.Credentials = new NetworkCredential(username,password,domain);        //Network credentials to connect with the sharepoint server

 webClient.UploadFile(uri, "PUT", pFilePath);     //Upload File will push the file to the server

TLDR: you need to use the server relative URL, even though the context includes the site information.

I had this same issue, and resolved it by using Fiddler. When I used the client Object Model, I created the context with the site path, i.e. "https://server/sites/siteName", then

var docs = web.Lists.GetByTitle(documentLibraryName);
SP.File uploadFile = docs.RootFolder.Files.Add(newFile);
context.Load(uploadFile);
context.ExecuteQuery();

This resulted in a POST to https://<server>/sites/<siteName>/_vti_bin/client.svc/ProcessQuery the path and filename (and content) were embedded in the XML by the CSOM.

Now, the SP.File.SaveBinaryDirect signature is SaveBinaryDirect(ClientContext context, string serverRelativeUrl, Stream stream, bool overwriteIfExists) -- but the request SaveBinaryDirect(context, "/<library>/<folder>/filename", stream, true) failed with a 401 error. Look in Fiddler, and here is the request made:

PUT https://<server>/<library>/<filename>

Even though the context includes the site, you have to give it the whole path from the server root. The successful call was

SaveBinaryDirect(context, "/sites/<sitename>/<library>/<folder>/filename", stream, true)

and that results in a PUT to the correct location. The parameter is called serverRelativeUrl after all.

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top