Download File from SharePoint Online using WebClient - c#

I am using .net 4.8 WebClient and the Microsoft.SharePointOnline.CSOM package, trying to download files from SharePoint online.
const string username = "myusername#domain.com";
const string password = "mypassword";
const string url = "https://tenant.sharepoint.com/:b:/r/filepath.pdf";
var securedPassword = new SecureString();
foreach (var c in password.ToCharArray())
{
securedPassword.AppendChar(c);
}
var credentials = new SharePointOnlineCredentials(username, securedPassword);
using (var client = new WebClient())
{
client.Credentials = credentials;
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
client.DownloadFile(url, "C:\\temp\\test.pdf"); //this file path definitely exists
}
The error I get is a 401 unauthorized.
I logged out and logged into the SharePoint environment using the same credentials, to ensure that they are correct.
I've tried adding a couple different user agents in the header to see if that helps.
client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
//or
client.Headers.Add("User-Agent: Other");
But it didn't make any difference.
This is similar to Download File From SharePoint 365 which is using what looks like the same code as I am, but Download Document from SharePoint Online using c# webclient stopped working suggests that something has changed and this form of authentication no longer works for connecting to SharePoint online. However I have been unable to find any recent documentation on what we're supposed to use now.

You could refer to the code provided by official document.
https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/working-with-folders-and-files-with-rest
As I test,it works well.
public static void DownloadFileViaRestAPI(string webUrl, ICredentials credentials, string documentLibName, string fileName, string path)
{
webUrl = webUrl.EndsWith("/") ? webUrl.Substring(0, webUrl.Length - 1) : webUrl;
string webRelativeUrl = null;
if (webUrl.Split('/').Length > 3)
{
webRelativeUrl = "/" + webUrl.Split(new char[] { '/' }, 4)[3];
}
else
{
webRelativeUrl = "";
}
using (WebClient client = new WebClient())
{
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
client.Credentials = credentials;
Uri endpointUri = new Uri(webUrl + "/_api/web/GetFileByServerRelativeUrl('" + webRelativeUrl + "/" + documentLibName + "/" + fileName + "')/$value");
byte[] data = client.DownloadData(endpointUri);
FileStream outputStream = new FileStream(path + fileName, FileMode.OpenOrCreate | FileMode.Append, FileAccess.Write, FileShare.None);
outputStream.Write(data, 0, data.Length);
outputStream.Flush(true);
outputStream.Close();
}
}
static void Main(string[] args)
{
string siteURL = "https://contoso.sharepoint.com/sites/dev";
//set credential of SharePoint online
SecureString secureString = new SecureString();
foreach (char c in "password".ToCharArray())
{
secureString.AppendChar(c);
}
ICredentials credentials = new Microsoft.SharePoint.Client.SharePointOnlineCredentials("amos#contoso.onmicrosoft.com", secureString);
//set credential of SharePoint 2013(On-Premises)
//string userName = "Administrator";
//string password = "xxxxxxx";
//string domain = "CONTOSO";
//ICredentials credentials = new NetworkCredential(userName, password, domain);
DownloadFileViaRestAPI(siteURL, credentials, "lib", "test.css", "c:\\SPFX\\");
Console.WriteLine("success");
Console.ReadLine();
}

Related

Getting exception during fileupload to sharepoint in C#

Please see the code below. This is my initialization:
string siteUrl = "https://(*company domain*).sharepoint.com/sites/BankGuaranteeManagement/";
string documentLibrary = "BG Docs";
string fileName = VIEWSTATE_MAIN_FILE_NAME;
string customerFolder = "Bank Guarantees";
string userNameSP = "bgmfileuser#company.com";
string passwordSP = "hs#29n#$";
This is the fileupload code:
#region ConnectToSharePoint
string serverRelativeURL = "";
var securePassword = new SecureString();
foreach (char c in Password)
{ securePassword.AppendChar(c); }
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
var onlineCredentials = new SharePointOnlineCredentials(Login, securePassword);
#endregion
#region Insert the data
using (ClientContext clientContext = new ClientContext(siteUrl))
{
clientContext.Credentials = onlineCredentials;
Web web = clientContext.Web;
List libraryList = clientContext.Web.Lists.GetByTitle("Documents");
Folder folder = libraryList.RootFolder;
clientContext.Load(folder, f => f.ServerRelativeUrl);
clientContext.ExecuteQuery();
serverRelativeURL = folder.ServerRelativeUrl;
System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
Microsoft.SharePoint.Client.File.SaveBinaryDirect(clientContext, serverRelativeURL + "/" + System.IO.Path.GetFileName(filePath), fs, true);
}
#endregion
}
catch (Exception exp)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(exp.Message + Environment.NewLine + exp.StackTrace);
}
On clientContext.ExecuteQuery, I am getting the following error:
Exception
{"The sign-in name or password does not match one in the Microsoft account system."}
Some points worth mentioning:
The ID being used in credentials has MFA disabled.
The ID being used is part of the Active directory.
I can login into portal.office.com using the same ID and password. So, no issues there.
.Net version is 4.6
Latest Sharepoint dll is installed and added.
I went through all materials on internet but cannot figure this ont out. Any help will be useful. Thanks.

