1 //------------------------------------------------------------------------------
2 // <copyright file="ClientProtocol.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System
.Web
.Services
.Protocols
{
9 using System
.Collections
;
10 using System
.Diagnostics
;
11 using System
.ComponentModel
;
13 using System
.Reflection
;
14 using System
.Xml
.Serialization
;
16 using System
.Net
.Cache
;
17 using System
.Threading
;
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) {
33 if (cache
[key
] == value) return;
34 Hashtable clone
= new Hashtable();
35 foreach (object k
in cache
.Keys
) {
36 clone
.Add(k
, cache
[k
]);
44 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol"]/*' />
47 /// Specifies the base class for all web service protocol client proxies that
48 /// use the HTTP protocol.
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
;
64 private string connectionGroupName
;
65 private Encoding requestEncoding
;
67 private RemoteDebugger debugger
;
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
{
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"]/*' />
90 /// <para>[To be supplied.]</para>
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
{
106 if (bypassCache
== null) {
107 bypassCache
= new RequestCachePolicy(RequestCacheLevel
.BypassCache
);
113 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.Credentials"]/*' />
115 /// <para>[To be supplied.]</para>
117 public ICredentials Credentials
{
126 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.UseDefaultCredentials"]/*' />
128 /// <para>Sets Credentials to CredentialCache.DefaultCredentials</para>
130 public bool UseDefaultCredentials
{
132 return (credentials
== CredentialCache
.DefaultCredentials
) ? true : false;
135 credentials
= value ? CredentialCache
.DefaultCredentials
: null;
139 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.ConnectionGroupName"]/*' />
142 /// Gets or sets a value indicating the name of the connection group to use when making a request.
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"]/*' />
159 /// Gets or sets a value indicating whether pre-authentication is enabled.
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"]/*' />
171 /// Gets or sets the base Uri to the server to use for requests.
174 [DefaultValue(""), SettingsBindable(true), WebServicesDescription(Res
.ClientProtocolUrl
)]
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; }
193 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.RequestEncoding"]/*' />
196 /// Gets or sets the encoding used for making the request.
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"]/*' />
208 /// Gets or sets the timeout (in milliseconds) used for synchronous calls.
211 [DefaultValue(100000), SettingsBindable(true), WebServicesDescription(Res
.ClientProtocolTimeout
)]
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
;
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.
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
);
250 request
.BeginGetResponse(getResponseAsyncCallback
, asyncResult
);
252 if (!asyncResult
.IsCompleted
)
253 asyncResult
.CombineCompletedSynchronously(false);
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
;
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
);
274 static private void GetRequestStreamAsyncCallback(IAsyncResult asyncResult
) {
275 WebClientAsyncResult client
= (WebClientAsyncResult
)asyncResult
.AsyncState
;
276 client
.CombineCompletedSynchronously(asyncResult
.CompletedSynchronously
);
277 bool processingRequest
= true;
279 Stream requestStream
= client
.Request
.EndGetRequestStream(asyncResult
);
280 processingRequest
= false;
282 client
.ClientProtocol
.AsyncBufferedSerialize(client
.Request
, requestStream
, client
.InternalAsyncState
);
285 requestStream
.Close();
287 client
.Request
.BeginGetResponse(getResponseAsyncCallback
, client
);
289 catch (Exception e
) {
290 if (e
is ThreadAbortException
|| e
is StackOverflowException
|| e
is OutOfMemoryException
) {
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.
309 static private void GetResponseAsyncCallback(IAsyncResult asyncResult
) {
310 WebClientAsyncResult client
= (WebClientAsyncResult
)asyncResult
.AsyncState
;
311 client
.CombineCompletedSynchronously(asyncResult
.CompletedSynchronously
);
313 client
.Response
= client
.ClientProtocol
.GetWebResponse(client
.Request
, asyncResult
);
315 catch (Exception e
) {
316 if (e
is ThreadAbortException
|| e
is StackOverflowException
|| e
is OutOfMemoryException
) {
319 ProcessAsyncException(client
, e
, "GetResponseAsyncCallback");
320 if (client
.Response
== null)
324 ReadAsyncResponse(client
);
327 static private void ReadAsyncResponse(WebClientAsyncResult client
) {
328 if (client
.Response
.ContentLength
== 0) {
333 client
.ResponseStream
= client
.Response
.GetResponseStream();
334 ReadAsyncResponseStream(client
);
336 catch (Exception e
) {
337 if (e
is ThreadAbortException
|| e
is StackOverflowException
|| e
is OutOfMemoryException
) {
340 ProcessAsyncException(client
, e
, "ReadAsyncResponse");
344 static private void ReadAsyncResponseStream(WebClientAsyncResult client
) {
345 IAsyncResult asyncResult
;
347 byte[] buffer
= client
.Buffer
;
348 long contentLength
= client
.Response
.ContentLength
;
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
)
357 while (!ProcessAsyncResponseStreamResult(client
, asyncResult
));
360 static private bool ProcessAsyncResponseStreamResult(WebClientAsyncResult client
, IAsyncResult asyncResult
) {
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
);
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
);
385 static private void ReadResponseAsyncCallback(IAsyncResult asyncResult
) {
386 WebClientAsyncResult client
= (WebClientAsyncResult
)asyncResult
.AsyncState
;
387 client
.CombineCompletedSynchronously(asyncResult
.CompletedSynchronously
);
388 if (asyncResult
.CompletedSynchronously
)
391 bool complete
= ProcessAsyncResponseStreamResult(client
, asyncResult
);
393 ReadAsyncResponseStream(client
);
395 catch (Exception e
) {
396 if (e
is ThreadAbortException
|| e
is StackOverflowException
|| e
is OutOfMemoryException
) {
399 ProcessAsyncException(client
, e
, "ReadResponseAsyncCallback");
403 internal void NotifyClientCallOut(WebRequest request
) {
405 if (RemoteDebugger
.IsClientCallOutEnabled()) {
406 debugger
= new RemoteDebugger();
407 debugger
.NotifyClientCallOut(request
);
415 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.GetWebRequest"]/*' />
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.
424 protected virtual WebRequest
GetWebRequest(Uri uri
) {
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
;
437 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.GetWebResponse"]/*' />
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.
445 protected virtual WebResponse
GetWebResponse(WebRequest request
) {
446 TraceMethod caller
= Tracing
.On
? new TraceMethod(this, "GetWebResponse") : null;
447 WebResponse response
= null;
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)
457 if (Tracing
.On
) Tracing
.ExceptionCatch(TraceEventType
.Error
, this, "GetWebResponse", e
);
458 response
= e
.Response
;
463 if (debugger
!= null)
464 debugger
.NotifyClientCallReturn(response
);
470 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.GetWebResponse1"]/*' />
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.
479 protected virtual WebResponse
GetWebResponse(WebRequest request
, IAsyncResult result
) {
480 WebResponse response
= request
.EndGetResponse(result
);
482 if (response
!= null && debugger
!= null)
483 debugger
.NotifyClientCallReturn(response
);
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
496 [PermissionSet(SecurityAction
.InheritanceDemand
, Name
= "FullTrust")]
497 internal virtual void InitializeAsyncRequest(WebRequest request
, object internalAsyncState
) {
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
;
519 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.GetFromCache"]/*' />
521 /// Returns an instance of a client protocol handler from the cache.
523 protected static object GetFromCache(Type type
) {
527 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="WebClientProtocol.AddToCache"]/*' />
530 /// Add an instance of the client protocol handler to the cache.
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
,
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
{
580 bool savedIsCompleted
= isCompleted
;
581 if (manualResetEvent
== null) {
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
;
609 internal void Complete() {
610 Debug
.Assert(!isCompleted
, "Complete called more than once.");
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
) {
625 if (this.Exception
== null)
627 if (Tracing
.On
) Tracing
.ExceptionCatch(TraceEventType
.Error
, this, "Complete", e
);
633 if (manualResetEvent
!= null)
634 manualResetEvent
.Set();
636 catch (Exception e
) {
637 if (e
is ThreadAbortException
|| e
is StackOverflowException
|| e
is OutOfMemoryException
) {
640 if (this.Exception
== null)
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)
652 internal void Complete(Exception e
) {
657 internal WebResponse
WaitForResponse() {
659 AsyncWaitHandle
.WaitOne();
661 if (this.Exception
!= null)
662 throw this.Exception
;
667 internal void CombineCompletedSynchronously(bool innerCompletedSynchronously
) {
668 completedSynchronously
= completedSynchronously
&& innerCompletedSynchronously
;
672 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="InvokeCompletedEventHandler"]/*' />
674 /// <para>[To be supplied.]</para>
676 public delegate void InvokeCompletedEventHandler(object sender
, InvokeCompletedEventArgs e
);
678 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="InvokeCompletedEventArgs"]/*' />
680 /// <para>[To be supplied.]</para>
682 public class InvokeCompletedEventArgs
: AsyncCompletedEventArgs
{
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"]/*' />
693 /// Gets or sets a value indicating whether the client should automatically follow server redirects.
696 public object[] Results
{
704 internal class UserToken
{
705 SendOrPostCallback callback
;
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"]/*' />
718 /// <para>[To be supplied.]</para>
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"]/*' />
733 /// <para>[To be supplied.]</para>
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
)
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"]/*' />
759 /// Gets or sets a value indicating whether the client should automatically follow server redirects.
762 [DefaultValue(false), WebServicesDescription(Res
.ClientProtocolAllowAutoRedirect
)]
763 public bool AllowAutoRedirect
{
765 return allowAutoRedirect
;
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
{
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
{
789 if (clientCertificates
== null) {
790 clientCertificates
= new X509CertificateCollection();
792 return clientCertificates
;
796 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.EnableDecompression"]/*' />
799 /// Gets or sets a value indicating whether the client should automatically follow server redirects.
802 [DefaultValue(false), WebServicesDescription(Res
.ClientProtocolEnableDecompression
)]
803 public bool EnableDecompression
{
805 return enableDecompression
;
809 enableDecompression
= value;
813 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.UserAgent"]/*' />
816 /// Gets or sets the value for the user agent header that is
817 /// sent with each request.
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"]/*' />
829 /// Gets or sets the name of the proxy server to use for requests.
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"]/*' />
840 /// <para>[To be supplied.]</para>
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).
857 httpRequest
.Proxy
= proxy
;
859 if (clientCertificates
!= null && clientCertificates
.Count
> 0) {
860 httpRequest
.ClientCertificates
.AddRange(clientCertificates
);
862 httpRequest
.CookieContainer
= cookieJar
;
867 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.GetWebResponse"]/*' />
869 /// <para>[To be supplied.]</para>
871 protected override WebResponse
GetWebResponse(WebRequest request
) {
872 WebResponse response
= base.GetWebResponse(request
);
876 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.GetWebResponse1"]/*' />
878 /// <para>[To be supplied.]</para>
880 protected override WebResponse
GetWebResponse(WebRequest request
, IAsyncResult result
) {
881 WebResponse response
= base.GetWebResponse(request
, result
);
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"]/*' />
894 /// <para>[To be supplied.]</para>
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) {
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
);
918 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.GenerateXmlMappings"]/*' />
920 /// <para>[To be supplied.]</para>
922 public static bool GenerateXmlMappings(Type type
, ArrayList mappings
) {
923 if (typeof(SoapHttpClientProtocol
).IsAssignableFrom(type
)) {
924 WebServiceBindingAttribute binding
= WebServiceBindingReflector
.GetAttribute(type
);
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
);
938 /// <include file='doc\ClientProtocol.uex' path='docs/doc[@for="HttpWebClientProtocol.GenerateXmlMappings1"]/*' />
940 /// <para>[To be supplied.]</para>
942 public static Hashtable
GenerateXmlMappings(Type
[] types
, ArrayList mappings
) {
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
);