Skip to content

Commit 7dfeae2

Browse files
author
Qiming Yuan
committed
Increase timeout for long poll properly dispose http client.
1 parent 179644e commit 7dfeae2

File tree

7 files changed

+211
-70
lines changed

7 files changed

+211
-70
lines changed

Dropbox.Api.Tests/DropboxApiTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace Dropbox.Api.Tests
1717
using Microsoft.VisualStudio.TestTools.UnitTesting;
1818

1919
using Dropbox.Api.Auth;
20+
using Dropbox.Api.Users;
2021

2122
/// <summary>
2223
/// The test class for Dropbox API.
@@ -363,5 +364,29 @@ public async Task TestUserAgentUserSupplied()
363364
await client.Users.GetCurrentAccountAsync();
364365
Assert.IsTrue(lastRequest.Headers.UserAgent.ToString().Contains(userAgent));
365366
}
367+
368+
/// <summary>
369+
/// Test cancel request of Dispose DropboxClient
370+
/// </summary>
371+
/// <returns></returns>
372+
[TestMethod]
373+
public async Task TestDropboxClientDispose()
374+
{
375+
var canceled = false;
376+
Task<FullAccount> task;
377+
using (var client = new DropboxClient(UserAccessToken))
378+
{
379+
task = client.Users.GetCurrentAccountAsync();
380+
}
381+
try
382+
{
383+
await task;
384+
}
385+
catch (TaskCanceledException)
386+
{
387+
canceled = true;
388+
}
389+
Assert.IsTrue(canceled);
390+
}
366391
}
367392
}

Dropbox.Api/DropboxAppClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public sealed partial class DropboxAppClient
2020
/// <para>Initializes the routes.</para>
2121
/// </summary>
2222
/// <returns>The transport.</returns>
23-
private void InitializeRoutes(ITransport transport)
23+
internal override void InitializeRoutes(ITransport transport)
2424
{
2525
this.Auth = new AuthAppRoutes(transport);
2626
}

Dropbox.Api/DropboxClient.common.cs

Lines changed: 96 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ namespace Dropbox.Api
1111
using System.Net.Http;
1212
using System.Text;
1313

14+
using Dropbox.Api.Stone;
15+
1416
/// <summary>
1517
/// The class which contains all configurations for Dropbox client.
1618
/// </summary>
@@ -39,21 +41,9 @@ public DropboxClientConfig(string userAgent)
3941
/// <param name="userAgent">The user agent to use when making requests.</param>
4042
/// <param name="maxRetriesOnError">The max number retries on error.</param>
4143
public DropboxClientConfig(string userAgent, int maxRetriesOnError)
42-
: this(userAgent, maxRetriesOnError, null)
43-
{
44-
}
45-
46-
/// <summary>
47-
/// Initializes a new instance of the <see cref="DropboxClientConfig"/> class.
48-
/// </summary>
49-
/// <param name="userAgent">The user agent to use when making requests.</param>
50-
/// <param name="maxRetriesOnError">The max number retries on error.</param>
51-
/// <param name="httpClient">The custom http client.</param>
52-
internal DropboxClientConfig(string userAgent, int maxRetriesOnError, HttpClient httpClient)
5344
{
5445
this.UserAgent = userAgent;
5546
this.MaxRetriesOnError = maxRetriesOnError;
56-
this.HttpClient = httpClient;
5747
}
5848

5949
/// <summary>
@@ -75,12 +65,67 @@ internal DropboxClientConfig(string userAgent, int maxRetriesOnError, HttpClient
7565
/// Gets or sets the custom http client. If not set, a default http client will be created.
7666
/// </summary>
7767
public HttpClient HttpClient { get; set; }
68+
69+
/// <summary>
70+
/// Gets or sets the custom http client for long poll request. If not set, a default
71+
/// http client with a longer timeout (480 seconds) will be created.
72+
/// </summary>
73+
public HttpClient LongPollHttpClient { get; set; }
74+
}
75+
76+
/// <summary>
77+
/// The base class for all Dropbox clients.
78+
/// </summary>
79+
public abstract class DropboxClientBase : IDisposable
80+
{
81+
/// <summary>
82+
/// The transport.
83+
/// </summary>
84+
private readonly ITransport transport;
85+
86+
/// <summary>
87+
/// Initializes a new instance of the <see cref="DropboxClientBase"/> class.
88+
/// </summary>
89+
/// <param name="transport">The transport.</param>
90+
internal DropboxClientBase(ITransport transport)
91+
{
92+
this.transport = transport;
93+
this.InitializeRoutes(this.transport);
94+
}
95+
96+
/// <summary>
97+
/// Initializes routes.
98+
/// </summary>
99+
/// <param name="transport"></param>
100+
internal abstract void InitializeRoutes(ITransport transport);
101+
102+
/// <summary>
103+
/// The public dispose.
104+
/// </summary>
105+
public void Dispose()
106+
{
107+
Dispose(true);
108+
GC.SuppressFinalize(this);
109+
}
110+
111+
/// <summary>
112+
/// The actual disposing logic.
113+
/// </summary>
114+
/// <param name="disposing">If is disposing.</param>
115+
protected virtual void Dispose(bool disposing)
116+
{
117+
if (disposing)
118+
{
119+
// ITransport is safe for multiple disposal.
120+
this.transport.Dispose();
121+
}
122+
}
78123
}
79124