c# script Sharepoint API giving 401 Error on remote server

I'm using the below code for sharepoint authentication. It works perfectly fine on a local machine, but when I deploy this package on server it is giving 401 error.
class Program
{
static void Main(string[] args)
{
//Delcaring Required variable (Actual variable values have been changed to dummy one)
var webUri = new Uri("https://blahblah.sharepoint.com");
string proxy = "http://abc.abc.com:1234/";
const string userName = "abc#blahblah.com";
const string password = "123";
string SalesPOV_GUID = "6319bd1f-7f-4ffd-95dc-a992afc4da10";
string Clients_GUID = "ojfoeiawe-3abcc6-41cd-be23-cf6043671d53";
//Creating a secured sring for SharepointOnline Credentials
var securePassword = new SecureString();
foreach (var c in password)
{
securePassword.AppendChar(c);
}
//Setting up credentials for Sharepoint
var credentials = new SharePointOnlineCredentials(userName, securePassword);
//Makiing a Call
using (var client = new WebClient())
{
try
{
//setting up proxy
System.Net.WebProxy wp = new System.Net.WebProxy();
Uri newUri = new Uri(proxy);
wp.Address = newUri;
client.Proxy = wp;
}
catch (WebException e) //In package we need to fail the package on catching exception.
{
string pageContent = new StreamReader(e.Response.GetResponseStream()).ReadToEnd().ToString();
}
client.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
client.Credentials = credentials;
}
}
}
Check if your sharepoint website is set to "pass-through" authentication for the physical path.

sharepoint rest api credentials

I'm triggering an external web page outside of sharepoint which needs to read lists using the sharepoint web api.
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(sharepointUrl.ToString() + "/_api/web/lists");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
//endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken);
HttpWebResponse endpointResponse = (HttpWebResponse)endpointRequest.GetResponse();
I can access the API using chrome if I'm logged in but I suspect I need the access token line.. but can't seem to find a way to populate it.
Currently it returns:
No connection could be made because the target machine actively refused it...
You need to set credential of HttpWebRequest.
Here you go:
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(sharepointUrl.ToString() + "/_api/web/lists");
string password = "XXXXX";
string userName = "XXXX";
SecureString secureString = new SecureString();
foreach (char c in password.ToCharArray())
{
secureString.AppendChar(c);
}
endpointRequest.Credentials = new SharePointOnlineCredentials(userName, secureString);
//.........
If you are using SharePoint online, it can work with my answer above because i have tested.
If you are using SharePoint 2013/2010/2016, the code will be as below.
HttpWebRequest endpointRequest = (HttpWebRequest)HttpWebRequest.Create(sharepointUrl.ToString() + "/_api/web/lists");
string password = "XXXXX";
string userName = "XXXX";
string domain = "XXX"
endpointRequest.Credentials = new NetworkCredential(userName, password, domain);
//.........

Authenticating Sharepoint site from background service and uploading file

