Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Web.Services / System / Web / Services / Protocols / ClientProtocol.cs
blobf06508a76d328dd0966db9245e8c84defa4e9183
1 //------------------------------------------------------------------------------
2 // <copyright file="ClientProtocol.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
7 namespace System.Web.Services.Protocols {
8 using System;
9 using System.Collections;
10 using System.Diagnostics;
11 using System.ComponentModel;
12 using System.IO;
13 using System.Reflection;
14 using System.Xml.Serialization;
15 using System.Net;
16 using System.Net.Cache;
17 using System.Threading;
18 using System.Text;
19 using System.Security.Cryptography.X509Certificates;
20 using System.Security.Permissions;
21 using System.Runtime.InteropServices;
22 using System.Web.Services.Diagnostics;
24 internal class ClientTypeCache {
25 Hashtable cache = new Hashtable();
27 internal object this[Type key] {
28 get { return cache[key]; }
31 internal void Add(Type key, object value) {
32 lock (this) {
33 if (cache[key] == value) return;
34 Hashtable clone = new Hashtable();
35 foreach (object k in cache.Keys) {
36 clone.Add(k, cache[k]);
38 cache = clone;
39 cache[key] = value;
44 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol"]/*' />
45 /// <devdoc>
46 /// <para>
47 /// Specifies the base class for all web service protocol client proxies that
48 /// use the HTTP protocol.
49 /// </para>
50 /// </devdoc>
51 [ComVisible(true)]
52 public abstract class WebClientProtocol : Component {
53 static AsyncCallback getRequestStreamAsyncCallback;
54 static AsyncCallback getResponseAsyncCallback;
56 // Double-checked locking pattern requires volatile for read/write synchronization
57 static volatile AsyncCallback readResponseAsyncCallback;
58 private static ClientTypeCache cache;
59 private static RequestCachePolicy bypassCache;
60 private ICredentials credentials;
61 private bool preAuthenticate;
62 private Uri uri;
63 private int timeout;
64 private string connectionGroupName;
65 private Encoding requestEncoding;
66 #if !MONO
67 private RemoteDebugger debugger;
68 #endif
69 private WebRequest pendingSyncRequest;
70 object nullToken = new object();
71 Hashtable asyncInvokes = Hashtable.Synchronized(new Hashtable());
73 private static Object s_InternalSyncObject;
74 internal static Object InternalSyncObject {
75 get {
76 if (s_InternalSyncObject == null) {
77 Object o = new Object();
78 Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
80 return s_InternalSyncObject;
84 static WebClientProtocol() {
85 cache = new ClientTypeCache();
88 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.WebClientProtocol"]/*' />
89 /// <devdoc>
90 /// <para>[To be supplied.]</para>
91 /// </devdoc>
92 protected WebClientProtocol() {
93 this.timeout = 100000; // should be kept in sync with HttpWebRequest.Timeout default (see private WebRequest.DefaultTimeout)
96 internal WebClientProtocol(WebClientProtocol protocol) {
97 this.credentials = protocol.credentials;
98 this.uri = protocol.uri;
99 this.timeout = protocol.timeout;
100 this.connectionGroupName = protocol.connectionGroupName;
101 this.requestEncoding = protocol.requestEncoding;
104 internal static RequestCachePolicy BypassCache {
105 get {
106 if (bypassCache == null) {
107 bypassCache = new RequestCachePolicy(RequestCacheLevel.BypassCache);
109 return bypassCache;
113 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.Credentials"]/*' />
114 /// <devdoc>
115 /// <para>[To be supplied.]</para>
116 /// </devdoc>
117 public ICredentials Credentials {
118 get {
119 return credentials;
121 set {
122 credentials = value;
126 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.UseDefaultCredentials"]/*' />
127 /// <devdoc>
128 /// <para>Sets Credentials to CredentialCache.DefaultCredentials</para>
129 /// </devdoc>
130 public bool UseDefaultCredentials {
131 get {
132 return (credentials == CredentialCache.DefaultCredentials) ? true : false;
134 set {
135 credentials = value ? CredentialCache.DefaultCredentials : null;
139 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.ConnectionGroupName"]/*' />
140 /// <devdoc>
141 /// <para>
142 /// Gets or sets a value indicating the name of the connection group to use when making a request.
143 /// </para>
144 /// </devdoc>
145 [DefaultValue("")]
146 public string ConnectionGroupName {
147 get { return (connectionGroupName == null) ? string.Empty : connectionGroupName; }
148 set { connectionGroupName = value; }
151 internal WebRequest PendingSyncRequest {
152 get { return pendingSyncRequest; }
153 set { pendingSyncRequest = value; }
156 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.PreAuthenticate"]/*' />
157 /// <devdoc>
158 /// <para>
159 /// Gets or sets a value indicating whether pre-authentication is enabled.
160 /// </para>
161 /// </devdoc>
162 [DefaultValue(false), WebServicesDescription(Res.ClientProtocolPreAuthenticate)]
163 public bool PreAuthenticate {
164 get { return preAuthenticate; }
165 set { preAuthenticate = value; }
168 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.Url"]/*' />
169 /// <devdoc>
170 /// <para>
171 /// Gets or sets the base Uri to the server to use for requests.
172 /// </para>
173 /// </devdoc>
174 [DefaultValue(""), SettingsBindable(true), WebServicesDescription(Res.ClientProtocolUrl)]
175 public string Url {
176 get { return uri == null ? string.Empty : uri.ToString(); }
177 set { uri = new Uri(value); }
180 internal Hashtable AsyncInvokes {
181 get { return asyncInvokes; }
184 internal object NullToken {
185 get { return nullToken; }
188 internal Uri Uri {
189 get { return uri; }
190 set { uri = value; }
193 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.RequestEncoding"]/*' />
194 /// <devdoc>
195 /// <para>
196 /// Gets or sets the encoding used for making the request.
197 /// </para>
198 /// </devdoc>
199 [DefaultValue(null), SettingsBindable(true), WebServicesDescription(Res.ClientProtocolEncoding)]
200 public Encoding RequestEncoding {
201 get { return requestEncoding; }
202 set { requestEncoding = value; }
205 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.Timeout"]/*' />
206 /// <devdoc>
207 /// <para>
208 /// Gets or sets the timeout (in milliseconds) used for synchronous calls.
209 /// </para>
210 /// </devdoc>
211 [DefaultValue(100000), SettingsBindable(true), WebServicesDescription(Res.ClientProtocolTimeout)]
212 public int Timeout {
213 get { return timeout; }
214 set { timeout = (value < Threading.Timeout.Infinite) ? Threading.Timeout.Infinite : value; }
217 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.Abort"]/*' />
218 public virtual void Abort() {
219 WebRequest request = PendingSyncRequest;
220 if (request != null)
221 request.Abort();
224 /// <devdoc>
225 /// <para>
226 /// Starts async request processing including async retrieval of the request stream and response.
227 /// Derived classes can use BeginSend
228 /// to help implement their own higher level async methods like BeginInvoke. Derived
229 /// classes can add custom behavior by overriding GetWebRequest, GetWebResponse,
230 /// InitializeAsyncRequest and WriteAsyncRequest methods.
231 /// </para>
232 /// </devdoc>
233 internal IAsyncResult BeginSend(Uri requestUri, WebClientAsyncResult asyncResult, bool callWriteAsyncRequest) {
234 if (readResponseAsyncCallback == null) {
235 lock (InternalSyncObject) {
236 if (readResponseAsyncCallback == null) {
237 getRequestStreamAsyncCallback = new AsyncCallback(GetRequestStreamAsyncCallback);
238 getResponseAsyncCallback = new AsyncCallback(GetResponseAsyncCallback);
239 readResponseAsyncCallback = new AsyncCallback(ReadResponseAsyncCallback);
243 Debug.Assert(asyncResult.Request == null, "calling GetWebRequest twice for the same WebClientAsyncResult");
244 WebRequest request = GetWebRequest(requestUri);
245 asyncResult.Request = request;
246 InitializeAsyncRequest(request, asyncResult.InternalAsyncState);
247 if (callWriteAsyncRequest)
248 request.BeginGetRequestStream(getRequestStreamAsyncCallback, asyncResult);
249 else
250 request.BeginGetResponse(getResponseAsyncCallback, asyncResult);
252 if (!asyncResult.IsCompleted)
253 asyncResult.CombineCompletedSynchronously(false);
254 return asyncResult;
257 static private void ProcessAsyncException(WebClientAsyncResult client, Exception e, string method) {
258 if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Error, typeof(WebClientProtocol), method, e);
259 WebException webException = e as WebException;
260 if (webException != null && webException.Response != null) {
261 client.Response = webException.Response;
263 else {
264 // If we've already completed the call then the exception must have come
265 // out of the user callback in which case we need to rethrow it here
266 // so that it bubbles up to the AppDomain unhandled exception event.
267 if (client.IsCompleted)
268 throw new InvalidOperationException(Res.GetString(Res.ThereWasAnErrorDuringAsyncProcessing), e);
269 else
270 client.Complete(e);
274 static private void GetRequestStreamAsyncCallback(IAsyncResult asyncResult) {
275 WebClientAsyncResult client = (WebClientAsyncResult)asyncResult.AsyncState;
276 client.CombineCompletedSynchronously(asyncResult.CompletedSynchronously);
277 bool processingRequest = true;
278 try {
279 Stream requestStream = client.Request.EndGetRequestStream(asyncResult);
280 processingRequest = false;
281 try {
282 client.ClientProtocol.AsyncBufferedSerialize(client.Request, requestStream, client.InternalAsyncState);
284 finally {
285 requestStream.Close();
287 client.Request.BeginGetResponse(getResponseAsyncCallback, client);
289 catch (Exception e) {
290 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
291 throw;
293 ProcessAsyncException(client, e, "GetRequestStreamAsyncCallback");
294 if (processingRequest)
296 WebException we = e as WebException;
297 if (we != null && we.Response != null)
299 // ProcessAsyncExcption doesn't call client.Complete() if there's a response,
300 // because it expects us to read the response. However, in certain cases
301 // (e.g. 502 errors), the exception thrown from Request can have a response.
302 // We don't process it, so call Complete() now.
303 client.Complete(e);
309 static private void GetResponseAsyncCallback(IAsyncResult asyncResult) {
310 WebClientAsyncResult client = (WebClientAsyncResult)asyncResult.AsyncState;
311 client.CombineCompletedSynchronously(asyncResult.CompletedSynchronously);
312 try {
313 client.Response = client.ClientProtocol.GetWebResponse(client.Request, asyncResult);
315 catch (Exception e) {
316 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
317 throw;
319 ProcessAsyncException(client, e, "GetResponseAsyncCallback");
320 if (client.Response == null)
321 return;
324 ReadAsyncResponse(client);
327 static private void ReadAsyncResponse(WebClientAsyncResult client) {
328 if (client.Response.ContentLength == 0) {
329 client.Complete();
330 return;
332 try {
333 client.ResponseStream = client.Response.GetResponseStream();
334 ReadAsyncResponseStream(client);
336 catch (Exception e) {
337 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
338 throw;
340 ProcessAsyncException(client, e, "ReadAsyncResponse");
344 static private void ReadAsyncResponseStream(WebClientAsyncResult client) {
345 IAsyncResult asyncResult;
346 do {
347 byte[] buffer = client.Buffer;
348 long contentLength = client.Response.ContentLength;
349 if (buffer == null)
350 buffer = client.Buffer = new byte[(contentLength == -1) ? 1024 : contentLength];
351 else if (contentLength != -1 && contentLength > buffer.Length)
352 buffer = client.Buffer = new byte[contentLength];
353 asyncResult = client.ResponseStream.BeginRead(buffer, 0, buffer.Length, readResponseAsyncCallback, client);
354 if (!asyncResult.CompletedSynchronously)
355 return;
357 while (!ProcessAsyncResponseStreamResult(client, asyncResult));
360 static private bool ProcessAsyncResponseStreamResult(WebClientAsyncResult client, IAsyncResult asyncResult) {
361 bool complete;
362 int bytesRead = client.ResponseStream.EndRead(asyncResult);
363 long contentLength = client.Response.ContentLength;
364 if (contentLength > 0 && bytesRead == contentLength) {
365 // the non-chunked response finished in a single read
366 client.ResponseBufferedStream = new MemoryStream(client.Buffer);
367 complete = true;
369 else if (bytesRead > 0) {
370 if (client.ResponseBufferedStream == null) {
371 int capacity = (int)((contentLength == -1) ? client.Buffer.Length : contentLength);
372 client.ResponseBufferedStream = new MemoryStream(capacity);
374 client.ResponseBufferedStream.Write(client.Buffer, 0, bytesRead);
375 complete = false;
377 else
378 complete = true;
380 if (complete)
381 client.Complete();
382 return complete;
385 static private void ReadResponseAsyncCallback(IAsyncResult asyncResult) {
386 WebClientAsyncResult client = (WebClientAsyncResult)asyncResult.AsyncState;
387 client.CombineCompletedSynchronously(asyncResult.CompletedSynchronously);
388 if (asyncResult.CompletedSynchronously)
389 return;
390 try {
391 bool complete = ProcessAsyncResponseStreamResult(client, asyncResult);
392 if (!complete)
393 ReadAsyncResponseStream(client);
395 catch (Exception e) {
396 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
397 throw;
399 ProcessAsyncException(client, e, "ReadResponseAsyncCallback");
403 internal void NotifyClientCallOut(WebRequest request) {
404 #if !MONO
405 if (RemoteDebugger.IsClientCallOutEnabled()) {
406 debugger = new RemoteDebugger();
407 debugger.NotifyClientCallOut(request);
409 else {
410 debugger = null;
412 #endif
415 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.GetWebRequest"]/*' />
416 /// <devdoc>
417 /// <para>
418 /// Creates a new <see cref='System.Net.WebRequest'/> instance for the given url. The base implementation creates a new
419 /// instance using the WebRequest.Create() and then sets request related properties from
420 /// the WebClientProtocol instance. Derived classes can override this method if additional
421 /// properties need to be set on the web request instance.
422 /// </para>
423 /// </devdoc>
424 protected virtual WebRequest GetWebRequest(Uri uri) {
425 if (uri == null)
426 throw new InvalidOperationException(Res.GetString(Res.WebMissingPath));
427 WebRequest request = (WebRequest)WebRequest.Create(uri);
428 PendingSyncRequest = request;
429 request.Timeout = this.timeout;
430 request.ConnectionGroupName = connectionGroupName;
431 request.Credentials = Credentials;
432 request.PreAuthenticate = PreAuthenticate;
433 request.CachePolicy = BypassCache;
434 return request;
437 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.GetWebResponse"]/*' />
438 /// <devdoc>
439 /// <para>
440 /// Gets the <see cref='System.Net.WebResponse'/> from the given request by calling
441 /// GetResponse(). Derived classes can override this method to do additional
442 /// processing on the response instance.
443 /// </para>
444 /// </devdoc>
445 protected virtual WebResponse GetWebResponse(WebRequest request) {
446 TraceMethod caller = Tracing.On ? new TraceMethod(this, "GetWebResponse") : null;
447 WebResponse response = null;
448 try {
449 if (Tracing.On) Tracing.Enter("WebRequest.GetResponse", caller, new TraceMethod(request, "GetResponse"));
450 response = request.GetResponse();
451 if (Tracing.On) Tracing.Exit("WebRequest.GetResponse", caller);
453 catch (WebException e) {
454 if (e.Response == null)
455 throw e;
456 else {
457 if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Error, this, "GetWebResponse", e);
458 response = e.Response;
461 finally {
462 #if !MONO
463 if (debugger != null)
464 debugger.NotifyClientCallReturn(response);
465 #endif
467 return response;
470 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.GetWebResponse1"]/*' />
471 /// <devdoc>
472 /// <para>
473 /// Gets the <see cref='System.Net.WebResponse'/> from the given request by calling
474 /// EndGetResponse(). Derived classes can override this method to do additional
475 /// processing on the response instance. This method is only called during
476 /// async request processing.
477 /// </para>
478 /// </devdoc>
479 protected virtual WebResponse GetWebResponse(WebRequest request, IAsyncResult result) {
480 WebResponse response = request.EndGetResponse(result);
481 #if !MONO
482 if (response != null && debugger != null)
483 debugger.NotifyClientCallReturn(response);
484 #endif
485 return response;
488 /// <devdoc>
489 /// <para>
490 /// Called during async request processing to give the derived class an opportunity
491 /// to modify the web request instance before the request stream is retrieved at which
492 /// point the request headers are sent and can no longer be modified. The base implementation
493 /// does nothing.
494 /// </para>
495 /// </devdoc>
496 [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
497 internal virtual void InitializeAsyncRequest(WebRequest request, object internalAsyncState) {
498 return;
501 [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
502 internal virtual void AsyncBufferedSerialize(WebRequest request, Stream requestStream, object internalAsyncState) {
503 throw new NotSupportedException(Res.GetString(Res.ProtocolDoesNotAsyncSerialize));
506 internal WebResponse EndSend(IAsyncResult asyncResult, ref object internalAsyncState, ref Stream responseStream) {
507 if (asyncResult == null) throw new ArgumentNullException(Res.GetString(Res.WebNullAsyncResultInEnd));
509 WebClientAsyncResult client = (WebClientAsyncResult)asyncResult;
510 if (client.EndSendCalled)
511 throw new InvalidOperationException(Res.GetString(Res.CanTCallTheEndMethodOfAnAsyncCallMoreThan));
512 client.EndSendCalled = true;
513 WebResponse response = client.WaitForResponse();
514 internalAsyncState = client.InternalAsyncState;
515 responseStream = client.ResponseBufferedStream;
516 return response;
519 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.GetFromCache"]/*' />
520 /// <devdoc>
521 /// Returns an instance of a client protocol handler from the cache.
522 /// </devdoc>
523 protected static object GetFromCache(Type type) {
524 return cache[type];
527 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.AddToCache"]/*' />
528 /// <devdoc>
529 /// <para>
530 /// Add an instance of the client protocol handler to the cache.
531 /// </para>
532 /// </devdoc>
533 protected static void AddToCache(Type type, object value) {
534 cache.Add(type, value);
539 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientAsyncResult"]/*' />
540 [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
541 public class WebClientAsyncResult : IAsyncResult {
542 private object userAsyncState;
543 private bool completedSynchronously;
544 private bool isCompleted;
546 // Double-checked locking pattern requires volatile for read/write synchronization
547 private volatile ManualResetEvent manualResetEvent;
548 private AsyncCallback userCallback;
550 internal WebClientProtocol ClientProtocol;
551 internal object InternalAsyncState;
552 internal Exception Exception;
553 internal WebResponse Response;
554 internal WebRequest Request;
555 internal Stream ResponseStream;
556 internal Stream ResponseBufferedStream;
557 internal byte[] Buffer;
558 internal bool EndSendCalled;
560 internal WebClientAsyncResult(WebClientProtocol clientProtocol,
561 object internalAsyncState,
562 WebRequest request,
563 AsyncCallback userCallback,
564 object userAsyncState)
566 this.ClientProtocol = clientProtocol;
567 this.InternalAsyncState = internalAsyncState;
568 this.userAsyncState = userAsyncState;
569 this.userCallback = userCallback;
570 this.Request = request;
571 this.completedSynchronously = true;
574 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientAsyncResult.AsyncState"]/*' />
575 public object AsyncState { get { return userAsyncState; } }
577 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientAsyncResult.AsyncWaitHandle"]/*' />
578 public WaitHandle AsyncWaitHandle {
579 get {
580 bool savedIsCompleted = isCompleted;
581 if (manualResetEvent == null) {
582 lock (this) {
583 if (manualResetEvent == null)
584 manualResetEvent = new ManualResetEvent(savedIsCompleted);
587 if (!savedIsCompleted && isCompleted)
588 manualResetEvent.Set();
589 return (WaitHandle)manualResetEvent;
593 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientAsyncResult.CompletedSynchronously"]/*' />
594 public bool CompletedSynchronously {
595 get { return completedSynchronously; }
598 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientAsyncResult.IsCompleted"]/*' />
599 public bool IsCompleted { get { return isCompleted; } }
601 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientAsyncResult.Abort"]/*' />
602 public void Abort() {
603 WebRequest req = Request;
604 if (req != null)
605 req.Abort();
609 internal void Complete() {
610 Debug.Assert(!isCompleted, "Complete called more than once.");
612 try {
613 if (ResponseStream != null) {
614 ResponseStream.Close();
615 ResponseStream = null;
618 if (ResponseBufferedStream != null)
619 ResponseBufferedStream.Position = 0;
621 catch (Exception e) {
622 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
623 throw;
625 if (this.Exception == null)
626 this.Exception = e;
627 if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Error, this, "Complete", e);
630 isCompleted = true;
632 try {
633 if (manualResetEvent != null)
634 manualResetEvent.Set();
636 catch (Exception e) {
637 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
638 throw;
640 if (this.Exception == null)
641 this.Exception = e;
642 if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Error, this, "Complete", e);
645 // We want to let exceptions in user callback to bubble up to
646 // threadpool so that AppDomain.UnhandledExceptionEventHandler
647 // will get it if one is registered
648 if (userCallback != null)
649 userCallback(this);
652 internal void Complete(Exception e) {
653 this.Exception = e;
654 Complete();
657 internal WebResponse WaitForResponse() {
658 if (!isCompleted)
659 AsyncWaitHandle.WaitOne();
661 if (this.Exception != null)
662 throw this.Exception;
664 return Response;
667 internal void CombineCompletedSynchronously(bool innerCompletedSynchronously) {
668 completedSynchronously = completedSynchronously && innerCompletedSynchronously;
672 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="InvokeCompletedEventHandler"]/*' />
673 /// <devdoc>
674 /// <para>[To be supplied.]</para>
675 /// </devdoc>
676 public delegate void InvokeCompletedEventHandler(object sender, InvokeCompletedEventArgs e);
678 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="InvokeCompletedEventArgs"]/*' />
679 /// <devdoc>
680 /// <para>[To be supplied.]</para>
681 /// </devdoc>
682 public class InvokeCompletedEventArgs : AsyncCompletedEventArgs {
683 object[] results;
685 internal InvokeCompletedEventArgs(object[] results, Exception exception, bool cancelled, object userState) :
686 base(exception, cancelled, userState) {
687 this.results = results;
690 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="InvokeCompletedEventArgs.Results"]/*' />
691 /// <devdoc>
692 /// <para>
693 /// Gets or sets a value indicating whether the client should automatically follow server redirects.
694 /// </para>
695 /// </devdoc>
696 public object[] Results {
697 get {
698 return results;
704 internal class UserToken {
705 SendOrPostCallback callback;
706 object userState;
708 internal UserToken(SendOrPostCallback callback, object userState) {
709 this.callback = callback;
710 this.userState = userState;
712 internal SendOrPostCallback Callback { get { return callback; } }
713 internal object UserState { get { return userState; } }
716 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol"]/*' />
717 /// <devdoc>
718 /// <para>[To be supplied.]</para>
719 /// </devdoc>
720 [ComVisible(true)]
721 public abstract class HttpWebClientProtocol : WebClientProtocol {
722 private bool allowAutoRedirect;
723 private bool enableDecompression = false;
724 private CookieContainer cookieJar = null;
725 private X509CertificateCollection clientCertificates;
726 private IWebProxy proxy;
727 private static string UserAgentDefault = "Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol " + System.Environment.Version.ToString() + ")";
728 private string userAgent;
729 private bool unsafeAuthenticatedConnectionSharing;
731 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.HttpWebClientProtocol"]/*' />
732 /// <devdoc>
733 /// <para>[To be supplied.]</para>
734 /// </devdoc>
735 protected HttpWebClientProtocol() : base() {
736 this.allowAutoRedirect = false;
737 this.userAgent = UserAgentDefault;
738 // the right thing to do, for NetClasses to pick up the default
739 // GlobalProxySelection settings, is to leave proxy to null
740 // (which is the default initialization value)
741 // rather than picking up GlobalProxySelection.Select
742 // which will never change.
745 // used by SoapHttpClientProtocol.Discover
746 internal HttpWebClientProtocol(HttpWebClientProtocol protocol)
747 : base(protocol) {
748 this.allowAutoRedirect = protocol.allowAutoRedirect;
749 this.enableDecompression = protocol.enableDecompression;
750 this.cookieJar = protocol.cookieJar;
751 this.clientCertificates = protocol.clientCertificates;
752 this.proxy = protocol.proxy;
753 this.userAgent = protocol.userAgent;
756 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.AllowAutoRedirect"]/*' />
757 /// <devdoc>
758 /// <para>
759 /// Gets or sets a value indicating whether the client should automatically follow server redirects.
760 /// </para>
761 /// </devdoc>
762 [DefaultValue(false), WebServicesDescription(Res.ClientProtocolAllowAutoRedirect)]
763 public bool AllowAutoRedirect {
764 get {
765 return allowAutoRedirect;
768 set {
769 allowAutoRedirect = value;
774 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.CookieContainer"]/*' />
775 [DefaultValue(null), WebServicesDescription(Res.ClientProtocolCookieContainer)]
776 public CookieContainer CookieContainer {
777 get {
778 return cookieJar;
780 set {
781 cookieJar = value;
785 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.ClientCertificates"]/*' />
786 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebServicesDescription(Res.ClientProtocolClientCertificates)]
787 public X509CertificateCollection ClientCertificates {
788 get {
789 if (clientCertificates == null) {
790 clientCertificates = new X509CertificateCollection();
792 return clientCertificates;
796 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.EnableDecompression"]/*' />
797 /// <devdoc>
798 /// <para>
799 /// Gets or sets a value indicating whether the client should automatically follow server redirects.
800 /// </para>
801 /// </devdoc>
802 [DefaultValue(false), WebServicesDescription(Res.ClientProtocolEnableDecompression)]
803 public bool EnableDecompression {
804 get {
805 return enableDecompression;
808 set {
809 enableDecompression = value;
813 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.UserAgent"]/*' />
814 /// <devdoc>
815 /// <para>
816 /// Gets or sets the value for the user agent header that is
817 /// sent with each request.
818 /// </para>
819 /// </devdoc>
820 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), WebServicesDescription(Res.ClientProtocolUserAgent)]
821 public string UserAgent {
822 get { return (userAgent == null) ? string.Empty : userAgent; }
823 set { userAgent = value; }
826 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.Proxy"]/*' />
827 /// <devdoc>
828 /// <para>
829 /// Gets or sets the name of the proxy server to use for requests.
830 /// </para>
831 /// </devdoc>
832 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
833 public IWebProxy Proxy {
834 get { return proxy; }
835 set { proxy = value; }
838 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.GetWebRequest"]/*' />
839 /// <devdoc>
840 /// <para>[To be supplied.]</para>
841 /// </devdoc>
842 protected override WebRequest GetWebRequest(Uri uri) {
843 WebRequest request = base.GetWebRequest(uri);
844 HttpWebRequest httpRequest = request as HttpWebRequest;
845 if (httpRequest != null) {
846 httpRequest.UserAgent = UserAgent;
847 httpRequest.AllowAutoRedirect = allowAutoRedirect;
848 httpRequest.AutomaticDecompression = enableDecompression ? DecompressionMethods.GZip : DecompressionMethods.None;
849 httpRequest.AllowWriteStreamBuffering = true;
850 httpRequest.SendChunked = false;
851 if (unsafeAuthenticatedConnectionSharing != httpRequest.UnsafeAuthenticatedConnectionSharing)
852 httpRequest.UnsafeAuthenticatedConnectionSharing = unsafeAuthenticatedConnectionSharing;
853 // if the user has set a proxy explictly then we need to
854 // propagate that to the WebRequest, otherwise we'll let NetClasses
855 // use their global setting (GlobalProxySelection.Select).
856 if (proxy != null) {
857 httpRequest.Proxy = proxy;
859 if (clientCertificates != null && clientCertificates.Count > 0) {
860 httpRequest.ClientCertificates.AddRange(clientCertificates);
862 httpRequest.CookieContainer = cookieJar;
864 return request;
867 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.GetWebResponse"]/*' />
868 /// <devdoc>
869 /// <para>[To be supplied.]</para>
870 /// </devdoc>
871 protected override WebResponse GetWebResponse(WebRequest request) {
872 WebResponse response = base.GetWebResponse(request);
873 return response;
876 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.GetWebResponse1"]/*' />
877 /// <devdoc>
878 /// <para>[To be supplied.]</para>
879 /// </devdoc>
880 protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result) {
881 WebResponse response = base.GetWebResponse(request, result);
882 return response;
885 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.UnsafeAuthenticatedConnectionSharing"]/*' />
886 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
887 public bool UnsafeAuthenticatedConnectionSharing {
888 get { return unsafeAuthenticatedConnectionSharing; }
889 set { unsafeAuthenticatedConnectionSharing = value; }
892 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="ClientProtocol.CancelInvokeAsync"]/*' />
893 /// <devdoc>
894 /// <para>[To be supplied.]</para>
895 /// </devdoc>
896 protected void CancelAsync(object userState) {
897 if (userState == null)
898 userState = NullToken;
899 WebClientAsyncResult result = OperationCompleted(userState, new object[] { null }, null, true);
900 if (result != null) {
901 result.Abort();
905 internal WebClientAsyncResult OperationCompleted(object userState, object[] parameters, Exception e, bool canceled) {
906 Debug.Assert(userState != null, "We should not call OperationCompleted with null user token.");
907 WebClientAsyncResult result = (WebClientAsyncResult)AsyncInvokes[userState];
908 if (result != null) {
909 AsyncOperation asyncOp = (AsyncOperation)result.AsyncState;
910 UserToken token = (UserToken)asyncOp.UserSuppliedState;
911 InvokeCompletedEventArgs eventArgs = new InvokeCompletedEventArgs(parameters, e, canceled, userState);
912 AsyncInvokes.Remove(userState);
913 asyncOp.PostOperationCompleted(token.Callback, eventArgs);
915 return result;
918 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.GenerateXmlMappings"]/*' />
919 /// <devdoc>
920 /// <para>[To be supplied.]</para>
921 /// </devdoc>
922 public static bool GenerateXmlMappings(Type type, ArrayList mappings) {
923 if (typeof(SoapHttpClientProtocol).IsAssignableFrom(type)) {
924 WebServiceBindingAttribute binding = WebServiceBindingReflector.GetAttribute(type);
925 if (binding == null)
926 throw new InvalidOperationException(Res.GetString(Res.WebClientBindingAttributeRequired));
927 // Note: Service namespace is taken from WebserviceBindingAttribute and not WebserviceAttribute because
928 // the generated proxy does not have a WebServiceAttribute; however all have a WebServiceBindingAttribute.
929 string serviceNamespace = binding.Namespace;
930 bool serviceDefaultIsEncoded = SoapReflector.ServiceDefaultIsEncoded(type);
931 ArrayList soapMethodList = new ArrayList();
932 SoapClientType.GenerateXmlMappings(type, soapMethodList, serviceNamespace, serviceDefaultIsEncoded, mappings);
933 return true;
935 return false;
938 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.GenerateXmlMappings1"]/*' />
939 /// <devdoc>
940 /// <para>[To be supplied.]</para>
941 /// </devdoc>
942 public static Hashtable GenerateXmlMappings(Type[] types, ArrayList mappings) {
943 if (types == null)
944 throw new ArgumentNullException("types");
946 Hashtable mappedTypes = new Hashtable();
947 foreach (Type type in types) {
948 ArrayList typeMappings = new ArrayList();
949 if (GenerateXmlMappings(type, mappings)) {
950 mappedTypes.Add(type, typeMappings);
951 mappings.Add(typeMappings);
954 return mappedTypes;