Download all documents from SharePoint List using the URL - c#

I wanted to know how to download all documents from a SharePoint list using the SharePoint client object model (CSOM) (Microsoft.SharePoint.Client) and the lists full URL.
For example, if the URL was http://teamhub.myorg.local/sites/teams/it/ISLibrary/Guides/
Is it possible to connect directly to that URL and retrieve all documents stored there?
I have tried out the below code but I am getting an error, also it seems to require that I split the URL into two parts.
string baseURL = "http://teamhub.myorg.local/sites/";
string listURL = "teams/it/ISLibrary/Guides/";
var ctx = new ClientContext(baseURL);
ctx.Credentials = new SharePointOnlineCredentials(userName, SecuredpassWord);
var list = ctx.Web.GetList(listURL);
ctx.Load(list);
ctx.ExecuteQuery();
Console.WriteLine(list.Title);
When I run this code I simply get a "File not found" error.
Can it be done by simply passing in the full url somewhere?
I will need to do this connection and get all documents 100's of times over for many different lists, so it would be best if there is a way to do it using the full URL.
Any advice is appreciated. Thanks

Microsoft.SharePoint.Client.Web.GetListByUrl use webRelativeUrl, for example:
My site: https://tenant.sharepoint.com/sites/TST, library: https://tenant.sharepoint.com/sites/TST/MyDoc4
So the code would be:
Web web = clientContext.Web;
var lib=web.GetListByUrl("/MyDoc4");
The listURL you shared seems a folder, so we could get the folder and files in folder as below:
Web web = clientContext.Web;
Folder folder = web.GetFolderByServerRelativeUrl("/sites/TST/MyDoc4/Folder");
var files = folder.Files;
clientContext.Load(files);
clientContext.ExecuteQuery();
Download fileļ¼š
foreach (var file in files)
{
clientContext.Load(file);
Console.WriteLine(file.Name);
ClientResult<Stream> stream = file.OpenBinaryStream();
clientContext.ExecuteQuery();
var fileOut = Path.Combine(localPath, file.Name);
if (!System.IO.File.Exists(fileOut))
{
using (Stream fileStream = new FileStream(fileOut, FileMode.Create))
{
CopyStream(stream.Value, fileStream);
}
}
}
private static void CopyStream(Stream src, Stream dest)
{
byte[] buf = new byte[8192];
for (; ; )
{
int numRead = src.Read(buf, 0, buf.Length);
if (numRead == 0)
break;
dest.Write(buf, 0, numRead);
}
}

Related

Uploading Image into SharePoint document library C#

I have a web service that currently passes base64 image format, However, How can I insert it into a sharepoint library? should i convert it to bytes array ?
Yes, need to read image file stream and then use Microsoft.SharePoint.Client.File.SaveBinaryDirect to save into SharePoint library:
var fileName=#"C:\Test.jpg";
using (ClientContext context = new ClientContext("http://sp/"))
{
using (var fs = new FileStream(fileName, FileMode.Open))
{
var fi = new FileInfo(fileName);
var list = context.Web.Lists.GetByTitle("Documents");
context.Load(list.RootFolder);
context.ExecuteQuery();
var fileUrl = String.Format("{0}/{1}", list.RootFolder.ServerRelativeUrl, fi.Name);
Microsoft.SharePoint.Client.File.SaveBinaryDirect(context, fileUrl, fs, true);
}
}
Here is a similiar thread for your reference:
How to Upload Images to SharePoint Online(Office 365) Picture-library using CSOM (Java Script)?

Download a specific file from SharePoint (CSOM) using C#