80125
/// <summary>
81126
/// The client which contains endpoints which perform user-level actions.
82127
/// </summary>
83-
public sealed partial class DropboxClient : IDisposable
128+
public sealed partial class DropboxClient : DropboxClientBase
84129
{
85130
/// <summary>
86131
/// Initializes a new instance of the <see cref="T:Dropbox.Api.DropboxClient"/> class.
@@ -108,7 +153,7 @@ public DropboxClient(string oauth2AccessToken, string userAgent)
108153
/// <param name="oauth2AccessToken">The oauth2 access token for making client requests.</param>
109154
/// <param name="config">The <see cref="DropboxClientConfig"/>.</param>
110155
public DropboxClient(string oauth2AccessToken, DropboxClientConfig config)
111-
: this(new DropboxRequestHandlerOptions(oauth2AccessToken, config.MaxRetriesOnError, config.UserAgent, httpClient: config.HttpClient))
156+
: this(new DropboxRequestHandlerOptions(config, oauth2AccessToken))
112157
{
113158
if (oauth2AccessToken == null)
114159
{
@@ -123,22 +168,15 @@ public DropboxClient(string oauth2AccessToken, DropboxClientConfig config)
123168
/// <param name="selectUser">The member id of the selected user. If provided together with
124169
/// a team access token, actions will be performed on this this user's Dropbox.</param>
125170
internal DropboxClient(DropboxRequestHandlerOptions options, string selectUser = null)
126-
{
127-
this.InitializeRoutes(new DropboxRequestHandler(options, selectUser));
128-
}
129-
130-
/// <summary>
131-
/// Dummy dispose method.
132-
/// </summary>
133-
public void Dispose()
171+
: base(new DropboxRequestHandler(options, selectUser))
134172
{
135173
}
136174
}
137175

138176
/// <summary>
139177
/// The client which contains endpoints which perform app-auth actions.
140178
/// </summary>
141-
public sealed partial class DropboxAppClient
179+
public sealed partial class DropboxAppClient : DropboxClientBase
142180
{
143181
/// <summary>
144182
/// Initializes a new instance of the <see cref="T:Dropbox.Api.DropboxAppClient"/> class.
@@ -152,30 +190,23 @@ public DropboxAppClient(string appKey, string appSecret)
152190

153191

154192
/// <summary>
155-
/// Initializes a new instance of the <see cref="T:Dropbox.Api.DropboxClient"/> class.
193+
/// Initializes a new instance of the <see cref="T:Dropbox.Api.DropboxAppClient"/> class.
156194
/// </summary>
157195
/// <param name="appKey">The Dropbox app key (e.g. consumer key in OAuth).</param>
158196
/// <param name="appSecret">The Dropbox app secret (e.g. consumer secret in OAuth).</param>
159197
/// <param name="config">The <see cref="DropboxClientConfig"/>.</param>
160198
public DropboxAppClient(string appKey, string appSecret, DropboxClientConfig config)
199+
: this(new DropboxRequestHandlerOptions(config, GetBasicAuthHeader(appKey, appSecret)))
161200
{
162-
if (appKey == null)
163-
{
164-
throw new ArgumentNullException("appKey");
165-
}
166-
167-
if (appSecret == null)
168-
{
169-
throw new ArgumentNullException("appSecret");
170-
}
171-
172-
var options = new DropboxRequestHandlerOptions(
173-
GetBasicAuthHeader(appKey, appSecret),
174-
config.MaxRetriesOnError,
175-
config.UserAgent,
176-
httpClient: config.HttpClient);
201+
}
177202

178-
this.InitializeRoutes(new DropboxRequestHandler(options));
203+
/// <summary>
204+
/// Initializes a new instance of the <see cref="T:Dropbox.Api.DropboxAppClient"/> class.
205+
/// </summary>
206+
/// <param name="options">The request handler options.</param>
207+
private DropboxAppClient(DropboxRequestHandlerOptions options)
208+
: base(new DropboxRequestHandler(options))
209+
{
179210
}
180211

181212
/// <summary>
@@ -184,8 +215,18 @@ public DropboxAppClient(string appKey, string appSecret, DropboxClientConfig con
184215
/// <param name="appKey">The app key.</param>
185216
/// <param name="appSecret">The app secret.</param>
186217
/// <returns>The basic auth header.</returns>
187-
private static string GetBasicAuthHeader(string appKey, string appSecret)
218+
private static string GetBasicAuthHeader(string appKey, string appSecret)
188219
{
220+
if (appKey == null)
221+
{
222+
throw new ArgumentNullException("appKey");
223+
}
224+
225+
if (appSecret == null)
226+
{
227+
throw new ArgumentNullException("appSecret");
228+
}
229+
189230
var rawValue = string.Format("{0}:{1}", appKey, appSecret);
190231
return Convert.ToBase64String(Encoding.UTF8.GetBytes(rawValue));
191232
}
@@ -194,7 +235,7 @@ private static string GetBasicAuthHeader(string appKey, string appSecret)
194235
/// <summary>
195236
/// The client which contains endpoints which perform team-level actions.
196237
/// </summary>
197-
public sealed partial class DropboxTeamClient
238+
public sealed partial class DropboxTeamClient : DropboxClientBase
198239
{
199240
/// <summary>
200241
/// The request handler options.
@@ -227,14 +268,22 @@ public DropboxTeamClient(string oauth2AccessToken, string userAgent)
227268
/// <param name="oauth2AccessToken">The oauth2 access token for making client requests.</param>
228269
/// <param name="config">The <see cref="DropboxClientConfig"/>.</param>
229270
public DropboxTeamClient(string oauth2AccessToken, DropboxClientConfig config)
271+
: this(new DropboxRequestHandlerOptions(config, oauth2AccessToken))
230272
{
231273
if (oauth2AccessToken == null)
232274
{
233275
throw new ArgumentNullException("oauth2AccessToken");
234276
}
277+
}
235278

236-
this.options = new DropboxRequestHandlerOptions(oauth2AccessToken, config.MaxRetriesOnError, config.UserAgent, httpClient: config.HttpClient);
237-
this.InitializeRoutes(new DropboxRequestHandler(this.options));
279+
/// <summary>
280+
/// Initializes a new instance of the <see cref="T:Dropbox.Api.DropboxTeamClient"/> class.
281+
/// </summary>
282+
/// <param name="options">The request handler options.</param>
283+
private DropboxTeamClient(DropboxRequestHandlerOptions options)
284+
: base(new DropboxRequestHandler(options))
285+
{
286+
this.options = options;
238287
}
239288

240289
/// <summary>
@@ -277,7 +326,7 @@ internal DropboxException(string requestId, string message = null, Exception inn
277326
public override string ToString()
278327
{
279328
var builder = new StringBuilder(base.ToString());
280-
if (this.requestId != null)
329+
if (this.requestId != null)
281330
{
282331
builder.AppendFormat(CultureInfo.InvariantCulture, "; Request Id: {0}", this.requestId);
283332
}
@@ -387,7 +436,7 @@ internal AccessException(string requestId)
387436
{
388437
}
389438
}
390-
439+
391440
/// <summary>
392441
/// An HTTP Exception that will cause a retry due to transient failure. The SDK will perform
393442
/// a certain number of retries which is configurable in <see cref="DropboxClient"/>. If the client
@@ -459,7 +508,7 @@ internal RateLimitException(string requestId)
459508
/// <summary>
460509
/// Gets the value in second which the client should backoff and retry after.
461510
/// </summary>
462-
public int RetryAfter
511+
public int RetryAfter
463512
{
464513
get { return (int)this.ErrorResponse.RetryAfter; }
465514
}

Dropbox.Api/DropboxClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public sealed partial class DropboxClient
4444
/// <para>Initializes the routes.</para>
4545
/// </summary>
4646
/// <returns>The transport.</returns>
47-
private void InitializeRoutes(ITransport transport)
47+
internal override void InitializeRoutes(ITransport transport)
4848
{
4949
this.Auth = new AuthUserRoutes(transport);
5050
this.Files = new FilesUserRoutes(transport);

0 commit comments

Comments
 (0)