root / trunk / hammock / src / net35 / Hammock / Web / WebQuery.cs @ 0eea575a
History | View | Annotate | Download (70.2 kB)
1 |
using System; |
---|---|
2 |
using System.Collections.Generic; |
3 |
using System.Diagnostics; |
4 |
using System.IO; |
5 |
using System.Linq; |
6 |
using System.Net; |
7 |
using System.Reflection; |
8 |
using System.Text; |
9 |
using Hammock.Attributes.Specialized; |
10 |
using Hammock.Caching; |
11 |
using Hammock.Extensions; |
12 |
using Hammock.Validation; |
13 |
using Hammock.Web.Mocks; |
14 |
|
15 |
#if SILVERLIGHT |
16 |
using Hammock.Silverlight.Compat; |
17 |
using System.IO.IsolatedStorage; |
18 |
#endif |
19 |
|
20 |
#if SILVERLIGHT && !WindowsPhone |
21 |
using System.Windows.Browser; |
22 |
using System.Net.Browser; |
23 |
#endif |
24 |
|
25 |
namespace Hammock.Web |
26 |
{ |
27 |
public abstract partial class WebQuery: IDisposable |
28 |
{ |
29 |
private const string AcceptEncodingHeader = "Accept-Encoding"; |
30 |
private static readonly object _sync = new object(); |
31 |
private readonly WebHeaderCollection _restrictedHeaders = new WebHeaderCollection(0); |
32 |
|
33 |
public virtual Encoding Encoding { get; protected internal set; } |
34 |
public virtual IWebQueryInfo Info { get; protected set; } |
35 |
public virtual string UserAgent { get; protected internal set; } |
36 |
public virtual WebHeaderCollection Headers { get; protected set; } |
37 |
public virtual WebParameterCollection Parameters { get; protected set; } |
38 |
public virtual WebParameterCollection Cookies { get; protected set; } |
39 |
|
40 |
private WebEntity _entity; |
41 |
protected internal virtual WebEntity Entity |
42 |
{ |
43 |
get |
44 |
{ |
45 |
return _entity; |
46 |
} |
47 |
set |
48 |
{ |
49 |
_entity = value; |
50 |
HasEntity = _entity != null; |
51 |
} |
52 |
} |
53 |
|
54 |
public virtual WebMethod Method { get; set; } |
55 |
public virtual string Proxy { get; set; } |
56 |
public virtual string AuthorizationHeader { get; internal set; } |
57 |
public DecompressionMethods? DecompressionMethods { get; set; } |
58 |
public virtual TimeSpan? RequestTimeout { get; set; } |
59 |
public virtual WebQueryResult Result { get; internal set; } |
60 |
public virtual object UserState { get; internal set; } |
61 |
|
62 |
#if SILVERLIGHT |
63 |
public virtual bool HasElevatedPermissions { get; set; } |
64 |
|
65 |
// [DC]: Headers to use when access isn't direct |
66 |
public virtual string SilverlightUserAgentHeader { get; set; } |
67 |
public virtual string SilverlightAcceptEncodingHeader { get; set; } |
68 |
#endif |
69 |
|
70 |
#if !Silverlight |
71 |
public virtual ServicePoint ServicePoint { get; set; } |
72 |
public virtual bool KeepAlive { get; set; } |
73 |
public virtual bool FollowRedirects { get; internal set; } |
74 |
#endif |
75 |
|
76 |
private WebResponse _webResponse; |
77 |
public virtual WebResponse WebResponse |
78 |
{ |
79 |
get |
80 |
{ |
81 |
lock (_sync) |
82 |
{ |
83 |
return _webResponse; |
84 |
} |
85 |
} |
86 |
set |
87 |
{ |
88 |
lock (_sync) |
89 |
{ |
90 |
_webResponse = value; |
91 |
} |
92 |
} |
93 |
} |
94 |
|
95 |
protected virtual Stream ContentStream { get; set; } |
96 |
public virtual bool HasEntity { get; set; } |
97 |
public virtual byte[] PostContent { get; set; } |
98 |
|
99 |
#if SL3 || SL4 |
100 |
static WebQuery() |
101 |
{ |
102 |
// [DC]: Opt-in to the networking stack so we can get headers for proxies |
103 |
WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp); |
104 |
WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp); |
105 |
} |
106 |
#endif |
107 |
|
108 |
protected WebQuery(bool enableTrace) : this(null, enableTrace) |
109 |
{ |
110 |
|
111 |
} |
112 |
|
113 |
protected WebQuery(IWebQueryInfo info, bool enableTrace) |
114 |
{ |
115 |
TraceEnabled = enableTrace; |
116 |
SetQueryMeta(info); |
117 |
InitializeResult(); |
118 |
} |
119 |
|
120 |
protected bool TraceEnabled { get; private set; } |
121 |
|
122 |
private void SetQueryMeta(IWebQueryInfo info) |
123 |
{ |
124 |
Cookies = new WebParameterCollection(0); |
125 |
|
126 |
if(info == null) |
127 |
{ |
128 |
Headers = new WebHeaderCollection(0); |
129 |
Parameters = new WebParameterCollection(0); |
130 |
return; |
131 |
} |
132 |
|
133 |
Info = info; |
134 |
IEnumerable<PropertyInfo> properties; |
135 |
IDictionary<string, string> transforms; |
136 |
|
137 |
ParseTransforms(out properties, out transforms); |
138 |
Headers = ParseInfoHeaders(properties, transforms); |
139 |
Parameters = ParseInfoParameters(properties, transforms); |
140 |
ParseUserAgent(properties); |
141 |
ParseWebEntity(properties); |
142 |
} |
143 |
|
144 |
private void ParseTransforms(out IEnumerable<PropertyInfo> properties, |
145 |
out IDictionary<string, string> transforms) |
146 |
{ |
147 |
properties = Info.GetType().GetProperties(); |
148 |
transforms = new Dictionary<string, string>(0); |
149 |
Info.ParseValidationAttributes(properties, transforms); |
150 |
} |
151 |
|
152 |
private void InitializeResult() |
153 |
{ |
154 |
Result = new WebQueryResult(); |
155 |
QueryRequest += (s, e) => SetRequestResults(e); |
156 |
QueryResponse += (s, e) => SetResponseResults(e); |
157 |
} |
158 |
|
159 |
private void SetResponseResults(WebQueryResponseEventArgs e) |
160 |
{ |
161 |
Result.ContentStream = e.Response; |
162 |
Result.ResponseDate = DateTime.UtcNow; |
163 |
Result.RequestHttpMethod = Method.ToUpper(); |
164 |
Result.IsMock = WebResponse is MockHttpWebResponse; |
165 |
Result.TimedOut = TimedOut; |
166 |
|
167 |
string version; |
168 |
int statusCode; |
169 |
string statusDescription; |
170 |
System.Net.WebHeaderCollection headers; |
171 |
string contentType; |
172 |
long contentLength; |
173 |
Uri responseUri; |
174 |
CastWebResponse( |
175 |
out version, out statusCode, out statusDescription, out headers, |
176 |
out contentType, out contentLength, out responseUri |
177 |
); |
178 |
|
179 |
#if !MonoTouch |
180 |
TraceResponse( |
181 |
responseUri, version, headers, statusCode, statusDescription |
182 |
); |
183 |
#endif |
184 |
|
185 |
Result.WebResponse = WebResponse; |
186 |
Result.ResponseHttpStatusCode = statusCode; |
187 |
Result.ResponseHttpStatusDescription = statusDescription; |
188 |
Result.ResponseType = contentType; |
189 |
Result.ResponseLength = contentLength; |
190 |
Result.ResponseUri = responseUri; |
191 |
Result.Exception = e.Exception; |
192 |
} |
193 |
|
194 |
#if !MonoTouch |
195 |
[Conditional("TRACE")] |
196 |
private void TraceResponse(Uri uri, string version, System.Net.WebHeaderCollection headers, int statusCode, string statusDescription) |
197 |
{ |
198 |
if(!TraceEnabled) |
199 |
{ |
200 |
return; |
201 |
} |
202 |
|
203 |
Trace.WriteLine( |
204 |
String.Concat("\r\n--RESPONSE:", " ", uri) |
205 |
); |
206 |
Trace.WriteLine( |
207 |
String.Concat(version, " ", statusCode, " ", statusDescription) |
208 |
); |
209 |
foreach (var trace in headers.AllKeys.Select( |
210 |
key => String.Concat(key, ": ", headers[key]))) |
211 |
{ |
212 |
Trace.WriteLine(trace); |
213 |
} |
214 |
} |
215 |
#endif |
216 |
|
217 |
private void SetRequestResults(WebQueryRequestEventArgs e) |
218 |
{ |
219 |
Result.RequestDate = DateTime.UtcNow; |
220 |
Result.RequestUri = new Uri(e.Request); |
221 |
#if !SILVERLIGHT |
222 |
Result.RequestKeptAlive = KeepAlive; |
223 |
#endif |
224 |
} |
225 |
|
226 |
#if !SILVERLIGHT |
227 |
protected virtual void SetWebProxy(WebRequest request) |
228 |
{ |
229 |
#if !Smartphone && !NETCF |
230 |
var proxyUriBuilder = new UriBuilder(Proxy); |
231 |
request.Proxy = new WebProxy(proxyUriBuilder.Host, |
232 |
proxyUriBuilder.Port); |
233 |
|
234 |
if (!proxyUriBuilder.UserName.IsNullOrBlank()) |
235 |
{ |
236 |
request.Headers["Proxy-Authorization"] = WebExtensions.ToBasicAuthorizationHeader(proxyUriBuilder.UserName, |
237 |
proxyUriBuilder.Password); |
238 |
} |
239 |
#else |
240 |
var uri = new Uri(Proxy); |
241 |
request.Proxy = new WebProxy(uri.Host, uri.Port); |
242 |
var userParts = uri.UserInfo.Split(new[] { ':' }).Where(ui => !ui.IsNullOrBlank()).ToArray(); |
243 |
if (userParts.Length == 2) |
244 |
{ |
245 |
request.Proxy.Credentials = new NetworkCredential(userParts[0], userParts[1]); |
246 |
} |
247 |
#endif |
248 |
} |
249 |
#endif |
250 |
|
251 |
protected virtual WebRequest BuildPostOrPutWebRequest(PostOrPut method, string url, out byte[] content) |
252 |
{ |
253 |
return !HasEntity |
254 |
? BuildPostOrPutFormWebRequest(method, url, out content) |
255 |
: BuildPostOrPutEntityWebRequest(method, url, out content); |
256 |
} |
257 |
|
258 |
protected virtual Func<string, string> BeforeBuildPostOrPutFormWebRequest() |
259 |
{ |
260 |
return url => AppendParameters(url).Replace(url + "?", ""); |
261 |
} |
262 |
|
263 |
protected virtual WebRequest BuildPostOrPutFormWebRequest(PostOrPut method, string url, out byte[] content) |
264 |
{ |
265 |
var post = BeforeBuildPostOrPutFormWebRequest().Invoke(url); |
266 |
|
267 |
var request = WebRequest.Create(url); |
268 |
|
269 |
AuthenticateRequest(request); |
270 |
|
271 |
SetMethod(method.ToString(), request); |
272 |
|
273 |
// It should be possible to override the content type in the case of AddPostContent |
274 |
var hasContentType = Headers.AllKeys.Where( |
275 |
key => key.Equals("Content-Type", StringComparison.InvariantCultureIgnoreCase) |
276 |
).Count() > 0; |
277 |
|
278 |
if(!hasContentType) |
279 |
{ |
280 |
request.ContentType = "application/x-www-form-urlencoded"; |
281 |
} |
282 |
|
283 |
HandleRequestMeta(request); |
284 |
|
285 |
#if !MonoTouch |
286 |
TraceRequest(request); |
287 |
#endif |
288 |
content = BuildPostOrPutContent(request, post); |
289 |
|
290 |
#if !SILVERLIGHT |
291 |
request.ContentLength = content.Length; |
292 |
#endif |
293 |
return request; |
294 |
} |
295 |
|
296 |
protected virtual byte[] BuildPostOrPutContent(WebRequest request, string post) |
297 |
{ |
298 |
var encoding = Encoding ?? Encoding.UTF8; |
299 |
|
300 |
var content = PostContent ?? encoding.GetBytes(post); |
301 |
|
302 |
#if TRACE |
303 |
Trace.WriteLineIf(TraceEnabled, string.Concat("\r\n", content)); |
304 |
#endif |
305 |
return content; |
306 |
} |
307 |
|
308 |
protected virtual Func<string, string> BeforeBuildPostOrPutEntityWebRequest() |
309 |
{ |
310 |
return AppendParameters; |
311 |
} |
312 |
|
313 |
protected virtual WebRequest BuildPostOrPutEntityWebRequest(PostOrPut method, string url, out byte[] content) |
314 |
{ |
315 |
url = BeforeBuildPostOrPutEntityWebRequest().Invoke(url); |
316 |
|
317 |
var request = WebRequest.Create(url); |
318 |
|
319 |
SetMethod(method.ToString(), request); |
320 |
|
321 |
AuthenticateRequest(request); |
322 |
|
323 |
HandleRequestMeta(request); |
324 |
|
325 |
#if !MonoTouch |
326 |
TraceRequest(request); |
327 |
#endif |
328 |
|
329 |
if (Entity != null) |
330 |
{ |
331 |
var entity = Entity.Content; |
332 |
|
333 |
var encoding = Entity.ContentEncoding ?? Encoding ?? Encoding.UTF8; |
334 |
|
335 |
content = encoding.GetBytes(entity); |
336 |
|
337 |
request.ContentType = Entity.ContentType; |
338 |
#if TRACE |
339 |
Trace.WriteLineIf(TraceEnabled, string.Concat("\r\n", entity)); |
340 |
#endif |
341 |
|
342 |
#if !SILVERLIGHT |
343 |
// [DC]: This is set by Silverlight |
344 |
request.ContentLength = content.Length; |
345 |
#endif |
346 |
} |
347 |
else |
348 |
{ |
349 |
using(var ms = new MemoryStream()) |
350 |
{ |
351 |
content = ms.ToArray(); |
352 |
} |
353 |
} |
354 |
|
355 |
return request; |
356 |
} |
357 |
|
358 |
protected virtual Func<string, string> BeforeBuildGetDeleteHeadOptionsWebRequest() |
359 |
{ |
360 |
return AppendParameters; |
361 |
} |
362 |
|
363 |
protected virtual WebRequest BuildGetDeleteHeadOptionsWebRequest(GetDeleteHeadOptions method, string url) |
364 |
{ |
365 |
url = BeforeBuildGetDeleteHeadOptionsWebRequest().Invoke(url); |
366 |
|
367 |
var request = WebRequest.Create(url); |
368 |
|
369 |
SetMethod(method.ToString(), request); |
370 |
|
371 |
AuthenticateRequest(request); |
372 |
|
373 |
HandleRequestMeta(request); |
374 |
|
375 |
#if !MonoTouch |
376 |
TraceRequest(request); |
377 |
#endif |
378 |
return request; |
379 |
} |
380 |
|
381 |
private void SetMethod(string method, WebRequest request) |
382 |
{ |
383 |
request.Method = method.ToUpper(); |
384 |
} |
385 |
|
386 |
private void HandleRequestMeta(WebRequest request) |
387 |
{ |
388 |
// [DC] LSP violation necessary for "pure" mocks |
389 |
if (request is HttpWebRequest) |
390 |
{ |
391 |
SetRequestMeta((HttpWebRequest)request); |
392 |
} |
393 |
else |
394 |
{ |
395 |
AppendHeaders(request); |
396 |
SetUserAgent(request); |
397 |
} |
398 |
} |
399 |
|
400 |
protected virtual void SetUserAgent(WebRequest request) |
401 |
{ |
402 |
if (!UserAgent.IsNullOrBlank()) |
403 |
{ |
404 |
#if SILVERLIGHT && !WindowsPhone |
405 |
// [DC] User-Agent is still restricted in elevated mode |
406 |
request.Headers[SilverlightUserAgentHeader ?? "X-User-Agent"] = UserAgent; |
407 |
#else |
408 |
if(request is HttpWebRequest) |
409 |
{ |
410 |
((HttpWebRequest) request).UserAgent = UserAgent; |
411 |
} |
412 |
else |
413 |
{ |
414 |
request.Headers["User-Agent"] = UserAgent; |
415 |
} |
416 |
#endif |
417 |
} |
418 |
} |
419 |
|
420 |
protected virtual void SetRequestMeta(HttpWebRequest request) |
421 |
{ |
422 |
AppendHeaders(request); |
423 |
AppendCookies(request); |
424 |
|
425 |
#if !SILVERLIGHT |
426 |
if (ServicePoint != null) |
427 |
{ |
428 |
#if !Smartphone && !NETCF |
429 |
request.ServicePoint.ConnectionLeaseTimeout = ServicePoint.ConnectionLeaseTimeout; |
430 |
request.ServicePoint.ReceiveBufferSize = ServicePoint.ReceiveBufferSize; |
431 |
request.ServicePoint.UseNagleAlgorithm = ServicePoint.UseNagleAlgorithm; |
432 |
request.ServicePoint.BindIPEndPointDelegate = ServicePoint.BindIPEndPointDelegate; |
433 |
#endif |
434 |
request.ServicePoint.ConnectionLimit = ServicePoint.ConnectionLimit; |
435 |
request.ServicePoint.Expect100Continue = ServicePoint.Expect100Continue; |
436 |
request.ServicePoint.MaxIdleTime = ServicePoint.MaxIdleTime; |
437 |
} |
438 |
#endif |
439 |
|
440 |
#if !SILVERLIGHT |
441 |
if (!Proxy.IsNullOrBlank()) |
442 |
{ |
443 |
SetWebProxy(request); |
444 |
} |
445 |
request.AllowAutoRedirect = FollowRedirects; |
446 |
#endif |
447 |
|
448 |
SetUserAgent(request); |
449 |
|
450 |
if (DecompressionMethods.HasValue) |
451 |
{ |
452 |
var decompressionMethods = DecompressionMethods.Value; |
453 |
|
454 |
#if !SILVERLIGHT && !WindowsPhone |
455 |
request.AutomaticDecompression = decompressionMethods; |
456 |
#else |
457 |
|
458 |
#if !WindowsPhone |
459 |
if (HasElevatedPermissions) |
460 |
{ |
461 |
#endif |
462 |
switch (decompressionMethods) |
463 |
{ |
464 |
case Silverlight.Compat.DecompressionMethods.GZip: |
465 |
request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "gzip"; |
466 |
break; |
467 |
case Silverlight.Compat.DecompressionMethods.Deflate: |
468 |
request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "deflate"; |
469 |
break; |
470 |
case Silverlight.Compat.DecompressionMethods.GZip | Silverlight.Compat.DecompressionMethods.Deflate: |
471 |
request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "gzip,deflate"; |
472 |
break; |
473 |
} |
474 |
|
475 |
#if !WindowsPhone |
476 |
} |
477 |
else |
478 |
{ |
479 |
switch (decompressionMethods) |
480 |
{ |
481 |
case Silverlight.Compat.DecompressionMethods.GZip: |
482 |
request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "gzip"; |
483 |
break; |
484 |
case Silverlight.Compat.DecompressionMethods.Deflate: |
485 |
request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "deflate"; |
486 |
break; |
487 |
case Silverlight.Compat.DecompressionMethods.GZip | Silverlight.Compat.DecompressionMethods.Deflate: |
488 |
request.Headers[SilverlightAcceptEncodingHeader ?? "X-Accept-Encoding"] = "gzip,deflate"; |
489 |
break; |
490 |
} |
491 |
} |
492 |
#endif |
493 |
|
494 |
#endif |
495 |
} |
496 |
#if !SILVERLIGHT |
497 |
if (RequestTimeout.HasValue) |
498 |
{ |
499 |
// [DC] Need to synchronize these as Timeout is ignored in async requests |
500 |
request.Timeout = (int)RequestTimeout.Value.TotalMilliseconds; |
501 |
request.ReadWriteTimeout = (int)RequestTimeout.Value.TotalMilliseconds; |
502 |
} |
503 |
|
504 |
if (KeepAlive) |
505 |
{ |
506 |
request.KeepAlive = true; |
507 |
} |
508 |
#endif |
509 |
} |
510 |
|
511 |
private void AppendCookies(HttpWebRequest request) |
512 |
{ |
513 |
#if !NETCF |
514 |
request.CookieContainer = new CookieContainer(); |
515 |
|
516 |
foreach(var cookie in Cookies.OfType<HttpCookieParameter>()) |
517 |
{ |
518 |
var value = new Cookie(cookie.Name, cookie.Value); |
519 |
if(cookie.Domain != null) |
520 |
{ |
521 |
request.CookieContainer.Add(cookie.Domain, value); |
522 |
} |
523 |
#if !SILVERLIGHT |
524 |
else |
525 |
{ |
526 |
request.CookieContainer.Add(value); |
527 |
} |
528 |
#endif |
529 |
} |
530 |
#endif |
531 |
} |
532 |
|
533 |
protected virtual void AppendHeaders(WebRequest request) |
534 |
{ |
535 |
if (!(request is HttpWebRequest) && |
536 |
!(request is MockHttpWebRequest)) |
537 |
{ |
538 |
return; |
539 |
} |
540 |
|
541 |
// [DC]: Combine all duplicate headers into CSV |
542 |
var headers = new Dictionary<string, string>(0); |
543 |
foreach(var header in Headers) |
544 |
{ |
545 |
string value; |
546 |
if(headers.ContainsKey(header.Name)) |
547 |
{ |
548 |
value = String.Concat(headers[header.Name], ",", header.Value); |
549 |
headers.Remove(header.Name); |
550 |
} |
551 |
else |
552 |
{ |
553 |
value = header.Value; |
554 |
} |
555 |
|
556 |
headers.Add(header.Name, value); |
557 |
} |
558 |
|
559 |
foreach (var header in headers) |
560 |
{ |
561 |
if (_restrictedHeaderActions.ContainsKey(header.Key)) |
562 |
{ |
563 |
if(request is HttpWebRequest) |
564 |
{ |
565 |
#if SILVERLIGHT |
566 |
if(header.Key.EqualsIgnoreCase("User-Agent")) |
567 |
{ |
568 |
// [DC]: User-Agent is still restricted in elevated mode |
569 |
request.Headers[SilverlightUserAgentHeader ?? "X-User-Agent"] = UserAgent; |
570 |
continue; |
571 |
} |
572 |
#endif |
573 |
_restrictedHeaderActions[header.Key].Invoke((HttpWebRequest) request, header.Value); |
574 |
_restrictedHeaders.Add(header.Key, header.Value); |
575 |
} |
576 |
if(request is MockHttpWebRequest) |
577 |
{ |
578 |
AddHeader(header, request); |
579 |
} |
580 |
} |
581 |
else |
582 |
{ |
583 |
AddHeader(header, request); |
584 |
} |
585 |
} |
586 |
} |
587 |
|
588 |
#if !MonoTouch |
589 |
[Conditional("TRACE")] |
590 |
private void TraceHeaders(WebRequest request) |
591 |
{ |
592 |
if (!TraceEnabled) |
593 |
{ |
594 |
return; |
595 |
} |
596 |
|
597 |
var restricted = _restrictedHeaders.AllKeys.Select(key => String.Concat(key, ": ", request.Headers[key])); |
598 |
var remaining = request.Headers.AllKeys.Except(_restrictedHeaders.AllKeys).Select(key => String.Concat(key, ": ", request.Headers[key])); |
599 |
var all = restricted.ToList(); |
600 |
all.AddRange(remaining); |
601 |
all.Sort(); |
602 |
|
603 |
foreach (var trace in all) |
604 |
{ |
605 |
Trace.WriteLine(trace); |
606 |
} |
607 |
} |
608 |
#endif |
609 |
|
610 |
private static void AddHeader(KeyValuePair<string, string> header, WebRequest request) |
611 |
{ |
612 |
#if !SILVERLIGHT |
613 |
request.Headers.Add(header.Key, header.Value); |
614 |
#else |
615 |
request.Headers[header.Key] = header.Value; |
616 |
#endif |
617 |
} |
618 |
|
619 |
#if !SILVERLIGHT |
620 |
private readonly IDictionary<string, Action<HttpWebRequest, string>> _restrictedHeaderActions |
621 |
= new Dictionary<string, Action<HttpWebRequest, string>>(StringComparer.OrdinalIgnoreCase) |
622 |
{ |
623 |
{"Accept", (r, v) => r.Accept = v}, |
624 |
{"Connection", (r, v) => r.Connection = v}, |
625 |
{"Content-Length", (r, v) => r.ContentLength = Convert.ToInt64(v)}, |
626 |
{"Content-Type", (r, v) => r.ContentType = v}, |
627 |
{"Expect", (r, v) => r.Expect = v}, |
628 |
{"Date", (r, v) => { /* Set by system */ }}, |
629 |
{"Host", (r, v) => { /* Set by system */ }}, |
630 |
{"If-Modified-Since", (r, v) => r.IfModifiedSince = Convert.ToDateTime(v)}, |
631 |
{"Range", (r, v) => { throw new NotSupportedException( /* r.AddRange() */); }}, |
632 |
{"Referer", (r, v) => r.Referer = v}, |
633 |
{"Transfer-Encoding", (r, v) => { r.TransferEncoding = v; r.SendChunked = true; }}, |
634 |
{"User-Agent", (r, v) => r.UserAgent = v } |
635 |
}; |
636 |
#else |
637 |
private readonly IDictionary<string, Action<HttpWebRequest, string>> _restrictedHeaderActions |
638 |
= new Dictionary<string, Action<HttpWebRequest, string>>(StringComparer.OrdinalIgnoreCase) { |
639 |
{ "Accept", (r, v) => r.Accept = v }, |
640 |
{ "Connection", (r, v) => { /* Set by Silverlight */ }}, |
641 |
{ "Content-Length", (r, v) => { /* Set by Silverlight */ }}, |
642 |
{ "Content-Type", (r, v) => r.ContentType = v }, |
643 |
{ "Expect", (r, v) => { /* Set by Silverlight */ }}, |
644 |
{ "Date", (r, v) => { /* Set by Silverlight */ }}, |
645 |
{ "Host", (r, v) => { /* Set by Silverlight */ }}, |
646 |
{ "If-Modified-Since", (r, v) => { /* Not supported */ }}, |
647 |
{ "Range", (r, v) => { /* Not supported */ }}, |
648 |
{ "Referer", (r, v) => { /* Not supported */ }}, |
649 |
{ "Transfer-Encoding", (r, v) => { /* Not supported */ }}, |
650 |
{ "User-Agent", (r, v) => { /* Not supported here */ }} |
651 |
}; |
652 |
#endif |
653 |
|
654 |
protected virtual string AppendParameters(string url) |
655 |
{ |
656 |
var count = 0; |
657 |
|
658 |
var parameters = Parameters.Where( |
659 |
parameter => !(parameter is HttpPostParameter) || Method == WebMethod.Post).Where( |
660 |
parameter => !string.IsNullOrEmpty(parameter.Name) && !string.IsNullOrEmpty(parameter.Value) |
661 |
); |
662 |
|
663 |
foreach (var parameter in parameters) |
664 |
{ |
665 |
// GET parameters in URL |
666 |
url = url.Then(count > 0 || url.Contains("?") ? "&" : "?"); |
667 |
url = url.Then("{0}={1}".FormatWith(parameter.Name, parameter.Value.UrlEncode())); |
668 |
count++; |
669 |
} |
670 |
|
671 |
return url; |
672 |
} |
673 |
|
674 |
// [DC] Headers don't need to be unique, this should change |
675 |
protected virtual WebHeaderCollection ParseInfoHeaders(IEnumerable<PropertyInfo> properties, |
676 |
IDictionary<string, string> transforms) |
677 |
{ |
678 |
var headers = new Dictionary<string, string>(); |
679 |
|
680 |
Info.ParseNamedAttributes<HeaderAttribute>(properties, transforms, headers); |
681 |
|
682 |
var collection = new WebHeaderCollection(); |
683 |
headers.ForEach(p => collection.Add(new WebHeader(p.Key, p.Value))); |
684 |
|
685 |
return collection; |
686 |
} |
687 |
|
688 |
protected virtual WebParameterCollection ParseInfoParameters(IEnumerable<PropertyInfo> properties, |
689 |
IDictionary<string, string> transforms) |
690 |
{ |
691 |
var parameters = new Dictionary<string, string>(); |
692 |
|
693 |
Info.ParseNamedAttributes<ParameterAttribute>(properties, transforms, parameters); |
694 |
|
695 |
var collection = new WebParameterCollection(); |
696 |
parameters.ForEach(p => collection.Add(new WebParameter(p.Key, p.Value))); |
697 |
|
698 |
return collection; |
699 |
} |
700 |
|
701 |
protected virtual WebParameterCollection ParseInfoParameters() |
702 |
{ |
703 |
IEnumerable<PropertyInfo> properties; |
704 |
IDictionary<string, string> transforms; |
705 |
ParseTransforms(out properties, out transforms); |
706 |
return ParseInfoParameters(properties, transforms); |
707 |
} |
708 |
|
709 |
private void ParseUserAgent(IEnumerable<PropertyInfo> properties) |
710 |
{ |
711 |
var count = 0; |
712 |
foreach (var property in properties) |
713 |
{ |
714 |
var attributes = property.GetCustomAttributes<UserAgentAttribute>(true); |
715 |
count += attributes.Count(); |
716 |
if (count > 1) |
717 |
{ |
718 |
throw new ArgumentException("Cannot declare more than one user agent per query"); |
719 |
} |
720 |
|
721 |
if (count < 1) |
722 |
{ |
723 |
continue; |
724 |
} |
725 |
|
726 |
if (!UserAgent.IsNullOrBlank()) |
727 |
{ |
728 |
continue; |
729 |
} |
730 |
|
731 |
var value = property.GetValue(Info, null); |
732 |
UserAgent = value != null ? value.ToString() : null; |
733 |
} |
734 |
} |
735 |
|
736 |
private void ParseWebEntity(IEnumerable<PropertyInfo> properties) |
737 |
{ |
738 |
if (Entity != null) |
739 |
{ |
740 |
// Already set by client or request |
741 |
return; |
742 |
} |
743 |
|
744 |
var count = 0; |
745 |
foreach (var property in properties) |
746 |
{ |
747 |
var attributes = property.GetCustomAttributes<EntityAttribute>(true); |
748 |
count += attributes.Count(); |
749 |
if (count > 1) |
750 |
{ |
751 |
throw new ValidationException("Cannot declare more than one entity per query"); |
752 |
} |
753 |
|
754 |
if (count < 1) |
755 |
{ |
756 |
continue; |
757 |
} |
758 |
|
759 |
if (Entity != null) |
760 |
{ |
761 |
// Already set in this pass |
762 |
continue; |
763 |
} |
764 |
|
765 |
var value = property.GetValue(Info, null); |
766 |
|
767 |
var content = value != null ? value.ToString() : null; |
768 |
var contentEncoding = attributes.Single().ContentEncoding; |
769 |
var contentType = attributes.Single().ContentType; |
770 |
|
771 |
Entity = new WebEntity |
772 |
{ |
773 |
Content = content, |
774 |
ContentEncoding = contentEncoding, |
775 |
ContentType = contentType |
776 |
}; |
777 |
} |
778 |
} |
779 |
|
780 |
protected void HandleWebException(WebException exception) |
781 |
{ |
782 |
if (!(exception.Response is HttpWebResponse)) |
783 |
{ |
784 |
return; |
785 |
} |
786 |
|
787 |
var response = exception.Response; |
788 |
#if SILVERLIGHT |
789 |
if (DecompressionMethods == Silverlight.Compat.DecompressionMethods.GZip || |
790 |
DecompressionMethods == Silverlight.Compat.DecompressionMethods.Deflate || |
791 |
DecompressionMethods == (Silverlight.Compat.DecompressionMethods.GZip | Silverlight.Compat.DecompressionMethods.Deflate) |
792 |
) |
793 |
{ |
794 |
response = new GzipHttpWebResponse((HttpWebResponse)response); |
795 |
} |
796 |
#endif |
797 |
WebResponse = response; |
798 |
var stream = WebResponse.GetResponseStream(); |
799 |
|
800 |
if (stream == null) |
801 |
{ |
802 |
return; |
803 |
} |
804 |
|
805 |
var args = new WebQueryResponseEventArgs(stream, exception); |
806 |
OnQueryResponse(args); |
807 |
} |
808 |
|
809 |
protected abstract void SetAuthorizationHeader(WebRequest request, string header); |
810 |
|
811 |
protected abstract void AuthenticateRequest(WebRequest request); |
812 |
|
813 |
public abstract string GetAuthorizationContent(); |
814 |
|
815 |
private static string CreateCacheKey(string prefix, string url) |
816 |
{ |
817 |
return !prefix.IsNullOrBlank() ? "{0}_{1}".FormatWith(prefix, url) : url; |
818 |
} |
819 |
|
820 |
protected virtual void ExecuteWithCache(ICache cache, |
821 |
string url, |
822 |
string key, |
823 |
Action<ICache, string> cacheScheme) |
824 |
{ |
825 |
var fetch = cache.Get<Stream>(CreateCacheKey(key, url)); |
826 |
if (fetch != null) |
827 |
{ |
828 |
// [DC]: In order to build results, an event must still raise |
829 |
var responseArgs = new WebQueryResponseEventArgs(fetch); |
830 |
OnQueryResponse(responseArgs); |
831 |
} |
832 |
else |
833 |
{ |
834 |
cacheScheme.Invoke(cache, url); |
835 |
} |
836 |
} |
837 |
|
838 |
protected virtual void ExecuteWithCacheAndAbsoluteExpiration(ICache cache, |
839 |
string url, |
840 |
string key, |
841 |
DateTime expiry, |
842 |
Action<ICache, string, DateTime> cacheScheme) |
843 |
{ |
844 |
var fetch = cache.Get<Stream>(CreateCacheKey(key, url)); |
845 |
if (fetch != null) |
846 |
{ |
847 |
// [DC]: In order to build results, an event must still raise |
848 |
var responseArgs = new WebQueryResponseEventArgs(fetch); |
849 |
OnQueryResponse(responseArgs); |
850 |
} |
851 |
else |
852 |
{ |
853 |
cacheScheme.Invoke(cache, url, expiry); |
854 |
} |
855 |
} |
856 |
|
857 |
protected virtual void ExecuteWithCacheAndSlidingExpiration(ICache cache, |
858 |
string url, |
859 |
string key, |
860 |
TimeSpan expiry, |
861 |
Action<ICache, string, TimeSpan> cacheScheme) |
862 |
{ |
863 |
var fetch = cache.Get<Stream>(CreateCacheKey(key, url)); |
864 |
if (fetch != null) |
865 |
{ |
866 |
// [DC]: In order to build results, an event must still raise |
867 |
var responseArgs = new WebQueryResponseEventArgs(fetch); |
868 |
OnQueryResponse(responseArgs); |
869 |
} |
870 |
else |
871 |
{ |
872 |
cacheScheme.Invoke(cache, url, expiry); |
873 |
} |
874 |
} |
875 |
|
876 |
#if !SILVERLIGHT |
877 |
protected virtual void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, string url, string key, ICache cache, out WebException exception) |
878 |
{ |
879 |
WebException ex = null; |
880 |
ExecuteWithCache(cache, url, key, (c, u) => ExecuteGetDeleteHeadOptions(method, cache, url, key, out ex)); |
881 |
exception = ex; |
882 |
} |
883 |
|
884 |
protected virtual void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, |
885 |
string url, |
886 |
string key, |
887 |
ICache cache, |
888 |
DateTime absoluteExpiration, |
889 |
out WebException exception) |
890 |
{ |
891 |
WebException ex = null; |
892 |
ExecuteWithCacheAndAbsoluteExpiration(cache, url, key, absoluteExpiration, |
893 |
(c, u, e) => |
894 |
ExecuteGetDeleteHeadOptions(method, cache, url, key, absoluteExpiration, out ex)); |
895 |
exception = ex; |
896 |
} |
897 |
|
898 |
protected virtual void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, |
899 |
string url, |
900 |
string key, |
901 |
ICache cache, |
902 |
TimeSpan slidingExpiration, |
903 |
out WebException exception) |
904 |
{ |
905 |
WebException ex = null; |
906 |
ExecuteWithCacheAndSlidingExpiration(cache, url, key, slidingExpiration, |
907 |
(c, u, e) => |
908 |
ExecuteGetDeleteHeadOptions(method, cache, url, key, slidingExpiration, out ex)); |
909 |
exception = ex; |
910 |
} |
911 |
|
912 |
private void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, |
913 |
ICache cache, |
914 |
string url, |
915 |
string key, |
916 |
out WebException exception) |
917 |
{ |
918 |
ExecuteGetDeleteHeadOptions(method, url, out exception); |
919 |
if (exception == null) |
920 |
{ |
921 |
cache.Insert(CreateCacheKey(key, url), ContentStream); |
922 |
} |
923 |
} |
924 |
|
925 |
private void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, |
926 |
ICache cache, |
927 |
string url, |
928 |
string key, |
929 |
DateTime absoluteExpiration, |
930 |
out WebException exception) |
931 |
{ |
932 |
ExecuteGetDeleteHeadOptions(method, url, out exception); |
933 |
if (exception == null) |
934 |
{ |
935 |
cache.Insert(CreateCacheKey(key, url), ContentStream, absoluteExpiration); |
936 |
} |
937 |
} |
938 |
|
939 |
private void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, ICache cache, string url, string key, |
940 |
TimeSpan slidingExpiration, out WebException exception) |
941 |
{ |
942 |
ExecuteGetDeleteHeadOptions(method, url, out exception); |
943 |
if (exception == null) |
944 |
{ |
945 |
cache.Insert(CreateCacheKey(key, url), ContentStream, slidingExpiration); |
946 |
} |
947 |
} |
948 |
#endif |
949 |
|
950 |
public virtual event EventHandler<WebQueryRequestEventArgs> QueryRequest; |
951 |
public virtual void OnQueryRequest(WebQueryRequestEventArgs args) |
952 |
{ |
953 |
var handler = QueryRequest; |
954 |
if (handler != null) |
955 |
{ |
956 |
handler(this, args); |
957 |
} |
958 |
} |
959 |
|
960 |
public virtual event EventHandler<WebQueryResponseEventArgs> QueryResponse; |
961 |
public virtual void OnQueryResponse(WebQueryResponseEventArgs args) |
962 |
{ |
963 |
var handler = QueryResponse; |
964 |
if (handler != null) |
965 |
{ |
966 |
handler(this, args); |
967 |
} |
968 |
} |
969 |
|
970 |
internal virtual event EventHandler<PostProgressEventArgs> PostProgress; |
971 |
internal virtual void OnPostProgress(PostProgressEventArgs args) |
972 |
{ |
973 |
var handler = PostProgress; |
974 |
if (handler != null) |
975 |
{ |
976 |
handler(this, args); |
977 |
} |
978 |
} |
979 |
#if !SILVERLIGHT |
980 |
protected virtual void ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions method, string url, out WebException exception) |
981 |
{ |
982 |
WebResponse = null; |
983 |
var request = BuildGetDeleteHeadOptionsWebRequest(method, url); |
984 |
|
985 |
var requestArgs = new WebQueryRequestEventArgs(url); |
986 |
OnQueryRequest(requestArgs); |
987 |
|
988 |
ExecuteGetDeleteHeadOptions(request, out exception); |
989 |
} |
990 |
|
991 |
private void ExecuteGetDeleteHeadOptions(WebRequest request, out WebException exception) |
992 |
{ |
993 |
try |
994 |
{ |
995 |
// [DC] Avoid disposing until no longer needed to build results |
996 |
var response = request.GetResponse(); |
997 |
WebResponse = response; |
998 |
|
999 |
if (response != null) |
1000 |
{ |
1001 |
ContentStream = response.GetResponseStream(); |
1002 |
if (ContentStream != null) |
1003 |
{ |
1004 |
var args = new WebQueryResponseEventArgs(ContentStream); |
1005 |
OnQueryResponse(args); |
1006 |
} |
1007 |
} |
1008 |
|
1009 |
exception = null; |
1010 |
} |
1011 |
catch (WebException ex) |
1012 |
{ |
1013 |
exception = ex; |
1014 |
HandleWebException(ex); |
1015 |
} |
1016 |
} |
1017 |
|
1018 |
#endif |
1019 |
protected virtual WebRequest BuildMultiPartFormRequest(PostOrPut method, string url, IEnumerable<HttpPostParameter> parameters, out string boundary) |
1020 |
{ |
1021 |
url = AppendParameters(url); |
1022 |
|
1023 |
boundary = Guid.NewGuid().ToString(); |
1024 |
var request = WebRequest.Create(url); |
1025 |
AuthenticateRequest(request); |
1026 |
|
1027 |
request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary); |
1028 |
request.Method = method == PostOrPut.Post ? "POST" : "PUT"; |
1029 |
|
1030 |
HandleRequestMeta(request); |
1031 |
|
1032 |
#if !MonoTouch |
1033 |
TraceRequest(request); |
1034 |
#endif |
1035 |
|
1036 |
return request; |
1037 |
} |
1038 |
|
1039 |
#if !MonoTouch |
1040 |
[Conditional("TRACE")] |
1041 |
protected void TraceRequest(WebRequest request) |
1042 |
{ |
1043 |
if (!TraceEnabled) |
1044 |
{ |
1045 |
return; |
1046 |
} |
1047 |
|
1048 |
var version = request is HttpWebRequest ? |
1049 |
#if SILVERLIGHT |
1050 |
"HTTP/v1.1" : |
1051 |
#else |
1052 |
string.Concat("HTTP/", ((HttpWebRequest)request).ProtocolVersion) : |
1053 |
#endif |
1054 |
"HTTP/v1.1"; |
1055 |
|
1056 |
Trace.WriteLine( |
1057 |
String.Concat("--REQUEST: ", request.RequestUri.Scheme, "://", request.RequestUri.Host) |
1058 |
); |
1059 |
var pathAndQuery = String.Concat( |
1060 |
request.RequestUri.AbsolutePath, string.IsNullOrEmpty(request.RequestUri.Query) |
1061 |
? "" |
1062 |
: string.Concat(request.RequestUri.Query) |
1063 |
); |
1064 |
Trace.WriteLine( |
1065 |
String.Concat(request.Method, " ", pathAndQuery, " ", version |
1066 |
)); |
1067 |
|
1068 |
TraceHeaders(request); |
1069 |
} |
1070 |
#endif |
1071 |
|
1072 |
#if !SILVERLIGHT |
1073 |
protected virtual void ExecutePostOrPut(PostOrPut method, string url, out WebException exception) |
1074 |
{ |
1075 |
WebResponse = null; |
1076 |
exception = null; |
1077 |
byte[] post; |
1078 |
var request = BuildPostOrPutWebRequest(method, url, out post); |
1079 |
|
1080 |
var requestArgs = new WebQueryRequestEventArgs(url); |
1081 |
OnQueryRequest(requestArgs); |
1082 |
|
1083 |
try |
1084 |
{ |
1085 |
using (var stream = request.GetRequestStream()) |
1086 |
{ |
1087 |
stream.Write(post, 0, post.Length); |
1088 |
stream.Close(); |
1089 |
|
1090 |
#if TRACE |
1091 |
var encoding = Encoding ?? new UTF8Encoding(); |
1092 |
#if NETCF |
1093 |
Trace.WriteLineIf(TraceEnabled, encoding.GetString(post, 0, post.Length)); |
1094 |
#else |
1095 |
Trace.WriteLineIf(TraceEnabled, encoding.GetString(post)); |
1096 |
#endif |
1097 |
#endif |
1098 |
|
1099 |
// [DC] Avoid disposing until no longer needed to build results |
1100 |
var response = request.GetResponse(); |
1101 |
WebResponse = response; |
1102 |
|
1103 |
if (response != null) |
1104 |
{ |
1105 |
ContentStream = response.GetResponseStream(); |
1106 |
if (ContentStream != null) |
1107 |
{ |
1108 |
var args = new WebQueryResponseEventArgs(ContentStream); |
1109 |
OnQueryResponse(args); |
1110 |
} |
1111 |
} |
1112 |
} |
1113 |
} |
1114 |
catch (WebException ex) |
1115 |
{ |
1116 |
exception = ex; |
1117 |
HandleWebException(ex); |
1118 |
} |
1119 |
} |
1120 |
|
1121 |
protected virtual void ExecutePostOrPut(PostOrPut method, |
1122 |
string url, |
1123 |
IEnumerable<HttpPostParameter> parameters, |
1124 |
out WebException exception) |
1125 |
{ |
1126 |
WebResponse = null; |
1127 |
|
1128 |
string boundary; |
1129 |
var request = BuildMultiPartFormRequest(method, url, parameters, out boundary); |
1130 |
|
1131 |
#if !Smartphone |
1132 |
var encoding = Encoding ?? Encoding.GetEncoding("ISO-8859-1"); |
1133 |
#else |
1134 |
var encoding = Encoding ?? Encoding.GetEncoding(1252); |
1135 |
#endif |
1136 |
var expected = WriteMultiPartImpl( |
1137 |
false /* write */, parameters, boundary, encoding, null |
1138 |
); |
1139 |
|
1140 |
request.ContentLength = expected; |
1141 |
|
1142 |
try |
1143 |
{ |
1144 |
using (var requestStream = request.GetRequestStream()) |
1145 |
{ |
1146 |
#if DEBUG |
1147 |
var actual = WriteMultiPartImpl( |
1148 |
true /* write */, parameters, boundary, encoding, requestStream |
1149 |
); |
1150 |
|
1151 |
Debug.Assert(expected == actual, string.Format("Expected {0} bytes but wrote {1}!", expected, actual)); |
1152 |
#else |
1153 |
WriteMultiPartImpl( |
1154 |
true /* write */, parameters, boundary, encoding, requestStream |
1155 |
); |
1156 |
#endif |
1157 |
|
1158 |
// [DC] Avoid disposing until no longer needed to build results |
1159 |
var response = request.GetResponse(); |
1160 |
WebResponse = response; |
1161 |
|
1162 |
if (response != null) |
1163 |
{ |
1164 |
ContentStream = response.GetResponseStream(); |
1165 |
if (ContentStream != null) |
1166 |
{ |
1167 |
var args = new WebQueryResponseEventArgs(ContentStream); |
1168 |
OnQueryResponse(args); |
1169 |
} |
1170 |
} |
1171 |
|
1172 |
exception = null; |
1173 |
} |
1174 |
} |
1175 |
catch (WebException ex) |
1176 |
{ |
1177 |
exception = ex; |
1178 |
HandleWebException(ex); |
1179 |
} |
1180 |
} |
1181 |
#endif |
1182 |
|
1183 |
private static int Write(bool write, Encoding encoding, Stream requestStream, string input) |
1184 |
{ |
1185 |
var dataBytes = encoding.GetBytes(input); |
1186 |
if(write) |
1187 |
{ |
1188 |
requestStream.Write(dataBytes, 0, dataBytes.Length); |
1189 |
} |
1190 |
return dataBytes.Length; |
1191 |
} |
1192 |
|
1193 |
private static int WriteLine(bool write, Encoding encoding, Stream requestStream, string input) |
1194 |
{ |
1195 |
var sb = new StringBuilder(); |
1196 |
sb.AppendLine(input); |
1197 |
|
1198 |
var dataBytes = encoding.GetBytes(sb.ToString()); |
1199 |
if (write) |
1200 |
{ |
1201 |
requestStream.Write(dataBytes, 0, dataBytes.Length); |
1202 |
} |
1203 |
return dataBytes.Length; |
1204 |
} |
1205 |
|
1206 |
private long WriteMultiPartImpl(bool write, IEnumerable<HttpPostParameter> parameters, string boundary, Encoding encoding, Stream requestStream) |
1207 |
{ |
1208 |
Stream fs = null; |
1209 |
var header = string.Format("--{0}", boundary); |
1210 |
var footer = string.Format("--{0}--", boundary); |
1211 |
long written = 0; |
1212 |
|
1213 |
foreach (var parameter in parameters) |
1214 |
{ |
1215 |
written += WriteLine(write, encoding, requestStream, header); |
1216 |
#if TRACE |
1217 |
if(write) |
1218 |
{ |
1219 |
Trace.WriteLineIf(TraceEnabled, header); |
1220 |
} |
1221 |
#endif |
1222 |
switch (parameter.Type) |
1223 |
{ |
1224 |
case HttpPostParameterType.File: |
1225 |
{ |
1226 |
var disposition = parameter.ContentDisposition ?? "form-data"; |
1227 |
var fileMask = "Content-Disposition: " + disposition + "; name=\"{0}\"; filename=\"{1}\""; |
1228 |
var fileHeader = fileMask.FormatWith(parameter.Name, parameter.FileName); |
1229 |
var fileLine = "Content-Type: {0}".FormatWith(parameter.ContentType.ToLower()); |
1230 |
|
1231 |
written += WriteLine(write, encoding, requestStream, fileHeader); |
1232 |
written += WriteLine(write, encoding, requestStream, fileLine); |
1233 |
written += WriteLine(write, encoding, requestStream, ""); |
1234 |
#if TRACE |
1235 |
if (write) |
1236 |
{ |
1237 |
Trace.WriteLineIf(TraceEnabled, fileHeader); |
1238 |
Trace.WriteLineIf(TraceEnabled, fileLine); |
1239 |
Trace.WriteLineIf(TraceEnabled, ""); |
1240 |
Trace.WriteLineIf(TraceEnabled, "[FILE DATA]"); |
1241 |
} |
1242 |
#endif |
1243 |
|
1244 |
#if !SILVERLIGHT |
1245 |
fs = parameter.FileStream ?? new FileStream(parameter.FilePath, FileMode.Open, FileAccess.Read); |
1246 |
#else |
1247 |
if (parameter.FileStream == null) |
1248 |
{ |
1249 |
var store = IsolatedStorageFile.GetUserStoreForApplication(); |
1250 |
var stream = store.OpenFile(parameter.FilePath, FileMode.Open, FileAccess.Read); |
1251 |
parameter.FileStream = stream; |
1252 |
} |
1253 |
|
1254 |
fs = parameter.FileStream; // <-- WP7 requires a stream |
1255 |
#endif |
1256 |
{ |
1257 |
if(!write) |
1258 |
{ |
1259 |
written += fs.Length; |
1260 |
} |
1261 |
else |
1262 |
{ |
1263 |
var fileWritten = default(long); |
1264 |
using (var br = new BinaryReader(fs)) |
1265 |
{ |
1266 |
while (fileWritten < fs.Length) |
1267 |
{ |
1268 |
var buffer = br.ReadBytes(8192); |
1269 |
requestStream.Write(buffer, 0, buffer.Length); |
1270 |
written += buffer.Length; |
1271 |
fileWritten += buffer.Length; |
1272 |
|
1273 |
var args = new PostProgressEventArgs |
1274 |
{ |
1275 |
FileName = parameter.FileName, |
1276 |
BytesWritten = fileWritten, |
1277 |
TotalBytes = fs.Length |
1278 |
}; |
1279 |
OnPostProgress(args); |
1280 |
} |
1281 |
} |
1282 |
} |
1283 |
} |
1284 |
written += WriteLine(write, encoding, requestStream, ""); |
1285 |
break; |
1286 |
} |
1287 |
case HttpPostParameterType.Field: |
1288 |
{ |
1289 |
var fieldLine = "Content-Disposition: form-data; name=\"{0}\"".FormatWith(parameter.Name); |
1290 |
|
1291 |
written += WriteLine(write, encoding, requestStream, fieldLine); |
1292 |
written += WriteLine(write, encoding, requestStream, ""); |
1293 |
written += WriteLine(write, encoding, requestStream, parameter.Value); |
1294 |
#if TRACE |
1295 |
if(write) |
1296 |
{ |
1297 |
Trace.WriteLineIf(TraceEnabled, fieldLine); |
1298 |
Trace.WriteLineIf(TraceEnabled, ""); |
1299 |
Trace.WriteLineIf(TraceEnabled, parameter.Value); |
1300 |
} |
1301 |
#endif |
1302 |
break; |
1303 |
} |
1304 |
} |
1305 |
} |
1306 |
|
1307 |
written += Write(write, encoding, requestStream, footer); |
1308 |
#if TRACE |
1309 |
if(write) |
1310 |
{ |
1311 |
Trace.WriteLineIf(TraceEnabled, footer); |
1312 |
} |
1313 |
#endif |
1314 |
if(write) |
1315 |
{ |
1316 |
requestStream.Flush(); |
1317 |
requestStream.Close(); |
1318 |
if (fs != null) |
1319 |
{ |
1320 |
fs.Dispose(); |
1321 |
} |
1322 |
} |
1323 |
|
1324 |
return written; |
1325 |
} |
1326 |
|
1327 |
#if !SILVERLIGHT |
1328 |
public virtual void Request(string url, out WebException exception) |
1329 |
{ |
1330 |
switch (Method) |
1331 |
{ |
1332 |
case WebMethod.Get: |
1333 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Get, url, out exception); |
1334 |
break; |
1335 |
case WebMethod.Put: |
1336 |
ExecutePostOrPut(PostOrPut.Put, url, out exception); |
1337 |
break; |
1338 |
case WebMethod.Post: |
1339 |
ExecutePostOrPut(PostOrPut.Post, url, out exception); |
1340 |
break; |
1341 |
case WebMethod.Delete: |
1342 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Delete, url, out exception); |
1343 |
break; |
1344 |
case WebMethod.Head: |
1345 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Head, url, out exception); |
1346 |
break; |
1347 |
case WebMethod.Options: |
1348 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Options, url, out exception); |
1349 |
break; |
1350 |
default: |
1351 |
throw new NotSupportedException("Unsupported web method"); |
1352 |
} |
1353 |
} |
1354 |
|
1355 |
public virtual void Request(string url, string key, ICache cache, out WebException exception) |
1356 |
{ |
1357 |
switch (Method) |
1358 |
{ |
1359 |
case WebMethod.Get: |
1360 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Get, url, key, cache, out exception); |
1361 |
break; |
1362 |
case WebMethod.Put: |
1363 |
ExecutePostOrPut(PostOrPut.Put, url, key, cache, out exception); |
1364 |
break; |
1365 |
case WebMethod.Post: |
1366 |
ExecutePostOrPut(PostOrPut.Post, url, key, cache, out exception); |
1367 |
break; |
1368 |
case WebMethod.Delete: |
1369 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Delete, url, key, cache, out exception); |
1370 |
break; |
1371 |
case WebMethod.Head: |
1372 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Head, url, key, cache, out exception); |
1373 |
break; |
1374 |
case WebMethod.Options: |
1375 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Options, url, key, cache, out exception); |
1376 |
break; |
1377 |
default: |
1378 |
throw new NotSupportedException("Unsupported web method"); |
1379 |
} |
1380 |
} |
1381 |
|
1382 |
public virtual void Request(string url, string key, ICache cache, DateTime absoluteExpiration, out WebException exception) |
1383 |
{ |
1384 |
switch (Method) |
1385 |
{ |
1386 |
case WebMethod.Get: |
1387 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Get, url, key, cache, absoluteExpiration, out exception); |
1388 |
break; |
1389 |
case WebMethod.Put: |
1390 |
ExecutePostOrPut(PostOrPut.Put, url, key, cache, absoluteExpiration, out exception); |
1391 |
break; |
1392 |
case WebMethod.Post: |
1393 |
ExecutePostOrPut(PostOrPut.Post, url, key, cache, absoluteExpiration, out exception); |
1394 |
break; |
1395 |
case WebMethod.Delete: |
1396 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Delete, url, key, cache, absoluteExpiration, out exception); |
1397 |
break; |
1398 |
case WebMethod.Head: |
1399 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Head, url, key, cache, absoluteExpiration, out exception); |
1400 |
break; |
1401 |
case WebMethod.Options: |
1402 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Options, url, key, cache, absoluteExpiration, out exception); |
1403 |
break; |
1404 |
default: |
1405 |
throw new NotSupportedException("Unsupported web method"); |
1406 |
} |
1407 |
} |
1408 |
|
1409 |
public virtual void Request(string url, string key, ICache cache, TimeSpan slidingExpiration, out WebException exception) |
1410 |
{ |
1411 |
switch (Method) |
1412 |
{ |
1413 |
case WebMethod.Get: |
1414 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Get, url, key, cache, slidingExpiration, out exception); |
1415 |
break; |
1416 |
case WebMethod.Put: |
1417 |
ExecutePostOrPut(PostOrPut.Put, url, key, cache, slidingExpiration, out exception); |
1418 |
break; |
1419 |
case WebMethod.Post: |
1420 |
ExecutePostOrPut(PostOrPut.Post, url, key, cache, slidingExpiration, out exception); |
1421 |
break; |
1422 |
case WebMethod.Delete: |
1423 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Delete, url, key, cache, slidingExpiration, out exception); |
1424 |
break; |
1425 |
case WebMethod.Head: |
1426 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Head, url, key, cache, slidingExpiration, out exception); |
1427 |
break; |
1428 |
case WebMethod.Options: |
1429 |
ExecuteGetDeleteHeadOptions(GetDeleteHeadOptions.Options, url, key, cache, slidingExpiration, out exception); |
1430 |
break; |
1431 |
default: |
1432 |
throw new NotSupportedException("Unsupported web method"); |
1433 |
} |
1434 |
} |
1435 |
|
1436 |
public virtual void Request(string url, IEnumerable<HttpPostParameter> parameters, out WebException exception) |
1437 |
{ |
1438 |
switch (Method) |
1439 |
{ |
1440 |
case WebMethod.Put: |
1441 |
ExecutePostOrPut(PostOrPut.Put, url, parameters, out exception); |
1442 |
break; |
1443 |
case WebMethod.Post: |
1444 |
ExecutePostOrPut(PostOrPut.Post, url, parameters, out exception); |
1445 |
break; |
1446 |
default: |
1447 |
throw new NotSupportedException("Only HTTP POSTs and PUTs can use multi-part parameters"); |
1448 |
} |
1449 |
} |
1450 |
#endif |
1451 |
|
1452 |
#if !WindowsPhone |
1453 |
public virtual WebQueryAsyncResult RequestAsync(string url, object userState) |
1454 |
{ |
1455 |
UserState = userState; |
1456 |
|
1457 |
switch (Method) |
1458 |
{ |
1459 |
case WebMethod.Get: |
1460 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, userState); |
1461 |
case WebMethod.Put: |
1462 |
return ExecutePostOrPutAsync(PostOrPut.Put, url, userState); |
1463 |
case WebMethod.Post: |
1464 |
return ExecutePostOrPutAsync(PostOrPut.Post, url, userState); |
1465 |
case WebMethod.Delete: |
1466 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, userState); |
1467 |
case WebMethod.Head: |
1468 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, userState); |
1469 |
case WebMethod.Options: |
1470 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, userState); |
1471 |
default: |
1472 |
throw new NotSupportedException("Unknown web method"); |
1473 |
} |
1474 |
} |
1475 |
#else |
1476 |
public virtual void RequestAsync(string url, object userState) |
1477 |
{ |
1478 |
UserState = userState; |
1479 |
|
1480 |
switch (Method) |
1481 |
{ |
1482 |
case WebMethod.Get: |
1483 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, userState); |
1484 |
break; |
1485 |
case WebMethod.Put: |
1486 |
ExecutePostOrPutAsync(PostOrPut.Put, url, userState); |
1487 |
break; |
1488 |
case WebMethod.Post: |
1489 |
ExecutePostOrPutAsync(PostOrPut.Post, url, userState); |
1490 |
break; |
1491 |
case WebMethod.Delete: |
1492 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, userState); |
1493 |
break; |
1494 |
case WebMethod.Head: |
1495 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, userState); |
1496 |
break; |
1497 |
case WebMethod.Options: |
1498 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, userState); |
1499 |
break; |
1500 |
default: |
1501 |
throw new NotSupportedException("Unknown web method"); |
1502 |
} |
1503 |
} |
1504 |
#endif |
1505 |
|
1506 |
#if !WindowsPhone |
1507 |
public virtual WebQueryAsyncResult RequestAsync(string url, |
1508 |
string key, |
1509 |
ICache cache, |
1510 |
object userState) |
1511 |
{ |
1512 |
UserState = userState; |
1513 |
|
1514 |
switch (Method) |
1515 |
{ |
1516 |
case WebMethod.Get: |
1517 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, userState); |
1518 |
case WebMethod.Put: |
1519 |
return ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, userState); |
1520 |
case WebMethod.Post: |
1521 |
return ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, userState); |
1522 |
case WebMethod.Delete: |
1523 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, userState); |
1524 |
case WebMethod.Head: |
1525 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, userState); |
1526 |
case WebMethod.Options: |
1527 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, userState); |
1528 |
default: |
1529 |
throw new NotSupportedException( |
1530 |
"Unsupported web method: {0}".FormatWith(Method.ToUpper()) |
1531 |
); |
1532 |
} |
1533 |
} |
1534 |
#else |
1535 |
public virtual void RequestAsync(string url, |
1536 |
string key, |
1537 |
ICache cache, |
1538 |
object userState) |
1539 |
{ |
1540 |
UserState = userState; |
1541 |
|
1542 |
switch (Method) |
1543 |
{ |
1544 |
case WebMethod.Get: |
1545 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, userState); |
1546 |
break; |
1547 |
case WebMethod.Put: |
1548 |
ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, userState); |
1549 |
break; |
1550 |
case WebMethod.Post: |
1551 |
ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, userState); |
1552 |
break; |
1553 |
case WebMethod.Delete: |
1554 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, userState); |
1555 |
break; |
1556 |
case WebMethod.Head: |
1557 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, userState); |
1558 |
break; |
1559 |
case WebMethod.Options: |
1560 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, userState); |
1561 |
break; |
1562 |
default: |
1563 |
throw new NotSupportedException( |
1564 |
"Unsupported web method: {0}".FormatWith(Method.ToUpper()) |
1565 |
); |
1566 |
} |
1567 |
} |
1568 |
#endif |
1569 |
|
1570 |
#if !WindowsPhone |
1571 |
public virtual WebQueryAsyncResult RequestAsync(string url, |
1572 |
string key, |
1573 |
ICache cache, |
1574 |
DateTime absoluteExpiration, |
1575 |
object userState) |
1576 |
{ |
1577 |
UserState = userState; |
1578 |
|
1579 |
switch (Method) |
1580 |
{ |
1581 |
case WebMethod.Get: |
1582 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, absoluteExpiration, userState); |
1583 |
case WebMethod.Put: |
1584 |
return ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, absoluteExpiration, userState); |
1585 |
case WebMethod.Post: |
1586 |
return ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, absoluteExpiration, userState); |
1587 |
case WebMethod.Delete: |
1588 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, absoluteExpiration, userState); |
1589 |
default: |
1590 |
throw new NotSupportedException( |
1591 |
"Unsupported web method: {0}".FormatWith(Method.ToUpper()) |
1592 |
); |
1593 |
} |
1594 |
} |
1595 |
#else |
1596 |
public virtual void RequestAsync(string url, |
1597 |
string key, |
1598 |
ICache cache, |
1599 |
DateTime absoluteExpiration, |
1600 |
object userState) |
1601 |
{ |
1602 |
UserState = userState; |
1603 |
|
1604 |
switch (Method) |
1605 |
{ |
1606 |
case WebMethod.Get: |
1607 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, absoluteExpiration, userState); |
1608 |
break; |
1609 |
case WebMethod.Put: |
1610 |
ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, absoluteExpiration, userState); |
1611 |
break; |
1612 |
case WebMethod.Post: |
1613 |
ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, absoluteExpiration, userState); |
1614 |
break; |
1615 |
case WebMethod.Delete: |
1616 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, absoluteExpiration, userState); |
1617 |
break; |
1618 |
case WebMethod.Head: |
1619 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, absoluteExpiration, userState); |
1620 |
break; |
1621 |
case WebMethod.Options: |
1622 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, absoluteExpiration, userState); |
1623 |
break; |
1624 |
default: |
1625 |
throw new NotSupportedException( |
1626 |
"Unsupported web method: {0}".FormatWith(Method.ToUpper()) |
1627 |
); |
1628 |
} |
1629 |
} |
1630 |
#endif |
1631 |
|
1632 |
#if !WindowsPhone |
1633 |
public virtual WebQueryAsyncResult RequestAsync(string url, |
1634 |
string key, |
1635 |
ICache cache, |
1636 |
TimeSpan slidingExpiration, |
1637 |
object userState) |
1638 |
{ |
1639 |
UserState = userState; |
1640 |
|
1641 |
switch (Method) |
1642 |
{ |
1643 |
case WebMethod.Get: |
1644 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, slidingExpiration, userState); |
1645 |
case WebMethod.Post: |
1646 |
return ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, slidingExpiration, userState); |
1647 |
case WebMethod.Put: |
1648 |
return ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, slidingExpiration, userState); |
1649 |
case WebMethod.Delete: |
1650 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, slidingExpiration, userState); |
1651 |
case WebMethod.Head: |
1652 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, slidingExpiration, userState); |
1653 |
case WebMethod.Options: |
1654 |
return ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, slidingExpiration, userState); |
1655 |
default: |
1656 |
throw new NotSupportedException( |
1657 |
"Unsupported web method: {0}".FormatWith(Method.ToUpper()) |
1658 |
); |
1659 |
} |
1660 |
} |
1661 |
#else |
1662 |
public virtual void RequestAsync(string url, |
1663 |
string key, |
1664 |
ICache cache, |
1665 |
TimeSpan slidingExpiration, |
1666 |
object userState) |
1667 |
{ |
1668 |
UserState = userState; |
1669 |
|
1670 |
switch (Method) |
1671 |
{ |
1672 |
case WebMethod.Get: |
1673 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Get, url, key, cache, slidingExpiration, userState); |
1674 |
break; |
1675 |
case WebMethod.Post: |
1676 |
ExecutePostOrPutAsync(PostOrPut.Post, url, key, cache, slidingExpiration, userState); |
1677 |
break; |
1678 |
case WebMethod.Put: |
1679 |
ExecutePostOrPutAsync(PostOrPut.Put, url, key, cache, slidingExpiration, userState); |
1680 |
break; |
1681 |
case WebMethod.Delete: |
1682 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Delete, url, key, cache, slidingExpiration, userState); |
1683 |
break; |
1684 |
case WebMethod.Head: |
1685 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Head, url, key, cache, slidingExpiration, userState); |
1686 |
break; |
1687 |
case WebMethod.Options: |
1688 |
ExecuteGetOrDeleteAsync(GetDeleteHeadOptions.Options, url, key, cache, slidingExpiration, userState); |
1689 |
break; |
1690 |
default: |
1691 |
throw new NotSupportedException( |
1692 |
"Unsupported web method: {0}".FormatWith(Method.ToUpper()) |
1693 |
); |
1694 |
} |
1695 |
} |
1696 |
#endif |
1697 |
|
1698 |
#if !WindowsPhone |
1699 |
public virtual WebQueryAsyncResult RequestAsync(string url, |
1700 |
IEnumerable<HttpPostParameter> parameters, |
1701 |
object userState) |
1702 |
{ |
1703 |
UserState = userState; |
1704 |
|
1705 |
switch (Method) |
1706 |
{ |
1707 |
case WebMethod.Put: |
1708 |
return ExecutePostOrPutAsync(PostOrPut.Put, url, parameters, userState); |
1709 |
case WebMethod.Post: |
1710 |
return ExecutePostOrPutAsync(PostOrPut.Post, url, parameters, userState); |
1711 |
default: |
1712 |
throw new NotSupportedException("Only HTTP POSTS can use multi-part forms"); |
1713 |
} |
1714 |
} |
1715 |
#else |
1716 |
public virtual void RequestAsync(string url, |
1717 |
IEnumerable<HttpPostParameter> parameters, |
1718 |
object userState) |
1719 |
{ |
1720 |
UserState = userState; |
1721 |
|
1722 |
switch (Method) |
1723 |
{ |
1724 |
case WebMethod.Put: |
1725 |
ExecutePostOrPutAsync(PostOrPut.Put, url, parameters, userState); |
1726 |
break; |
1727 |
case WebMethod.Post: |
1728 |
ExecutePostOrPutAsync(PostOrPut.Post, url, parameters, userState); |
1729 |
break; |
1730 |
default: |
1731 |
throw new NotSupportedException("Only HTTP POSTS can use multi-part forms"); |
1732 |
} |
1733 |
} |
1734 |
#endif |
1735 |
|
1736 |
#if !SILVERLIGHT |
1737 |
public virtual void ExecutePostOrPut(PostOrPut method, |
1738 |
string url, |
1739 |
string key, |
1740 |
ICache cache, |
1741 |
out WebException exception) |
1742 |
{ |
1743 |
WebException ex = null; |
1744 |
ExecuteWithCache(cache, url, key, (c, u) => ExecutePostOrPut(method, cache, url, key, out ex)); |
1745 |
exception = ex; |
1746 |
} |
1747 |
|
1748 |
public virtual void ExecutePostOrPut(PostOrPut method, string url, string key, ICache cache, DateTime absoluteExpiration, out WebException exception) |
1749 |
{ |
1750 |
WebException ex = null; |
1751 |
ExecuteWithCacheAndAbsoluteExpiration(cache, url, key, absoluteExpiration, |
1752 |
(c, u, e) => |
1753 |
ExecutePostOrPut(method, cache, url, key, absoluteExpiration, out ex)); |
1754 |
exception = ex; |
1755 |
} |
1756 |
|
1757 |
public virtual void ExecutePostOrPut(PostOrPut method, string url, string key, ICache cache, TimeSpan slidingExpiration, out WebException exception) |
1758 |
{ |
1759 |
WebException ex = null; |
1760 |
ExecuteWithCacheAndSlidingExpiration(cache, url, key, slidingExpiration, |
1761 |
(c, u, e) => |
1762 |
ExecutePostOrPut(method, cache, url, key, slidingExpiration, out ex)); |
1763 |
exception = ex; |
1764 |
} |
1765 |
|
1766 |
private void ExecutePostOrPut(PostOrPut method, |
1767 |
ICache cache, |
1768 |
string url, |
1769 |
string key, |
1770 |
out WebException exception) |
1771 |
{ |
1772 |
ExecutePostOrPut(method, url, out exception); |
1773 |
if (exception == null) |
1774 |
{ |
1775 |
cache.Insert(CreateCacheKey(key, url), ContentStream); |
1776 |
} |
1777 |
} |
1778 |
|
1779 |
private void ExecutePostOrPut(PostOrPut method, |
1780 |
ICache cache, |
1781 |
string url, |
1782 |
string key, |
1783 |
DateTime absoluteExpiration, |
1784 |
out WebException exception) |
1785 |
{ |
1786 |
ExecutePostOrPut(method, url, out exception); |
1787 |
if (exception == null) |
1788 |
{ |
1789 |
cache.Insert(CreateCacheKey(key, url), ContentStream, absoluteExpiration); |
1790 |
} |
1791 |
} |
1792 |
|
1793 |
private void ExecutePostOrPut(PostOrPut method, ICache cache, string url, string key, |
1794 |
TimeSpan slidingExpiration, out WebException exception) |
1795 |
{ |
1796 |
ExecutePostOrPut(method, url, out exception); |
1797 |
if (exception == null) |
1798 |
{ |
1799 |
cache.Insert(CreateCacheKey(key, url), ContentStream, slidingExpiration); |
1800 |
} |
1801 |
} |
1802 |
#endif |
1803 |
|
1804 |
public void Dispose() |
1805 |
{ |
1806 |
if(ContentStream != null) |
1807 |
{ |
1808 |
ContentStream.Dispose(); |
1809 |
} |
1810 |
} |
1811 |
} |
1812 |
|
1813 |
internal class PostProgressEventArgs : EventArgs |
1814 |
{ |
1815 |
public virtual string FileName { get; set; } |
1816 |
public virtual long BytesWritten { get; set; } |
1817 |
public virtual long TotalBytes { get; set; } |
1818 |
} |
1819 |
} |