Statistics
| Branch: | Revision:

root / trunk / Pithos.Network / docs / restclient.html @ 1caef52e

History | View | Annotate | Download (17.3 kB)

1
<!DOCTYPE html />
2

    
3
<html>
4
<head>
5
        <title>RestClient.cs</title>
6
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
7
        <link href="focco.css" rel="stylesheet" media="all" type="text/css" />
8
        <script src="prettify.js" type="text/javascript"></script>
9
</head>
10
<body onload="prettyPrint()">
11
        <div id="container">
12
                <div id="background"></div>
13
                        <div id="jump_to">
14
                                Jump To &hellip;
15
                                <div id="jump_wrapper">
16
                                        <div id="jump_page">
17
                                                        <a class="source" href="cloudfilesclient.html">
18
                                                                CloudFilesClient.cs
19
                                                        </a>
20
                                                        <a class="source" href="restclient.html">
21
                                                                RestClient.cs
22
                                                        </a>
23
                                                        <a class="source" href="timeoutretrycondition.html">
24
                                                                TimeoutRetryCondition.cs
25
                                                        </a>
26
                                                        <a class="source" href="properties/assemblyinfo.html">
27
                                                                Properties\AssemblyInfo.cs
28
                                                        </a>
29
                                        </div>
30
                                </div>
31
                        </div>
32
                <table cellpadding="0" cellspacing="0">
33
                        <thead>
34
                                <tr>
35
                                        <th class="docs">
36
                                                <h1>RestClient.cs</h1>
37
                                        </th>
38
                                        <th class="code"></th>
39
                                </tr>
40
                        </thead>
41
                        <tbody>
42
                                        <tr id="section_1">
43
                                                <td class="docs">
44
                                                        <div class="pilwrap">
45
                                                                <a class="pilcrow" href="#section_1">&#182;</a>
46
                                                        </div>
47
                                                        <hr />
48

    
49
<p><copyright file="RestClient.cs" company="Microsoft">
50
TODO: Update copyright text.</p>
51

    
52
<h2></copyright></h2>
53

    
54
                                                </td>
55
                                                <td class="code">
56
                                                        <pre><code class='prettyprint'>