I'm trying to authenticate up against Sharepoint so that it's possible for me to upload files onto a specific Sharepoint site.
I'm trying to use an X.509 certificate to retrieve the access token, but I keep getting (401): Unauthorized.
Here's the way I try to retrieve the access token with the certificate:
string authority = SettingsHelper.Authority;
string clientID = SettingsHelper.ClientId;
string serverName = SettingsHelper.SharepointServerName;
//Retreive the certificate path
string certFile = Server.MapPath(SettingsHelper.CertificatePath);
string certPassword = SettingsHelper.CertificatePassword;
AuthenticationResult authenticationResult = null;
AuthenticationContext authenticationContext = new AuthenticationContext(authority);
//Create the certificate file, using the path (certFile), password (certPassword) and the MachineKeySet
X509Certificate2 cert = new X509Certificate2(certFile, certPassword, X509KeyStorageFlags.MachineKeySet);
//Create the ClientAssertionCertificate using the clientID and the actual certificate
ClientAssertionCertificate cac = new ClientAssertionCertificate(clientID, cert);
//Retreive the access token using the serverName and client assertion
authenticationResult = authenticationContext.AcquireToken(serverName, cac);
And here's how I try to upload a specific file onto a specific Sharepoint list:
WebRequest request = null;
HttpWebResponse response = null;
byte[] bytesToUpload = bytes;
var returnValue = "";
string requestUriString = string.Format("{0}/_api/web/GetFolderByServerRelativeUrl(#sru)/Files/Add(url=#fn,overwrite=true)?#sru='{1}'&#fn='{2}'", url, HttpUtility.UrlEncode(serverRelativeUrl), HttpUtility.UrlEncode(fileName));
request = (HttpWebRequest)HttpWebRequest.Create(requestUriString);
request.Method = "POST";
(request as HttpWebRequest).Accept = "*/*";
request.ContentType = "application/json;odata=verbose";
request.Headers.Add("Authorization", String.Format("Bearer {0}", authenticationResult.AccessToken));
request.ContentLength = bytesToUpload.Length;
// Write the local file to the remote system
using (Stream requestStream = request.GetRequestStream())
{
BinaryWriter writer = new BinaryWriter(requestStream);
writer.Write(bytesToUpload, 0, bytesToUpload.Length);
writer.Close();
}
// Get a web response back
response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.Default))
{
returnValue = sr.ReadToEnd();
sr.Close();
}
if (request.RequestUri.ToString().Contains("GetFolderByServerRelativeUrl") == true)
{
returnValue = "";
}
Some of the variables comes from the parameters:
UploadEmail(System.IO.File.ReadAllBytes(emlFilePath), "https://(blablabla).sharepoint.com", "sites/(bla)/(bla)/Emails", email.Subject + ".msg");
I'm not sure what's wrong, and I'm definitely not sure how to fix this.
NOTE: Please don't tell me to use NetworkCredentials, I'd rather use the certificate or something else, but not NetworkCredentials
EDIT
Managed to debug the code and find this in the response header of the WebRequest:
The better approach would be using the SharePoint Client Side Object Model (as hbulens suggested in comments).
Here's the code that uploads the file to the library in O365 (just replace the string literals with your own details):
string username = "YOUR_USERNAME";
string password = "YOUR_PASSWORD";
string siteUrl = "https://XXX.sharepoint.com";
ClientContext context = new ClientContext(siteUrl);
SecureString pass = new SecureString();
foreach (char c in password.ToCharArray()) pass.AppendChar(c);
context.Credentials = new SharePointOnlineCredentials(username, pass);
Site site = context.Site;
context.Load(site);
context.ExecuteQuery();
Web web = site.OpenWeb("YOUR_SUBSITE");
context.Load(web);
context.ExecuteQuery();
List docLib = web.Lists.GetByTitle("YOUR_LIBRARY");
context.Load(docLib);
FileCreationInformation newFile = new FileCreationInformation();
string filePath = #"YOUR_LOCAL_FILE";
newFile.Content = System.IO.File.ReadAllBytes(filePath);
newFile.Url = System.IO.Path.GetFileName(filePath);
Microsoft.SharePoint.Client.File uploadFile = docLib.RootFolder.Files.Add(newFile);
context.Load(uploadFile);
context.ExecuteQuery();
You can run it in console application. Two dll's that you need to reference are:
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll

Upload File To SharePoint Online(office 365) Library Invokes Error

How can one resolve this runtime error?
Error
Could not load file or assembly 'Microsoft.SharePoint.Library, Version = 14.0.0.0, Culture = neutral, PublicKeyToken = 71e9bce111e9429c' or one of its dependencies. The system can not find the file specified.
CODE
string destUrl = "URL";
string destFileUrl = destUrl + "biblioteca" + "/text.txt";
using(SPWeb site = new SPSite(destUrl).OpenWeb())
{
site.AllowUnsafeUpdates = true;
FileStream fileStream = File.Open("FILE" , FileMode.Open);
site.Files.Add(destFileUrl, fileStream, true/*overwrite*/);
fileStream.Close();
}
This works for me.
using (ClientContext clientContext = new ClientContext("SHAREPOINT URL")) {
SecureString passWord = new SecureString();
foreach (char c in "PASSWORD".ToCharArray()) passWord.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials("ACOUNT.onmicrosoft.com", passWord);
Web web = clientContext.Web;
FileCreationInformation newFile = new FileCreationInformation();
newFile.Content = System.IO.File.ReadAllBytes(FILE);
newFile.Url = NAMEFORTHEFILE;
List docs = web.Lists.GetByTitle("LIBRARY NAME");
Microsoft.SharePoint.Client.File uploadFile = docs.RootFolder.Files.Add(newFile);
clientContext.ExecuteQuery();
}
string fileName = #"C:\AddUser.aspx";
using (var context = new ClientContext("https://yourdomain.com")) {
var passWord = new SecureString();
foreach (var c in "YourPassword") passWord.AppendChar(c);
context.Credentials = new SharePointOnlineCredentials("YourUsername", passWord);
var web = context.Web;
var newFile = new FileCreationInformation {
Content = System.IO.File.ReadAllBytes(fileName),
Url = Path.GetFileName(fileName)
};
var docs = web.Lists.GetByTitle("Pages");
Microsoft.SharePoint.Client.File uploadFile = docs.RootFolder.Files.Add(newFile);
context.ExecuteQuery();
}
Have you encountered this error: The partner returned a bad sign-in name or password error. For more information, see Federation Error-handling Scenarios.
I have the following codes:
NetworkCredential Cred = new NetworkCredential(ConfigurationManager.AppSettings["Username"], ConfigurationManager.AppSettings["Password"], ConfigurationManager.AppSettings["Domain"]);
SecureString PassWord = new SecureString();
foreach (char c in ConfigurationManager.AppSettings["Password"].ToCharArray()) PassWord.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials(ConfigurationManager.AppSettings["Username"], PassWord);
Web web = clientContext.Web;
clientContext.Load(web);
You cannot use the server side object model to upload files to SharePoint Online.
One has to use the Client Object Model to upload files to SharePoint online.
More Info
Office 365 Sharepoint Upload Files to Documents Library

Categories

Resources