From f4f14c97af51f3ea238c0155a1121eb0ae52b36b Mon Sep 17 00:00:00 2001 From: rgregg Date: Mon, 18 May 2015 10:05:43 -0700 Subject: [PATCH 01/13] Updating dependencies and resolving warnings --- OneDriveApiExplorer/FormBrowser.cs | 6 +++--- OneDriveApiExplorer/OneDriveApiExplorer.csproj | 15 +++++++-------- OneDriveApiExplorer/Picker/FormOneDrivePicker.cs | 2 +- OneDriveApiExplorer/packages.config | 8 ++++---- OneDriveSDK/OneDriveSDK.csproj | 15 ++++++++------- OneDriveSDK/packages.config | 9 ++++----- 6 files changed, 27 insertions(+), 28 deletions(-) diff --git a/OneDriveApiExplorer/FormBrowser.cs b/OneDriveApiExplorer/FormBrowser.cs index 19a17ae..642e81d 100644 --- a/OneDriveApiExplorer/FormBrowser.cs +++ b/OneDriveApiExplorer/FormBrowser.cs @@ -195,7 +195,7 @@ private void FixBreadCrumbForCurrentFolder(ODItem folder) } } - private void linkLabelBreadcrumb_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + private async void linkLabelBreadcrumb_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { LinkLabel link = (LinkLabel)sender; @@ -205,11 +205,11 @@ private void linkLabelBreadcrumb_LinkClicked(object sender, LinkLabelLinkClicked if (null == item) { - Task t = LoadFolderFromId("root"); + await LoadFolderFromId("root"); } else { - Task t = LoadFolderFromId(item.Id); + await LoadFolderFromId(item.Id); } } diff --git a/OneDriveApiExplorer/OneDriveApiExplorer.csproj b/OneDriveApiExplorer/OneDriveApiExplorer.csproj index 92fe8c3..6e56d27 100644 --- a/OneDriveApiExplorer/OneDriveApiExplorer.csproj +++ b/OneDriveApiExplorer/OneDriveApiExplorer.csproj @@ -68,14 +68,6 @@ false - - False - ..\packages\MicrosoftAccount.WindowsForms.1.0.3.0\lib\net45\MicrosoftAccount.WindowsForms.dll - - - False - ..\packages\Newtonsoft.Json.6.0.5\lib\net45\Newtonsoft.Json.dll - @@ -87,6 +79,12 @@ + + ..\packages\MicrosoftAccount.WindowsForms.1.0.4.0\lib\net45\MicrosoftAccount.WindowsForms.dll + + + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + @@ -222,6 +220,7 @@ + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. diff --git a/OneDriveApiExplorer/Picker/FormOneDrivePicker.cs b/OneDriveApiExplorer/Picker/FormOneDrivePicker.cs index 1fe2d05..b34156a 100644 --- a/OneDriveApiExplorer/Picker/FormOneDrivePicker.cs +++ b/OneDriveApiExplorer/Picker/FormOneDrivePicker.cs @@ -70,7 +70,7 @@ private void webBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e) private void CloseWindow() { const int interval = 100; - var t = new System.Threading.Timer(new System.Threading.TimerCallback((state) => + new System.Threading.Timer(new System.Threading.TimerCallback((state) => { this.DialogResult = System.Windows.Forms.DialogResult.OK; this.BeginInvoke(new MethodInvoker(() => this.Close())); diff --git a/OneDriveApiExplorer/packages.config b/OneDriveApiExplorer/packages.config index 2952537..f55cfaa 100644 --- a/OneDriveApiExplorer/packages.config +++ b/OneDriveApiExplorer/packages.config @@ -1,8 +1,8 @@  - + - - - + + + \ No newline at end of file diff --git a/OneDriveSDK/OneDriveSDK.csproj b/OneDriveSDK/OneDriveSDK.csproj index ba3c01c..44df23b 100644 --- a/OneDriveSDK/OneDriveSDK.csproj +++ b/OneDriveSDK/OneDriveSDK.csproj @@ -111,17 +111,17 @@ ..\packages\Microsoft.Bcl.Async.1.0.168\lib\portable-net45+win8+wp8+wpa81\Microsoft.Threading.Tasks.Extensions.dll - - ..\packages\Newtonsoft.Json.6.0.6\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Newtonsoft.Json.dll - - ..\packages\Microsoft.Net.Http.2.2.28\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.dll + ..\packages\Microsoft.Net.Http.2.2.29\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.dll + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Primitives.dll - ..\packages\Microsoft.Net.Http.2.2.28\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Extensions.dll + ..\packages\Microsoft.Net.Http.2.2.29\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Extensions.dll - - ..\packages\Microsoft.Net.Http.2.2.28\lib\portable-net40+sl4+win8+wp71+wpa81\System.Net.Http.Primitives.dll + + ..\packages\Newtonsoft.Json.6.0.8\lib\portable-net45+wp80+win8+wpa81+aspnetcore50\Newtonsoft.Json.dll @@ -134,6 +134,7 @@ + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. diff --git a/OneDriveSDK/packages.config b/OneDriveSDK/packages.config index 7ad96d8..c56ccfc 100644 --- a/OneDriveSDK/packages.config +++ b/OneDriveSDK/packages.config @@ -1,9 +1,8 @@  - + - - - - + + + \ No newline at end of file From 485b2a7975937ff48ad3fd1ca8bc4ac27efb3413 Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Mon, 18 May 2015 10:58:13 -0700 Subject: [PATCH 02/13] Add select to ViewChangesOptions --- OneDriveSDK/CommandOptions/ViewChangesOptions.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/OneDriveSDK/CommandOptions/ViewChangesOptions.cs b/OneDriveSDK/CommandOptions/ViewChangesOptions.cs index 0f55104..b923d25 100644 --- a/OneDriveSDK/CommandOptions/ViewChangesOptions.cs +++ b/OneDriveSDK/CommandOptions/ViewChangesOptions.cs @@ -18,6 +18,15 @@ public int? PageSize set { SetValueForQueryString(ApiConstants.PageSizeQueryParameterKey, value.ToString()); } } + /// + /// Select properties on the expanded objects + /// + public string Select + { + get { return ValueForQueryString(ApiConstants.SelectQueryParameterKey); } + set { SetValueForQueryString(ApiConstants.SelectQueryParameterKey, value); } + } + public static ViewChangesOptions Default { get { return new ViewChangesOptions(); } From f9d856cf898c47fdd1dd3e8ee8c151ecada80179 Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Mon, 18 May 2015 19:38:32 -0700 Subject: [PATCH 03/13] Fix exception if item doesn't have a path --- .../Extensions/ItemExtensionMethods.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/OneDriveSDK/Extensions/ItemExtensionMethods.cs b/OneDriveSDK/Extensions/ItemExtensionMethods.cs index 5a48f9f..c8d1d6c 100644 --- a/OneDriveSDK/Extensions/ItemExtensionMethods.cs +++ b/OneDriveSDK/Extensions/ItemExtensionMethods.cs @@ -99,19 +99,25 @@ public static string Path(this ODItem item, bool includeApiRoot = false) { if (!includeApiRoot) { - string userPath = item.ParentReference.Path.Split(new char[] { ':' })[1]; - if (null != userPath && !userPath.EndsWith("/")) - userPath = string.Concat(userPath, "/"); - return "/" + userPath + item.Name; + if (!string.IsNullOrEmpty(item.ParentReference.Path)) + { + string userPath = item.ParentReference.Path.Split(new char[] { ':' })[1]; + if (null != userPath && !userPath.EndsWith("/")) + userPath = string.Concat(userPath, "/"); + return "/" + userPath + item.Name; + } } var parentPath = item.ParentReference.Path; - if (null != parentPath && !parentPath.EndsWith("/")) + if (!string.IsNullOrEmpty(parentPath)) { - parentPath = string.Concat(parentPath, "/"); - } + if (null != parentPath && !parentPath.EndsWith("/")) + { + parentPath = string.Concat(parentPath, "/"); + } - return parentPath + item.Name; + return parentPath + item.Name; + } } return null; From 5097572b6c6f1b8575b16345fe64469aa00e7822 Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Mon, 18 May 2015 19:38:58 -0700 Subject: [PATCH 04/13] Add automatic retry after 503 error w/ backoff --- OneDriveSDK/Http/BackoffHelper.cs | 60 +++++++++++++++++++++++++++ OneDriveSDK/Http/WrappedHttpClient.cs | 15 +++++-- 2 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 OneDriveSDK/Http/BackoffHelper.cs diff --git a/OneDriveSDK/Http/BackoffHelper.cs b/OneDriveSDK/Http/BackoffHelper.cs new file mode 100644 index 0000000..899026a --- /dev/null +++ b/OneDriveSDK/Http/BackoffHelper.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading.Tasks; + +namespace OneDrive +{ + public class BackoffHelper + { + public int MaximumTimeMilliseconds { get; set; } + + public int BaseTimeMilliseconds { get; set; } + + private readonly Random _random; + + public BackoffHelper() + { + MaximumTimeMilliseconds = 5000; + BaseTimeMilliseconds = 100; + _random = new Random(); + } + + /// + /// Implements the full jitter backoff algorithm as defined here: http://www.awsarchitectureblog.com/2015/03/backoff.html + /// + /// A task that completes after the duration of the delay. + /// The number of times an error has occured for this particular command / session. + public async Task FullJitterBackoffDelay(int errorCount) + { + double expectedBackoffTime = Math.Min(MaximumTimeMilliseconds, + BaseTimeMilliseconds * Math.Pow(2, errorCount)); + + var sleepDuration = Between(_random, 0, (int)expectedBackoffTime); + + //System.Diagnostics.Debug.WriteLine("Waiting for: {0} milliseconds", sleepDuration); + await Task.Delay(sleepDuration); + } + + private static int Between(Random rnd, int lowNumber, int highNumber) + { + var dbl = rnd.NextDouble(); + int range = highNumber - lowNumber; + double selectedValue = (dbl * range); + return (int)(lowNumber + selectedValue); + } + + + private static BackoffHelper _defaultInstance = null; + public static BackoffHelper Default + { + get + { + if (_defaultInstance == null) + { + _defaultInstance = new BackoffHelper(); + } + return _defaultInstance; + } + } + } +} + diff --git a/OneDriveSDK/Http/WrappedHttpClient.cs b/OneDriveSDK/Http/WrappedHttpClient.cs index 17e70ef..e24d899 100644 --- a/OneDriveSDK/Http/WrappedHttpClient.cs +++ b/OneDriveSDK/Http/WrappedHttpClient.cs @@ -35,6 +35,7 @@ public WrappedHttpClientRequest(Uri uri) public string Accept { get; set; } public Dictionary Headers {get; private set;} private MemoryStream RequestBodyStream {get;set;} + private int RetryCount { get; set; } public async Task GetRequestStreamAsync() { @@ -45,11 +46,19 @@ public async Task GetRequestStreamAsync() public async Task GetResponseAsync() { // Build the StreamContent if necessary - - var client = new HttpClient(Handler); - var message = BuildMessage(); + HttpClient client = new HttpClient(Handler); + HttpRequestMessage message = BuildMessage(); var response = await client.SendAsync(message); + if (response.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable) + { + // We should retry again + if (RetryCount++ < 4) + { + await BackoffHelper.Default.FullJitterBackoffDelay(RetryCount); + return await GetResponseAsync(); + } + } return new WrappedHttpClientResponse(response); } From 0f779a459efca8f8507b9aae2ac0a9917f46ebd9 Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Mon, 18 May 2015 19:39:14 -0700 Subject: [PATCH 05/13] Add simple auth support for just access tokens --- OneDriveSDK/ODConnection.cs | 7 ++++ OneDriveSDK/OneDriveSDK.csproj | 2 + OneDriveSDK/SimpleAuthenticationInfo.cs | 51 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 OneDriveSDK/SimpleAuthenticationInfo.cs diff --git a/OneDriveSDK/ODConnection.cs b/OneDriveSDK/ODConnection.cs index 0229c6c..e03cf8a 100644 --- a/OneDriveSDK/ODConnection.cs +++ b/OneDriveSDK/ODConnection.cs @@ -28,6 +28,13 @@ public ODConnection(string rootUrl, IAuthenticationInfo auth) Authentication = auth; } + public ODConnection(string rootUrl, string accessToken) + { + HttpRequestFactory = new Http.HttpFactoryDefault(); + RootUrl = rootUrl; + Authentication = new SimpleAuthenticationInfo { AccessToken = accessToken }; + } + #endregion #region Helper Methods diff --git a/OneDriveSDK/OneDriveSDK.csproj b/OneDriveSDK/OneDriveSDK.csproj index 44df23b..3d4806b 100644 --- a/OneDriveSDK/OneDriveSDK.csproj +++ b/OneDriveSDK/OneDriveSDK.csproj @@ -65,6 +65,7 @@ + @@ -98,6 +99,7 @@ + diff --git a/OneDriveSDK/SimpleAuthenticationInfo.cs b/OneDriveSDK/SimpleAuthenticationInfo.cs new file mode 100644 index 0000000..cf5f6ce --- /dev/null +++ b/OneDriveSDK/SimpleAuthenticationInfo.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OneDrive +{ + public class SimpleAuthenticationInfo : IAuthenticationInfo + { + public SimpleAuthenticationInfo() + { + TokenType = "Bearer"; + TokenExpiration = DateTimeOffset.MaxValue; + } + + public string AccessToken + { + get; + set; + } + + public string RefreshToken + { + get; + set; + } + + public string TokenType + { + get; + set; + } + + public DateTimeOffset TokenExpiration + { + get; + set; + } + + public Task RefreshAccessTokenAsync() + { + throw new NotSupportedException(); + } + + public string AuthorizationHeaderValue + { + get { return string.Format("{0} {1}", TokenType, AccessToken); } + } + } +} From 3f120b8006b6227c3f21953e8122b6bd0d6111f3 Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Mon, 18 May 2015 19:49:52 -0700 Subject: [PATCH 06/13] Fix bugs in calculating some paths --- .../Extensions/ItemExtensionMethods.cs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/OneDriveSDK/Extensions/ItemExtensionMethods.cs b/OneDriveSDK/Extensions/ItemExtensionMethods.cs index c8d1d6c..ae4b6c6 100644 --- a/OneDriveSDK/Extensions/ItemExtensionMethods.cs +++ b/OneDriveSDK/Extensions/ItemExtensionMethods.cs @@ -89,34 +89,33 @@ public static string JsonString(this ODDataModel item) } /// - /// Returns the Path for an item. + /// Returns the Path for an item. Returns null if a path is not available for the item. /// /// /// public static string Path(this ODItem item, bool includeApiRoot = false) { - if (null != item.ParentReference) + + if (null != item.ParentReference && null != item.ParentReference.Path) { + var decodedPath = Uri.UnescapeDataString(item.ParentReference.Path); + if (!includeApiRoot) { - if (!string.IsNullOrEmpty(item.ParentReference.Path)) + string userPath = decodedPath.Split(new char[] { ':' })[1]; + if (null != userPath && userPath.Length > 0 && !userPath.EndsWith("/")) { - string userPath = item.ParentReference.Path.Split(new char[] { ':' })[1]; - if (null != userPath && !userPath.EndsWith("/")) - userPath = string.Concat(userPath, "/"); - return "/" + userPath + item.Name; + userPath = string.Concat(userPath, "/"); } + return "/" + userPath + item.Name; } - - var parentPath = item.ParentReference.Path; - if (!string.IsNullOrEmpty(parentPath)) + else { - if (null != parentPath && !parentPath.EndsWith("/")) + if (!decodedPath.EndsWith("/")) { - parentPath = string.Concat(parentPath, "/"); + decodedPath = string.Concat(decodedPath, "/"); } - - return parentPath + item.Name; + return decodedPath + item.Name; } } From 68f64717d5649b9ae740b70f272cb80c7a3c8416 Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Mon, 18 May 2015 19:50:05 -0700 Subject: [PATCH 07/13] Fix bug where uploading to a known filename didn't work. --- OneDriveSDK/ODConnection.public.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OneDriveSDK/ODConnection.public.cs b/OneDriveSDK/ODConnection.public.cs index 9edc15d..162379d 100644 --- a/OneDriveSDK/ODConnection.public.cs +++ b/OneDriveSDK/ODConnection.public.cs @@ -131,7 +131,7 @@ public async Task PutContentsAsync(ODItemReference itemReference, Stream throw new ODException("Couldn't get length of sourceFileStream."); } - Uri serviceUri = UriForItemReference(itemReference); + Uri serviceUri = UriForItemReference(itemReference, ApiConstants.ContentRelationshipName); return await UploadToUrl(sourceFileStream, options, localItemSize, serviceUri); } From aee0253a782efb3df37561d40b0059c75e9047fe Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Mon, 18 May 2015 20:03:02 -0700 Subject: [PATCH 08/13] Enable opening a folder by path to test special characters. Path encoded. --- OneDriveApiExplorer/FormBrowser.Designer.cs | 16 ++++++++--- OneDriveApiExplorer/FormBrowser.cs | 27 ++++++++++++++++++- .../Extensions/ItemExtensionMethods.cs | 3 ++- OneDriveSDK/ODConnection.cs | 2 +- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/OneDriveApiExplorer/FormBrowser.Designer.cs b/OneDriveApiExplorer/FormBrowser.Designer.cs index 2555afe..bd5a377 100644 --- a/OneDriveApiExplorer/FormBrowser.Designer.cs +++ b/OneDriveApiExplorer/FormBrowser.Designer.cs @@ -61,6 +61,7 @@ private void InitializeComponent() this.getChangesHereToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.searchToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.getDriveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openItemByPathToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); this.splitContainer1.Panel1.SuspendLayout(); this.splitContainer1.Panel2.SuspendLayout(); @@ -179,6 +180,7 @@ private void InitializeComponent() this.toolStripMenuItem3, this.createFolderToolStripMenuItem, this.saveSelectedFileToolStripMenuItem, + this.openItemByPathToolStripMenuItem, this.toolStripMenuItem4, this.renameSelectedItemToolStripMenuItem, this.deleteSelectedItemToolStripMenuItem, @@ -342,24 +344,31 @@ private void InitializeComponent() // getChangesHereToolStripMenuItem // this.getChangesHereToolStripMenuItem.Name = "getChangesHereToolStripMenuItem"; - this.getChangesHereToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.getChangesHereToolStripMenuItem.Size = new System.Drawing.Size(150, 22); this.getChangesHereToolStripMenuItem.Text = "Get Changes..."; this.getChangesHereToolStripMenuItem.Click += new System.EventHandler(this.getChangesHereToolStripMenuItem_Click); // // searchToolStripMenuItem // this.searchToolStripMenuItem.Name = "searchToolStripMenuItem"; - this.searchToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.searchToolStripMenuItem.Size = new System.Drawing.Size(150, 22); this.searchToolStripMenuItem.Text = "Search..."; this.searchToolStripMenuItem.Click += new System.EventHandler(this.searchToolStripMenuItem_Click); // // getDriveToolStripMenuItem // this.getDriveToolStripMenuItem.Name = "getDriveToolStripMenuItem"; - this.getDriveToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.getDriveToolStripMenuItem.Size = new System.Drawing.Size(150, 22); this.getDriveToolStripMenuItem.Text = "Get Drive..."; this.getDriveToolStripMenuItem.Click += new System.EventHandler(this.getDriveToolStripMenuItem_Click); // + // openItemByPathToolStripMenuItem + // + this.openItemByPathToolStripMenuItem.Name = "openItemByPathToolStripMenuItem"; + this.openItemByPathToolStripMenuItem.Size = new System.Drawing.Size(214, 22); + this.openItemByPathToolStripMenuItem.Text = "Open item by path"; + this.openItemByPathToolStripMenuItem.Click += new System.EventHandler(this.openItemByPathToolStripMenuItem_Click); + // // FormBrowser // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -420,6 +429,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem largeFileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem renameSelectedItemToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem getDriveToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem openItemByPathToolStripMenuItem; } } diff --git a/OneDriveApiExplorer/FormBrowser.cs b/OneDriveApiExplorer/FormBrowser.cs index 642e81d..e4819ce 100644 --- a/OneDriveApiExplorer/FormBrowser.cs +++ b/OneDriveApiExplorer/FormBrowser.cs @@ -35,13 +35,19 @@ private async Task LoadFolderFromId(string id) { if (null == Connection) return; + ODItemReference item = new ODItemReference { Id = id }; + await LoadFolderFromReference(item); + } + + private async Task LoadFolderFromReference(ODItemReference item) + { // Update the UI for loading something new ShowWork(true); LoadChildren(null); // Clear the current folder view try { - ODItemReference item = new ODItemReference { Id = id }; + var selectedItem = await Connection.GetItemAsync(item, ItemRetrievalOptions.DefaultWithChildrenThumbnails); ProcessFolder(selectedItem); } @@ -677,6 +683,25 @@ private async void getDriveToolStripMenuItem_Click(object sender, EventArgs e) display.Show(); } + + private async void openItemByPathToolStripMenuItem_Click(object sender, EventArgs e) + { + if (null == Connection) return; + + var currentFolder = this.CurrentFolder; + var selectedItem = this.SelectedItem; + if (null == selectedItem || null == currentFolder) return; + + string pathToItem = selectedItem.Path(false); + if (null == pathToItem) + { + pathToItem = currentFolder.Path(false) + "/" + selectedItem.Name; + } + + var itemRef = ODConnection.ItemReferenceForDrivePath(pathToItem); + + await LoadFolderFromReference(itemRef); + } } } diff --git a/OneDriveSDK/Extensions/ItemExtensionMethods.cs b/OneDriveSDK/Extensions/ItemExtensionMethods.cs index ae4b6c6..231ac68 100644 --- a/OneDriveSDK/Extensions/ItemExtensionMethods.cs +++ b/OneDriveSDK/Extensions/ItemExtensionMethods.cs @@ -107,7 +107,8 @@ public static string Path(this ODItem item, bool includeApiRoot = false) { userPath = string.Concat(userPath, "/"); } - return "/" + userPath + item.Name; + + return (!userPath.StartsWith("/") ? "/" : "") + userPath + item.Name; } else { diff --git a/OneDriveSDK/ODConnection.cs b/OneDriveSDK/ODConnection.cs index e03cf8a..1432379 100644 --- a/OneDriveSDK/ODConnection.cs +++ b/OneDriveSDK/ODConnection.cs @@ -262,7 +262,7 @@ private Uri UriForItemReference(ODItemReference itemReference, string navigation if (!itemReference.Path.StartsWith("/drive", StringComparison.Ordinal)) throw new ArgumentException("Invalid ODItemReference: Path doesn't start with \"/drive\" or \"/drives\"."); - url.Append(itemReference.Path); + url.Append(Uri.EscapeUriString(itemReference.Path)); if (itemReference.Path.OccurrencesOfCharacter(':') == 1) { // Make sure we terminate the path escape so we can add a navigation property if necessary From 670a211fdcd60dcab7ca6538547024d12c07ecac Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Tue, 19 May 2015 20:58:26 -0700 Subject: [PATCH 09/13] Enable gzip compression on responses --- OneDriveSDK/Http/WrappedHttpClient.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/OneDriveSDK/Http/WrappedHttpClient.cs b/OneDriveSDK/Http/WrappedHttpClient.cs index e24d899..a9030de 100644 --- a/OneDriveSDK/Http/WrappedHttpClient.cs +++ b/OneDriveSDK/Http/WrappedHttpClient.cs @@ -12,13 +12,19 @@ internal class WrappedHttpClientRequest : Http.IHttpRequest private static readonly HttpClientHandler Handler; private HttpClient Client { get; set; } + public static readonly bool ResponseCompressionEnabled = true; + static WrappedHttpClientRequest() { Handler = new HttpClientHandler { AllowAutoRedirect = false, - //AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate, UseCookies = false }; + + if (ResponseCompressionEnabled) + { + Handler.AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate; + } } public WrappedHttpClientRequest(Uri uri) @@ -96,6 +102,11 @@ private HttpRequestMessage BuildMessage() message.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(Accept)); } + if (ResponseCompressionEnabled) + { + message.Headers.TryAddWithoutValidation("Accept-Encoding", "gzip, deflate"); + } + message.RequestUri = Uri; return message; } From a1c533b01e44fedb8f51fc653a09fd4d3d03df0b Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Tue, 19 May 2015 20:59:47 -0700 Subject: [PATCH 10/13] Add the PutItemAsync method --- OneDriveSDK/ODConnection.public.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/OneDriveSDK/ODConnection.public.cs b/OneDriveSDK/ODConnection.public.cs index 162379d..34dbf6b 100644 --- a/OneDriveSDK/ODConnection.public.cs +++ b/OneDriveSDK/ODConnection.public.cs @@ -135,6 +135,22 @@ public async Task PutContentsAsync(ODItemReference itemReference, Stream return await UploadToUrl(sourceFileStream, options, localItemSize, serviceUri); } + public async Task PutItemAsync(ODItemReference itemReference, ODItem itemProperties) + { + if (!itemReference.IsValid()) + throw new ArgumentException("ItemReference was invalid. Requires either an ID or Path"); + + Uri serviceUri = UriForItemReference(itemReference); + var request = await CreateHttpRequestAsync(serviceUri, ApiConstants.HttpPut); + request.ContentType = ApiConstants.ContentTypeJson; + + await SerializeObjectToRequestBody(itemProperties, request); + + var item = await DataModelForRequest(request); + return item; + + } + /// /// Upload a new file to a parent folder item. /// @@ -168,6 +184,7 @@ public async Task PutNewFileToParentItemAsync(ODItemReference parentItem return await UploadToUrl(sourceFileStream, options, localItemSize, serviceUri); } + /// /// Uploads a file using the resumable fragment upload API, splitting the file into smaller pieces to upload. /// From d881c93778286dc54345e187434137f33fd980f2 Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Tue, 19 May 2015 21:00:27 -0700 Subject: [PATCH 11/13] Provide a way to do ItemRef + Path addressing --- .../DataType/ODExtendedItemReference.cs | 24 +++++++++++++++++++ .../Extensions/GenericExtensionMethods.cs | 13 ++++++++++ .../Extensions/ItemExtensionMethods.cs | 6 +++++ OneDriveSDK/ODConnection.cs | 19 +++++++++++---- OneDriveSDK/OneDriveSDK.csproj | 1 + 5 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 OneDriveSDK/DataType/ODExtendedItemReference.cs diff --git a/OneDriveSDK/DataType/ODExtendedItemReference.cs b/OneDriveSDK/DataType/ODExtendedItemReference.cs new file mode 100644 index 0000000..d0fad25 --- /dev/null +++ b/OneDriveSDK/DataType/ODExtendedItemReference.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace OneDrive +{ + public class ODExtendedItemReference : ODItemReference + { + public ODExtendedItemReference(ODItemReference itemRef) + { + this.DriveId = itemRef.DriveId; + this.Id = itemRef.Id; + this.Path = itemRef.Path; + } + + /// + /// AdditionalPath enables you to address an item by ID + AdditionalPath. When this reference is converted into + /// a URL, the value of AdditionalPath is appended to the resolved item. + /// + public string AdditionalPath { get; set; } + } +} diff --git a/OneDriveSDK/Extensions/GenericExtensionMethods.cs b/OneDriveSDK/Extensions/GenericExtensionMethods.cs index 741d551..3fab285 100644 --- a/OneDriveSDK/Extensions/GenericExtensionMethods.cs +++ b/OneDriveSDK/Extensions/GenericExtensionMethods.cs @@ -40,5 +40,18 @@ public static bool IsSuccess(this HttpStatusCode code) else return false; } + + /// + /// Ensures that a path component has a leading path seperator "foo/bar" => "/foo/bar" + /// + /// + /// + public static string EnsureLeadingPathSeperator(this string path) + { + if (path.StartsWith("/")) + return path; + else + return "/" + path; + } } } diff --git a/OneDriveSDK/Extensions/ItemExtensionMethods.cs b/OneDriveSDK/Extensions/ItemExtensionMethods.cs index 231ac68..b7e44ad 100644 --- a/OneDriveSDK/Extensions/ItemExtensionMethods.cs +++ b/OneDriveSDK/Extensions/ItemExtensionMethods.cs @@ -133,5 +133,11 @@ public static string Path(this ODItem item, bool includeApiRoot = false) { return await connection.DownloadStreamForItemAsync(item.ItemReference(), downloadOptions); } + + + public static ODItemReference AddPathComponent(this ODItemReference itemRef, string pathComponent) + { + return new ODExtendedItemReference(itemRef) { AdditionalPath = pathComponent }; + } } } diff --git a/OneDriveSDK/ODConnection.cs b/OneDriveSDK/ODConnection.cs index 1432379..4fb376a 100644 --- a/OneDriveSDK/ODConnection.cs +++ b/OneDriveSDK/ODConnection.cs @@ -244,18 +244,21 @@ private Uri UriForItemReference(ODItemReference itemReference, string navigation // RootUrl = "https://api.onedrive.com/v1.0" StringBuilder url = new StringBuilder(RootUrl); + var extendedReference = itemReference as ODExtendedItemReference; + + if (!string.IsNullOrEmpty(itemReference.Id)) { - if (!string.IsNullOrEmpty(itemReference.DriveId)) - { + if (!string.IsNullOrEmpty(itemReference.DriveId)) url.AppendFormat("/drives/{0}", itemReference.DriveId); - } else - { url.AppendFormat("/drive"); - } url.AppendFormat("/items/{0}", itemReference.Id); + if (null != extendedReference && !string.IsNullOrEmpty(extendedReference.AdditionalPath)) + { + url.AppendFormat(":{0}:", extendedReference.AdditionalPath.EnsureLeadingPathSeperator()); + } } else if (!string.IsNullOrEmpty(itemReference.Path)) { @@ -263,6 +266,12 @@ private Uri UriForItemReference(ODItemReference itemReference, string navigation throw new ArgumentException("Invalid ODItemReference: Path doesn't start with \"/drive\" or \"/drives\"."); url.Append(Uri.EscapeUriString(itemReference.Path)); + + if (null != extendedReference && !string.IsNullOrEmpty(extendedReference.AdditionalPath)) + { + url.AppendFormat(extendedReference.AdditionalPath.EnsureLeadingPathSeperator()); + } + if (itemReference.Path.OccurrencesOfCharacter(':') == 1) { // Make sure we terminate the path escape so we can add a navigation property if necessary diff --git a/OneDriveSDK/OneDriveSDK.csproj b/OneDriveSDK/OneDriveSDK.csproj index 3d4806b..ec69736 100644 --- a/OneDriveSDK/OneDriveSDK.csproj +++ b/OneDriveSDK/OneDriveSDK.csproj @@ -47,6 +47,7 @@ + From 7c69ca28f9593b2c09eafb74ce124b44d9b9e169 Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Tue, 19 May 2015 21:00:41 -0700 Subject: [PATCH 12/13] Exclude serializing default values for the folder facet --- OneDriveSDK/Facets/FolderFacet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OneDriveSDK/Facets/FolderFacet.cs b/OneDriveSDK/Facets/FolderFacet.cs index e0dad52..0bc156f 100644 --- a/OneDriveSDK/Facets/FolderFacet.cs +++ b/OneDriveSDK/Facets/FolderFacet.cs @@ -5,7 +5,7 @@ namespace OneDrive.Facets { public class FolderFacet { - [JsonProperty("childCount")] + [JsonProperty("childCount", DefaultValueHandling=DefaultValueHandling.Ignore)] public long ChildCount { get; set; } } } From 2b80c868d6b84e32287ccd1477d5dcc7affc3bb0 Mon Sep 17 00:00:00 2001 From: Ryan Gregg Date: Tue, 19 May 2015 21:01:02 -0700 Subject: [PATCH 13/13] Enable path addressing scenarios --- OneDriveApiExplorer/App.config | 12 ++++++++++-- OneDriveApiExplorer/FormBrowser.cs | 2 ++ OneDriveApiExplorer/OneDriveApiExplorer.csproj | 10 ++++++++++ OneDriveApiExplorer/packages.config | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/OneDriveApiExplorer/App.config b/OneDriveApiExplorer/App.config index 799acb3..86a39c6 100644 --- a/OneDriveApiExplorer/App.config +++ b/OneDriveApiExplorer/App.config @@ -1,7 +1,7 @@ - + - +
@@ -15,4 +15,12 @@ + + + + + + + + \ No newline at end of file diff --git a/OneDriveApiExplorer/FormBrowser.cs b/OneDriveApiExplorer/FormBrowser.cs index e4819ce..7731ad5 100644 --- a/OneDriveApiExplorer/FormBrowser.cs +++ b/OneDriveApiExplorer/FormBrowser.cs @@ -55,6 +55,8 @@ private async Task LoadFolderFromReference(ODItemReference item) { PresentOneDriveException(exception); } + + FixBreadCrumbForCurrentFolder(this.CurrentFolder); ShowWork(false); } diff --git a/OneDriveApiExplorer/OneDriveApiExplorer.csproj b/OneDriveApiExplorer/OneDriveApiExplorer.csproj index 6e56d27..a9dcec2 100644 --- a/OneDriveApiExplorer/OneDriveApiExplorer.csproj +++ b/OneDriveApiExplorer/OneDriveApiExplorer.csproj @@ -71,6 +71,16 @@ + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll + True + + diff --git a/OneDriveApiExplorer/packages.config b/OneDriveApiExplorer/packages.config index f55cfaa..8c8430a 100644 --- a/OneDriveApiExplorer/packages.config +++ b/OneDriveApiExplorer/packages.config @@ -3,6 +3,7 @@ + \ No newline at end of file