57
using System.Collections.Specialized;
58
using System.Diagnostics;
59
using System.Diagnostics.Contracts;
60
using System.IO;
61
using System.Net;
62
using System.Runtime.Serialization;
63
using System.Threading.Tasks;
64

    
65
namespace Pithos.Network
66
{
67
    using System;
68
    using System.Collections.Generic;
69
    using System.Linq;
70
    using System.Text;
71

    
72
</code></pre>
73
                                                </td>
74
                                        </tr>
75
                                        <tr id="section_2">
76
                                                <td class="docs">
77
                                                        <div class="pilwrap">
78
                                                                <a class="pilcrow" href="#section_2">&#182;</a>
79
                                                        </div>
80
                                                        <p>/ <summary>
81
/ TODO: Update summary.
82
/ </summary></p>
83

    
84
                                                </td>
85
                                                <td class="code">
86
                                                        <pre><code class='prettyprint'>    public class RestClient:WebClient
87
    {
88
        public int Timeout { get; set; }
89

    
90
        public bool TimedOut { get; set; }
91

    
92
        public HttpStatusCode StatusCode { get; private set; }
93

    
94
        public string StatusDescription { get; set; }
95

    
96

    
97
        public int Retries { get; set; }
98

    
99
        private readonly Dictionary&lt;string, string&gt; _parameters=new Dictionary&lt;string, string&gt;();
100
        public Dictionary&lt;string, string&gt; Parameters
101
        {
102
            get { return _parameters; }            
103
        }
104

    
105
        public RestClient():base()
106
        {
107
            
108
        }
109

    
110
       
111
        public RestClient(RestClient other)
112
            : base()
113
        {
114
            CopyHeaders(other);
115
            Timeout = other.Timeout;
116
            Retries = other.Retries;
117
            BaseAddress = other.BaseAddress;             
118

    
119
            foreach (var parameter in other.Parameters)
120
            {
121
                Parameters.Add(parameter.Key,parameter.Value);
122
            }
123

    
124
            this.Proxy = other.Proxy;
125
        }
126

    
127
        protected override WebRequest GetWebRequest(Uri address)
128
        {
129
            TimedOut = false;
130
            var webRequest = base.GetWebRequest(address);
131
            var request = webRequest as HttpWebRequest;
132
            if (IfModifiedSince.HasValue)
133
                request.IfModifiedSince = IfModifiedSince.Value;
134
            request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
135
            if(Timeout&gt;0)
136
                request.Timeout = Timeout;
137
            return request; 
138
        }
139

    
140
        public DateTime? IfModifiedSince { get; set; }
141

    
142
        protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
143
        {
144
            var response = (HttpWebResponse) base.GetWebResponse(request, result);            
145
            StatusCode=response.StatusCode;
146
            StatusDescription=response.StatusDescription;
147
            return response;
148
        }
149

    
150

    
151

    
152
        protected override WebResponse GetWebResponse(WebRequest request)
153
        {
154
            try
155
            {                
156
                var response = (HttpWebResponse)base.GetWebResponse(request);
157
                StatusCode = response.StatusCode;
158
                StatusDescription = response.StatusDescription;
159
                return response;
160
            }
161
            catch (WebException exc)
162
            {
163
                if (exc.Response!=null &amp;&amp; exc.Response.ContentLength &gt; 0)
164
                {
165
                    string content = GetContent(exc.Response);
166
                    Trace.TraceError(content);
167
                }
168
                throw;
169
            }
170
        }
171

    
172
        private static string GetContent(WebResponse webResponse)
173
        {
174
            string content;
175
            using (var stream = webResponse.GetResponseStream())
176
            using (var reader = new StreamReader(stream))
177
            {
178
                content = reader.ReadToEnd();
179
            }
180
            return content;
181
        }
182

    
183
        public string DownloadStringWithRetry(string address,int retries=0)
184
        {
185
            if (address == null)
186
                throw new ArgumentNullException(&quot;address&quot;);
187

    
188
            var actualAddress = GetActualAddress(address);
189

    
190
            TraceStart(&quot;GET&quot;,actualAddress);            
191
            
192
            var actualRetries = (retries == 0) ? Retries : retries;
193
            
194

    
195
            
196
            var task = Retry(() =&gt;
197
            {
198
                var uriString = String.Join(&quot;/&quot;, BaseAddress.TrimEnd(&#39;/&#39;), actualAddress);                
199
                var content = base.DownloadString(uriString);
200

    
201
                if (StatusCode == HttpStatusCode.NoContent)
202
                    return String.Empty;
203
                return content;
204

    
205
            }, actualRetries);
206

    
207
            var result = task.Result;
208
            return result;
209
        }
210

    
211
        public void Head(string address,int retries=0)
212
        {
213
            RetryWithoutContent(address, retries, &quot;HEAD&quot;);
214
        }
215

    
216
        public void PutWithRetry(string address, int retries = 0)
217
        {
218
            RetryWithoutContent(address, retries, &quot;PUT&quot;);
219
        }
220

    
221
        public void DeleteWithRetry(string address,int retries=0)
222
        {
223
            RetryWithoutContent(address, retries, &quot;DELETE&quot;);
224
        }
225

    
226
        public string GetHeaderValue(string headerName)
227
        {
228
            var values=this.ResponseHeaders.GetValues(headerName);
229
            if (values == null)
230
                throw new WebException(String.Format(&quot;The {0}  header is missing&quot;, headerName));
231
            else
232
                return values[0];
233
        }
234

    
235
        private void RetryWithoutContent(string address, int retries, string method)
236
        {
237
            if (address == null)
238
                throw new ArgumentNullException(&quot;address&quot;);
239

    
240
            var actualAddress = GetActualAddress(address);            
241
            var actualRetries = (retries == 0) ? Retries : retries;
242

    
243
            var task = Retry(() =&gt;
244
            {
245
                var uriString = String.Join(&quot;/&quot;,BaseAddress ,actualAddress);
246
                var uri = new Uri(uriString);
247
                var request =  GetWebRequest(uri);
248
                request.Method = method;
249
                if (ResponseHeaders!=null)
250
                    ResponseHeaders.Clear();
251

    
252
                TraceStart(method, uriString);
253

    
254
                var response = (HttpWebResponse)GetWebResponse(request);
255
                StatusCode = response.StatusCode;
256
                StatusDescription = response.StatusDescription;                
257
                
258

    
259
                return 0;
260
            }, actualRetries);
261

    
262
            task.Wait();
263
        }
264
        
265
        /*private string RetryWithContent(string address, int retries, string method)
266
        {
267
            if (address == null)
268
                throw new ArgumentNullException(&quot;address&quot;);
269

    
270
            var actualAddress = GetActualAddress(address);            
271
            var actualRetries = (retries == 0) ? Retries : retries;
272

    
273
            var task = Retry(() =&gt;
274
            {
275
                var uriString = String.Join(&quot;/&quot;,BaseAddress ,actualAddress);
276
                var uri = new Uri(uriString);
277
                
278
                var request =  GetWebRequest(uri);
279
                request.Method = method;                
280

    
281
                if (ResponseHeaders!=null)
282
                    ResponseHeaders.Clear();
283

    
284
                TraceStart(method, uriString);
285

    
286
                var getResponse = request.GetResponseAsync();
287
                
288
                var setStatus= getResponse.ContinueWith(t =&gt;
289
                {
290
                    var response = (HttpWebResponse)t.Result;                    
291
                    StatusCode = response.StatusCode;
292
                    StatusDescription = response.StatusDescription;                
293
                    return response;
294
                });
295

    
296
                var getData = setStatus.ContinueWith(t =&gt;
297
                {
298
                    var response = t.Result;
299
                    return response.GetResponseStream()
300
                        .ReadAllBytesAsync();
301
                }).Unwrap();
302

    
303
                var data = getData.Result;
304
                var content=Encoding.UTF8.GetString(data);
305

    
306
</code></pre>
307
                                                </td>
308
                                        </tr>
309
                                        <tr id="section_3">
310
                                                <td class="docs">
311
                                                        <div class="pilwrap">
312
                                                                <a class="pilcrow" href="#section_3">&#182;</a>
313
                                                        </div>
314
                                                        <pre><code>           var response = (HttpWebResponse)GetWebResponse(request);
315
</code></pre>
316

    
317
                                                </td>
318
                                                <td class="code">
319
                                                        <pre><code class='prettyprint'>                
320
                
321
/*
322
                StatusCode = response.StatusCode;
323
                StatusDescription = response.StatusDescription;                
324
#1#
325
                
326

    
327
                return content;
328
            }, actualRetries);
329

    
330
            return task.Result;
331
        }*/
332

    
333
        private static void TraceStart(string method, string actualAddress)
334
        {
335
            Trace.WriteLine(String.Format(&quot;[{0}] {1} {2}&quot;, method, DateTime.Now, actualAddress));
336
        }
337

    
338
        private string GetActualAddress(string address)
339
        {
340
            if (Parameters.Count == 0)
341
                return address;
342
            var addressBuilder=new StringBuilder(address);            
343

    
344
            bool isFirst = true;
345
            foreach (var parameter in Parameters)
346
            {
347
                if(isFirst)
348
                    addressBuilder.AppendFormat(&quot;?{0}={1}&quot;, parameter.Key, parameter.Value);
349
                else
350
                    addressBuilder.AppendFormat(&quot;&amp;{0}={1}&quot;, parameter.Key, parameter.Value);
351
                isFirst = false;
352
            }
353
            return addressBuilder.ToString();
354
        }
355

    
356
        public string DownloadStringWithRetry(Uri address,int retries=0)
357
        {
358
            if (address == null)
359
                throw new ArgumentNullException(&quot;address&quot;);
360

    
361
            var actualRetries = (retries == 0) ? Retries : retries;            
362
            var task = Retry(() =&gt;
363
            {
364
                var content = base.DownloadString(address);
365

    
366
                if (StatusCode == HttpStatusCode.NoContent)
367
                    return String.Empty;
368
                return content;
369

    
370
            }, actualRetries);
371

    
372
            var result = task.Result;
373
            return result;
374
        }
375

    
376
      
377
</code></pre>
378
                                                </td>
379
                                        </tr>
380
                                        <tr id="section_4">
381
                                                <td class="docs">
382
                                                        <div class="pilwrap">
383
                                                                <a class="pilcrow" href="#section_4">&#182;</a>
384
                                                        </div>
385
                                                        <p>/ <summary>
386
/ Copies headers from another RestClient
387
/ </summary>
388
/ <param name="source">The RestClient from which the headers are copied</param></p>
389

    
390
                                                </td>
391
                                                <td class="code">
392
                                                        <pre><code class='prettyprint'>        public void CopyHeaders(RestClient source)
393
        {
394
            Contract.Requires(source != null, &quot;source can&#39;t be null&quot;);
395
            if (source == null)
396
                throw new ArgumentNullException(&quot;source&quot;, &quot;source can&#39;t be null&quot;);
397
            CopyHeaders(source.Headers,Headers);
398
        }
399
        
400
</code></pre>
401
                                                </td>
402
                                        </tr>
403
                                        <tr id="section_5">
404
                                                <td class="docs">
405
                                                        <div class="pilwrap">
406
                                                                <a class="pilcrow" href="#section_5">&#182;</a>
407
                                                        </div>
408
                                                        <p>/ <summary>
409
/ Copies headers from one header collection to another
410
/ </summary>
411
/ <param name="source">The source collection from which the headers are copied</param>
412
/ <param name="target">The target collection to which the headers are copied</param></p>
413

    
414
                                                </td>
415
                                                <td class="code">
416
                                                        <pre><code class='prettyprint'>        public static void CopyHeaders(WebHeaderCollection source,WebHeaderCollection target)
417
        {
418
            Contract.Requires(source != null, &quot;source can&#39;t be null&quot;);
419
            Contract.Requires(target != null, &quot;target can&#39;t be null&quot;);
420
            if (source == null)
421
                throw new ArgumentNullException(&quot;source&quot;, &quot;source can&#39;t be null&quot;);
422
            if (target == null)
423
                throw new ArgumentNullException(&quot;target&quot;, &quot;target can&#39;t be null&quot;);
424
            for (int i = 0; i &lt; source.Count; i++)
425
            {
426
                target.Add(source.GetKey(i), source[i]);
427
            }            
428
        }
429

    
430
        public void AssertStatusOK(string message)
431
        {
432
            if (StatusCode &gt;= HttpStatusCode.BadRequest)
433
                throw new WebException(String.Format(&quot;{0} with code {1} - {2}&quot;, message, StatusCode, StatusDescription));
434
        }
435

    
436

    
437
        private Task&lt;T&gt; Retry&lt;T&gt;(Func&lt;T&gt; original, int retryCount, TaskCompletionSource&lt;T&gt; tcs = null)
438
        {
439
            if (tcs == null)
440
                tcs = new TaskCompletionSource&lt;T&gt;();
441
            Task.Factory.StartNew(original).ContinueWith(_original =&gt;
442
                {
443
                    if (!_original.IsFaulted)
444
                        tcs.SetFromTask(_original);
445
                    else 
446
                    {
447
                        var e = _original.Exception.InnerException;
448
                        var we = (e as WebException);
449
                        if (we==null)
450
                            tcs.SetException(e);
451
                        else
452
                        {
453
                            var statusCode = GetStatusCode(we);
454

    
455
</code></pre>
456
                                                </td>
457
                                        </tr>
458
                                        <tr id="section_6">
459
                                                <td class="docs">
460
                                                        <div class="pilwrap">
461
                                                                <a class="pilcrow" href="#section_6">&#182;</a>
462
                                                        </div>
463
                                                        <p>Return null for 404</p>
464

    
465
                                                </td>
466
                                                <td class="code">
467
                                                        <pre><code class='prettyprint'>                            if (statusCode == HttpStatusCode.NotFound)
468
                                tcs.SetResult(default(T));
469
</code></pre>
470
                                                </td>
471
                                        </tr>
472
                                        <tr id="section_7">
473
                                                <td class="docs">
474
                                                        <div class="pilwrap">
475
                                                                <a class="pilcrow" href="#section_7">&#182;</a>
476
                                                        </div>
477
                                                        <p>Retry for timeouts and service unavailable</p>
478

    
479
                                                </td>
480
                                                <td class="code">
481
                                                        <pre><code class='prettyprint'>                            else if (we.Status == WebExceptionStatus.Timeout ||
482
                                (we.Status == WebExceptionStatus.ProtocolError &amp;&amp; statusCode == HttpStatusCode.ServiceUnavailable))
483
                            {
484
                                TimedOut = true;
485
                                if (retryCount == 0)
486
                                {
487
                                    Trace.TraceError(&quot;[ERROR] Timed out too many times. {0}\n&quot;, e);
488
                                    tcs.SetException(new RetryException(&quot;Timed out too many times.&quot;, e));                                    
489
                                }
490
                                else
491
                                {
492
                                    Trace.TraceError(
493
                                        &quot;[RETRY] Timed out after {0} ms. Will retry {1} more times\n{2}&quot;, Timeout,
494
                                        retryCount, e);
495
                                    Retry(original, retryCount - 1, tcs);
496
                                }
497
                            }
498
                            else
499
                                tcs.SetException(e);
500
                        }
501
                    };
502
                });
503
            return tcs.Task;
504
        }
505

    
506
        private HttpStatusCode GetStatusCode(WebException we)
507
        {
508
            var statusCode = HttpStatusCode.RequestTimeout;
509
            if (we.Response != null)
510
            {
511
                statusCode = ((HttpWebResponse) we.Response).StatusCode;
512
                this.StatusCode = statusCode;
513
            }
514
            return statusCode;
515
        }
516
    }
517

    
518
    public class RetryException:Exception
519
    {
520
        public RetryException()
521
            :base()
522
        {
523
            
524
        }
525

    
526
        public RetryException(string message)
527
            :base(message)
528
        {
529
            
530
        }
531

    
532
        public RetryException(string message,Exception innerException)
533
            :base(message,innerException)
534
        {
535
            
536
        }
537

    
538
        public RetryException(SerializationInfo info,StreamingContext context)
539
            :base(info,context)
540
        {
541
            
542
        }
543
    }
544
}
545
</code></pre>
546
                                                </td>
547
                                        </tr>
548
                        </tbody>
549
                </table>
550
        </div>
551
</body>
552
</html>