|
| 1 | +# Bulk upload documents sample add-in for SharePoint |
| 2 | + |
| 3 | +As part of your Enterprise Content Management (ECM) strategy, you can bulk upload documents to document libraries, including OneDrive for Business. |
| 4 | + |
| 5 | +_**Applies to:** Office 365 | SharePoint 2013 | SharePoint Online_ |
| 6 | + |
| 7 | +**Note** The sample uploads one file to a document library. To upload multiple files, you'll need to extend the sample. |
| 8 | + |
| 9 | +This add-in uses a console application to upload files by using REST API calls. Configuration settings are specified in an XML and a CSV file. Use this solution if you want to: |
| 10 | + |
| 11 | +- Upload files to SharePoint Online. |
| 12 | + |
| 13 | +- Migrate to Office 365 and use a custom migration tool to move your files. |
| 14 | + |
| 15 | +## Before you begin |
| 16 | +<a name="sectionSection0"> </a> |
| 17 | + |
| 18 | +To get started, download the [Core.BulkDocumentUploader](https://github.com/SharePoint/PnP/tree/master/Samples/Core.BulkDocumentUploader) sample add-in from the [Office 365 Developer patterns and practices](https://github.com/SharePoint/PnP/tree/dev) project on GitHub. |
| 19 | + |
| 20 | +Before you run the code sample, do the following: |
| 21 | + |
| 22 | + |
| 23 | +1. Edit the OneDriveUploader.xml file with the following information: |
| 24 | + |
| 25 | + - The ___location where you want to save your text and CSV log files. |
| 26 | + |
| 27 | + - The file path to your CSV mapping file (for example, C:\PnP\Samples\Core.BulkDocumentUploader\Input\SharePointSites.csv). |
| 28 | + |
| 29 | + - The ___location of the company policy files to upload (for example, C:\PnP\Samples\Core.BulkDocumentUploader\Input\OneDriveFiles). |
| 30 | + |
| 31 | + - Your SharePoint Online credentials. |
| 32 | + |
| 33 | + - The document action to perform (either upload or delete). |
| 34 | + |
| 35 | + - The new file name to apply to the file after the file is uploaded to the document library (for example, COMPANY POLICY DOCUMENT.xlsx). |
| 36 | + |
| 37 | +2. In the SharePointSites.csv mapping file, list the document library URL to upload files to, and the name of the company policy file to upload. |
| 38 | + |
| 39 | +3. Add the file path of the OneDriveUploader.xml file as a command-line argument. To do this, open the Core.BulkDocumentUploader project properties in Solution Explorer, and then choose **Properties** > **Debug**, as shown in Figure 1. |
| 40 | + |
| 41 | + **Figure 1. Setting OneDriveUploader.xml as a command-line argument in the project properties** |
| 42 | + |
| 43 | +  |
| 44 | + |
| 45 | + |
| 46 | +## Using the Core.BulkDocumentUploader sample app |
| 47 | +<a name="sectionSection1"> </a> |
| 48 | + |
| 49 | +From the **Main** method in Program.cs, the **RecurseActions** method calls the **Run** method in OneDriveMapper.cs. The **Run** method gets the ___location of the file to upload from SharePointSites.csv, and then calls the **IterateCollection** method. |
| 50 | + |
| 51 | +**Note** The code in this article is provided as-is, without warranty of any kind, either express or implied, including any implied warranties of fitness for a particular purpose, merchantability, or non-infringement. |
| 52 | + |
| 53 | +```C# |
| 54 | +public override void Run(BaseAction parentAction, DateTime CurrentTime, LogHelper logger) |
| 55 | + { |
| 56 | + CsvProcessor csvProcessor = new CsvProcessor(); |
| 57 | + |
| 58 | + logger.LogVerbose(string.Format("Attempting to read mapping CSV file '{0}'", this.UserMappingCSVFile)); |
| 59 | + |
| 60 | + using (StreamReader reader = new StreamReader(this.UserMappingCSVFile)) |
| 61 | + { |
| 62 | + csvProcessor.Execute(reader, (entries, y) => { IterateCollection(entries, logger); }, logger); |
| 63 | + } |
| 64 | + } |
| 65 | + |
| 66 | +``` |
| 67 | + |
| 68 | +The SharePointSite.csv file lists a file to upload and the document library to upload that file to. The **IterateCollection** method then does the following to upload the file to the document library: |
| 69 | + |
| 70 | +1. Gets the file to upload. |
| 71 | + |
| 72 | +2. Ensures that the user has permissions to add items. |
| 73 | + |
| 74 | +3. Creates the **HttpWebRequest** object with the authentication cookie, the REST string request to upload the document, and the HTTP request action method. |
| 75 | + |
| 76 | +4. Performs the file upload. |
| 77 | + |
| 78 | +**Note** The file name is overwritten with the value of **FileUploadName** specified in OneDriveUploader.xml. |
| 79 | + |
| 80 | +```C# |
| 81 | +public override void IterateCollection(Collection<string> entries, LogHelper logger) |
| 82 | + { |
| 83 | + Stopwatch IterationSW = new Stopwatch(); |
| 84 | + IterationSW.Start(); |
| 85 | + |
| 86 | + logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Establishing context object to: '{0}'", entries[this.SiteIndex])); |
| 87 | + |
| 88 | + try |
| 89 | + { |
| 90 | + // Use the context of the current iteration URL for current user item. |
| 91 | + using (ClientContext context = new ClientContext(entries[this.SiteIndex])) |
| 92 | + { |
| 93 | + using (SecureString password = new SecureString()) |
| 94 | + { |
| 95 | + foreach (char c in this.Password.ToCharArray()) |
| 96 | + { |
| 97 | + password.AppendChar(c); |
| 98 | + } |
| 99 | + |
| 100 | + context.Credentials = new SharePointOnlineCredentials(this.UserName, password); |
| 101 | + |
| 102 | + // Get the file to upload from the directory. |
| 103 | + FileInfo theFileToUpload = new FileInfo(Path.Combine(this.DirectoryLocation + "\\", entries[this.FileIndex] + ".xlsx")); |
| 104 | + |
| 105 | + logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Attempting to {0} file {1}", this.DocumentAction, theFileToUpload)); |
| 106 | + |
| 107 | + // Ensure that the account has permissions to access. |
| 108 | + BasePermissions perm = new BasePermissions(); |
| 109 | + perm.Set(PermissionKind.AddListItems); |
| 110 | + |
| 111 | + ConditionalScope scope = new ConditionalScope(context, () => context.Web.DoesUserHavePermissions(perm).Value); |
| 112 | + |
| 113 | + using(scope.StartScope()) |
| 114 | + { |
| 115 | + Stopwatch tempSW = new Stopwatch(); |
| 116 | + tempSW.Start(); |
| 117 | + |
| 118 | + int success = 0; |
| 119 | + |
| 120 | + while(tempSW.Elapsed.TotalSeconds < 20) |
| 121 | + { |
| 122 | + var digest = context.GetFormDigestDirect(); |
| 123 | + |
| 124 | + string cookie = ((SharePointOnlineCredentials)context.Credentials).GetAuthenticationCookie(new Uri(entries[this.SiteIndex])).TrimStart("SPOIDCRL=".ToCharArray()); |
| 125 | + |
| 126 | + using (Stream s = theFileToUpload.OpenRead()) |
| 127 | + { |
| 128 | + // Define REST string request to upload document to context. This string specifies the Documents folder, but you can specify another document library. |
| 129 | + string theTargetUri = string.Format(CultureInfo.CurrentCulture, "{0}/_api/web/lists/getByTitle('Documents')/RootFolder/Files/add(url='{1}',overwrite='true')?", entries[this.SiteIndex], this.FileUploadName); |
| 130 | + |
| 131 | + // Define REST HTTP request object. |
| 132 | + HttpWebRequest SPORequest = (HttpWebRequest)HttpWebRequest.Create(theTargetUri); |
| 133 | + |
| 134 | + // Define HTTP request action method. |
| 135 | + if (this.DocumentAction == "Upload") |
| 136 | + { |
| 137 | + SPORequest.Method = "POST"; |
| 138 | + } |
| 139 | + else if (this.DocumentAction == "Delete") |
| 140 | + { |
| 141 | + SPORequest.Method = "DELETE"; |
| 142 | + } |
| 143 | + else |
| 144 | + { |
| 145 | + logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "There was a problem with the HTTP request in DocumentAction attribute of XML file")); |
| 146 | + throw new Exception("The HTTP Request operation is not supported, please check the value of DocumentAction in the XML file"); |
| 147 | + } |
| 148 | + |
| 149 | + // Build out additional HTTP request details. |
| 150 | + SPORequest.Accept = "application/json;odata=verbose"; |
| 151 | + SPORequest.Headers.Add("X-RequestDigest", digest.DigestValue); |
| 152 | + SPORequest.ContentLength = s.Length; |
| 153 | + SPORequest.ContentType = "application/octet-stream"; |
| 154 | + |
| 155 | + // Handle authentication to context through cookie. |
| 156 | + SPORequest.CookieContainer = new CookieContainer(); |
| 157 | + SPORequest.CookieContainer.Add(new Cookie("SPOIDCRL", cookie, string.Empty, new Uri(entries[this.SiteIndex]).Authority)); |
| 158 | + |
| 159 | + // Perform file upload/deletion. |
| 160 | + using (Stream requestStream = SPORequest.GetRequestStream()) |
| 161 | + { |
| 162 | + s.CopyTo(requestStream); |
| 163 | + } |
| 164 | + |
| 165 | + // Get HTTP response to determine success of operation. |
| 166 | + HttpWebResponse SPOResponse = (HttpWebResponse)SPORequest.GetResponse(); |
| 167 | + |
| 168 | + logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Successfully '{0}' file {1}", this.DocumentAction, theFileToUpload)); |
| 169 | + logger.LogOutcome(entries[this.SiteIndex], "SUCCCESS"); |
| 170 | + |
| 171 | + success = 1; |
| 172 | + |
| 173 | + // Dispose of the HTTP response. |
| 174 | + SPOResponse.Close(); |
| 175 | + |
| 176 | + break; |
| 177 | + } |
| 178 | + |
| 179 | + } |
| 180 | + |
| 181 | + tempSW.Stop(); |
| 182 | + |
| 183 | + if (success != 1) |
| 184 | + { |
| 185 | + throw new Exception("The HTTP Request operation exceeded the timeout of 20 seconds"); |
| 186 | + } |
| 187 | + |
| 188 | + } |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + } |
| 193 | + catch(Exception ex) |
| 194 | + { |
| 195 | + logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "There was an issue performing '{0}' on to the URL '{1}' with exception: {2}", this.DocumentAction, entries[this.SiteIndex], ex.Message)); |
| 196 | + logger.LogOutcome(entries[this.SiteIndex], "FAILURE"); |
| 197 | + } |
| 198 | + finally |
| 199 | + { |
| 200 | + IterationSW.Stop(); |
| 201 | + logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Completed processing URL:'{0}' in {1} seconds", entries[this.SiteIndex], IterationSW.ElapsedMilliseconds/1000)); |
| 202 | + } |
| 203 | + } |
| 204 | + |
| 205 | +``` |
| 206 | + |
| 207 | +## Additional resources |
| 208 | +<a name="bk_addresources"> </a> |
| 209 | + |
| 210 | +- [Enterprise Content Management solutions for SharePoint 2013 and SharePoint Online](Enterprise-Content-Management-solutions-for-SharePoint-2013-and-SharePoint-Online.md) |
| 211 | + |
| 212 | +- [Core.LargeFileUpload sample](https://github.com/SharePoint/PnP/tree/master/Samples/Core.LargeFileUpload) |
| 213 | + |
0 commit comments