/// <summary> /// Put's a file as a stream using the REST API documented at https://developers.google.com/drive/v3/web/manage-uploads#multipart /// </summary> /// <param name="szFileName">The file name to use</param> /// <param name="ms">The stream of the data</param> /// <param name="szMimeType">The mime type for the data</param> /// <returns>True for success</returns> /// <exception cref="MyFlightbookException"></exception> /// <exception cref="System.Net.Http.HttpRequestException"></exception> public async Task <IReadOnlyDictionary <string, string> > PutFile(Stream ms, string szFileName, string szMimeType) { if (!CheckAccessToken()) { throw new MyFlightbookException("Google drive: access token missing or expired"); } bool fIsCSV = szMimeType.CompareCurrentCultureIgnoreCase("text/csv") == 0; ms.Seek(0, SeekOrigin.Begin); // write out the whole stream. UploadAsync appears to pick up from the current location, which is the end-of-file after writing to a ZIP. string szResult = string.Empty; HttpResponseMessage response = null; using (HttpClient httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + AuthState.AccessToken); if (String.IsNullOrEmpty(RootFolderID)) { RootFolderID = await IDForFolder(RootPath); if (String.IsNullOrEmpty(RootFolderID)) { RootFolderID = await CreateFolder(Branding.CurrentBrand.AppName); } } // CSV loses its extension when uploaded because we map it to a google spreadsheet. So if it's CSV AND we are patching an existing file, drop the extension so that we ov // update the existing file if it is present. If CSV, strip the extension string szFileNameToCheck = fIsCSV ? Path.GetFileNameWithoutExtension(szFileName) : szFileName; string idExisting = null; if (!String.IsNullOrEmpty(RootFolderID)) { idExisting = await IDForFile(szFileNameToCheck, RootFolderID); } // If we got a hit, use that filename for the udpate if (!String.IsNullOrEmpty(idExisting)) { szFileName = szFileNameToCheck; } // Create the metadata. Name is most important, but we can also specify mimeType for CSV to import into GoogleDocs Dictionary <string, object> dictMeta = new Dictionary <string, object>() { { "name", szFileName } }; if (fIsCSV) { dictMeta["mimeType"] = "application/vnd.google-apps.spreadsheet"; // get it to show up in google drive sheets. } if (String.IsNullOrEmpty(idExisting) && !String.IsNullOrEmpty(RootFolderID)) { dictMeta["parents"] = new List <string>() { RootFolderID } } ; // Create the form. The form itself needs the authtoken header using (MultipartContent form = new MultipartContent("related")) { // Next add the metadata - it is in Json format string szJSonMeta = JsonConvert.SerializeObject(dictMeta); StringContent metadata = new StringContent(szJSonMeta, System.Text.Encoding.UTF8); metadata.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json") { CharSet = "UTF-8" }; form.Add(metadata); // Finally, add the body, with its appropriate mime type. StreamContent body = new StreamContent(ms); body.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(szMimeType); form.Add(body); try { response = (String.IsNullOrEmpty(idExisting)) ? await httpClient.PostAsync(szURLUploadEndpoint, form) : await httpClient.PatchAsync(new Uri(String.Format(szURLUpdateEndpointTemplate, idExisting)), form); szResult = response.Content.ReadAsStringAsync().Result; response.EnsureSuccessStatusCode(); return((String.IsNullOrEmpty(szResult)) ? null : JsonConvert.DeserializeObject <Dictionary <string, string> >(szResult)); } catch (System.Net.Http.HttpRequestException ex) { if (response == null) { throw new MyFlightbookException("Unknown error in GoogleDrive.PutFile", ex); } Dictionary <string, GoogleDriveError> d = String.IsNullOrEmpty(szResult) ? null : JsonConvert.DeserializeObject <Dictionary <string, GoogleDriveError> >(szResult); GoogleDriveError gde = (d == null || !d.ContainsKey("error")) ? null : d["error"]; if (gde != null && gde.code == 403 && gde.errors != null && gde.errors.Length > 0 && gde.errors[0].reason != null && gde.errors[0].reason.CompareCurrentCultureIgnoreCase("storageQuotaExceeded") == 0) { throw new MyFlightbookException(Resources.LocalizedText.GoogleDriveOutOfSpace); } else { throw new MyFlightbookException(response.ReasonPhrase + " " + (szResult ?? string.Empty)); } } } } } }
private static async Task <GoogleDriveResultDictionary> SendForm(HttpClient httpClient, Stream ms, Dictionary <string, object> dictMeta, string szMimeType, string idExisting) { string szResult = string.Empty; HttpResponseMessage response = null; // Create the form. The form itself needs the authtoken header using (MultipartContent form = new MultipartContent("related")) { // Next add the metadata - it is in Json format string szJSonMeta = JsonConvert.SerializeObject(dictMeta); using (StringContent metadata = new StringContent(szJSonMeta, System.Text.Encoding.UTF8)) { metadata.Headers.ContentType = new MediaTypeHeaderValue("application/json") { CharSet = "UTF-8" }; form.Add(metadata); // Finally, add the body, with its appropriate mime type. using (StreamContent body = new StreamContent(ms)) { body.Headers.ContentType = new MediaTypeHeaderValue(szMimeType); form.Add(body); try { response = (String.IsNullOrEmpty(idExisting)) ? await httpClient.PostAsync(new Uri(szURLUploadEndpoint), form).ConfigureAwait(false) : await httpClient.PatchAsync(new Uri(String.Format(CultureInfo.InvariantCulture, szURLUpdateEndpointTemplate, idExisting)), form, false).ConfigureAwait(false); szResult = await response.Content.ReadAsStringAsync().ConfigureAwait(false); response.EnsureSuccessStatusCode(); return((String.IsNullOrEmpty(szResult)) ? null : JsonConvert.DeserializeObject <GoogleDriveResultDictionary>(szResult)); } catch (HttpRequestException ex) { if (response == null) { throw new MyFlightbookException("Unknown error in GoogleDrive.PutFile", ex); } Dictionary <string, GoogleDriveError> d = String.IsNullOrEmpty(szResult) ? null : JsonConvert.DeserializeObject <Dictionary <string, GoogleDriveError> >(szResult); GoogleDriveError gde = (d == null || !d.ContainsKey("error")) ? null : d["error"]; if (gde != null && gde.code == 403 && gde.errors != null && gde.errors.Count > 0 && gde.errors[0].reason != null && gde.errors[0].reason.CompareCurrentCultureIgnoreCase("storageQuotaExceeded") == 0) { throw new MyFlightbookException(Resources.LocalizedText.GoogleDriveOutOfSpace); } else { throw new MyFlightbookException(response.ReasonPhrase + " " + (szResult ?? string.Empty)); } } finally { if (response != null) { response.Dispose(); } } } } } }