I'm developing a C# based application that requires to download, checkout, upload, check in on a specific file from/to Sharepoint with CSOM. So I have two questions here:
Firstly, on download, is there others way to download a specific named file under folder "Document" instead of searching through GetItemByID(). Please refer to code below:
string siteUrl = #"http://test.com/sites/company/";
ClientContext ctx = new ClientContext(siteUrl);
ctx.Credentials = new NetworkCredential("username", "password" , "domain");
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
var list = ctx.Web.Lists.GetByTitle("Document");
var listItem = list.GetItemById();
ctx.Load(list);
ctx.Load(listItem, i => i.File);
ctx.ExecuteQuery();
var fileRef = listItem.File.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(ctx, fileRef);
var fileName = Path.Combine("C:\\", (string)listItem.File.Name);
using (var fileStream = System.IO.File.Create(fileName))
{
fileInfo.Stream.CopyTo(fileStream);
}
Secondly, in regards to the workflow (download, modify, check out, upload, check in), is this feasible of doing?
Thanks in advance.
For getting specific file, no need to get ListItem by Id, instead, directly pass server relativer url like this:
ClientContext clientContext = new ClientContext("http://sp/sites/dev");
Web web = clientContext.Web;
Microsoft.SharePoint.Client.File filetoDownload = web.GetFileByServerRelativeUrl("/sites/dev/shared%20documents/mytest.txt");
clientContext.Load(filetoDownload);
clientContext.ExecuteQuery();
var fileRef = filetoDownload.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
var fileName = Path.Combine("C:\\", (string)filetoDownload.Name);
using (var fileStream = System.IO.File.Create(fileName))
{
fileInfo.Stream.CopyTo(fileStream);
}
For other usage, checkout,update,checkin, I would suggest you can still use CSOM, as there are buit-in functions support:
File methods

Web API: Download Multiple Files Separately

I have a Web Api controller method that gets passed document IDs and it should return the document files individually for those requested Ids. I have tried the accepted answer from the following link to achieve this functionality, but it's not working. I don't know where I did go wrong.
What's the best way to serve up multiple binary files from a single WebApi method?
My Web Api Method,
public async Task<HttpResponseMessage> DownloadMultiDocumentAsync(
IClaimedUser user, string documentId)
{
List<long> docIds = documentId.Split(',').Select(long.Parse).ToList();
List<Document> documentList = coreDataContext.Documents.Where(d => docIds.Contains(d.DocumentId) && d.IsActive).ToList();
var content = new MultipartContent();
CloudBlockBlob blob = null;
var container = GetBlobClient(tenantInfo);
var directory = container.GetDirectoryReference(
string.Format(DirectoryNameConfigValue, tenantInfo.TenantId.ToString(), documentList[0].ProjectId));
for (int docId = 0; docId < documentList.Count; docId++)
{
blob = directory.GetBlockBlobReference(DocumentNameConfigValue + documentList[docId].DocumentId);
if (!blob.Exists()) continue;
MemoryStream memStream = new MemoryStream();
await blob.DownloadToStreamAsync(memStream);
memStream.Seek(0, SeekOrigin.Begin);
var streamContent = new StreamContent(memStream);
content.Add(streamContent);
}
HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
httpResponseMessage.Content = content;
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
httpResponseMessage.StatusCode = HttpStatusCode.OK;
return httpResponseMessage;
}
I tried with 2 or more document Ids but only one file was downloaded and that also is not in the correct format (without extension).
Zipping is the only option that will have consistent result on all browsers. MIME/multipart content is for email messages (https://en.wikipedia.org/wiki/MIME#Multipart_messages) and it was never intended to be received and parsed on the client side of a HTTP transaction. Some browsers do implement it, some others don't.
Alternatively, you can change your API to take in a single docId and iterate over your API from your client for each docId.
I think only way is that you zip your all the files and then download one zip file. I guess you can use dotnetzip package because it is easy to use.
One way is that, you can first save your files on disk and then stream the zip to download. Another way is, you can zip them in memory and then download the file in stream
public ActionResult Download()
{
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(Server.MapPath("~/Directories/hello"));
MemoryStream output = new MemoryStream();
zip.Save(output);
return File(output, "application/zip", "sample.zip");
}
}

This method or property is not supported after HttpRequest.GetBufferlessInputStream has been invoked

I am trying to browse and upload a file from client to server using Angular Js and WEB API.I used Input file type for user to select file and post the file to WEB API. In web API, I am getting following error "This method or property is not supported after HttpRequest.GetBufferlessInputStream has been invoked."
I am using the following code:-
public IHttpActionResult UploadForm()
{
HttpResponseMessage response = new HttpResponseMessage();
var httpRequest = System.Web.HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = System.Web.HttpContext.Current.Server.MapPath("~/UploadFile/" + postedFile.FileName);
postedFile.SaveAs(filePath);
}
}
return Json("Document Saved");
}
I get this error when i tried to get files from HTTP request... should I update anything in web config??
Please help me to resolve this issue..
try this it work fine for me.
//get the root folder where file will be store
string root = HttpContext.Current.Server.MapPath("~/UploadFile");
// Read the form data.
var provider = new MultipartFormDataStreamProvider(root);
await Request.Content.ReadAsMultipartAsync(provider);
if (provider.FileData.Count > 0 && provider.FileData[0] != null)
{
MultipartFileData file = provider.FileData[0];
//clean the file name
var fileWithoutQuote = file.Headers.ContentDisposition.FileName.Substring(1, file.Headers.ContentDisposition.FileName.Length - 2);
//get current file directory on the server
var directory = Path.GetDirectoryName(file.LocalFileName);
if (directory != null)
{
//generate new random file name (not mandatory)
var randomFileName = Path.Combine(directory, Path.GetRandomFileName());
var fileExtension = Path.GetExtension(fileWithoutQuote);
var newfilename = Path.ChangeExtension(randomFileName, fileExtension);
//Move file to rename existing upload file name with new random filr name
File.Move(file.LocalFileName, newfilename);
}
}
I also had the same problem. And the solution by #Jean did not work for me.
I need to upload some CSV file and had to use it in the controller.
In Javascript, I used Fetch API to upload the csv file.
But, in the controller, I used this code:
[HttpPost]
[CatchException]
public bool ImportBundlesFromCsv()
{
var a = Request.Content.ReadAsByteArrayAsync();
//convert to Stream if needed
Stream stream = new MemoryStream(a.Result); // a.Result is byte[]
// convert to String if needed
string result = System.Text.Encoding.UTF8.GetString(a.Result);
// your code
return true;
}
This worked for me. Hope this helps!

How to Upload to SharePoint using a memory stream? Using COM

I am creating a method to UploadDocument_FromStream() method which has one parameter -- Stream file.
I am having trouble trying to keep my SharePoint connection open to allow me to upload my Stream file to SharePoint. I think the issue is due to the fact that I am executing a query then trying to upload to SharePoint.
Is this the best way to handle Uploading to SharePoint with a MemoryStream?
UploadDocument_FromStream()
public void UploadDocument_FromStream(Stream file)
{
using (var clientContext = OpenConnectionToSharePoint())
{
if (file == null) throw new Exception("Stream cannot be null");
using (clientContext)
{
var list = clientContext.Web.Lists.GetByTitle("Documents");
clientContext.Load(list.RootFolder);
clientContext.ExecuteQuery();
Microsoft.SharePoint.Client.File.SaveBinaryDirect(clientContext, "/shared documents/test.pdf", file, true);
}
}
Also should note - that I am using SharePoint.Client.dll or COM approach.
SharePoint CSOM API utilizes internal query queue to support Request Batching via ClientRuntimeContext.Load method. But both File.OpenBinaryDirect and File.SaveBinaryDirect methods are executed directly and require internal queue to be empty. For that purpose you could utilize the following checking before invoking File.SaveBinaryDirect method:
if (ctx.HasPendingRequest)
ctx.ExecuteQuery();
The following example shows how to save a file stream into documents library
var list = ctx.Web.Lists.GetByTitle(listTitle);
ctx.Load(list.RootFolder);
ctx.ExecuteQuery();
var fileName = System.IO.Path.GetFileName(path);
byte[] data = System.IO.File.ReadAllBytes(path);
MemoryStream stream = new MemoryStream(data);
var fileUrl = Path.Combine(list.RootFolder.ServerRelativeUrl, fileName);
if (ctx.HasPendingRequest)
ctx.ExecuteQuery();
Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, fileUrl, stream, true);

Categories