1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 
5 namespace System.ServiceModel.Channels
6 {
7     using System.Collections.Generic;
8     using System.Runtime;
9     using System.ServiceModel;
10 
11     class ReplyChannel : InputQueueChannel<RequestContext>, IReplyChannel
12     {
13         EndpointAddress localAddress;
14 
ReplyChannel(ChannelManagerBase channelManager, EndpointAddress localAddress)15         public ReplyChannel(ChannelManagerBase channelManager, EndpointAddress localAddress)
16             : base(channelManager)
17         {
18             this.localAddress = localAddress;
19         }
20 
21         public EndpointAddress LocalAddress
22         {
23             get { return localAddress; }
24         }
25 
GetProperty()26         public override T GetProperty<T>()
27         {
28             if (typeof(T) == typeof(IReplyChannel))
29             {
30                 return (T)(object)this;
31             }
32 
33             T baseProperty = base.GetProperty<T>();
34             if (baseProperty != null)
35             {
36                 return baseProperty;
37             }
38 
39             return default(T);
40         }
41 
OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)42         protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
43         {
44             return new CompletedAsyncResult(callback, state);
45         }
46 
OnEndOpen(IAsyncResult result)47         protected override void OnEndOpen(IAsyncResult result)
48         {
49             CompletedAsyncResult.End(result);
50         }
51 
OnOpen(TimeSpan timeout)52         protected override void OnOpen(TimeSpan timeout)
53         {
54         }
55 
56         #region static Helpers to convert TryReceiveRequest to ReceiveRequest
HelpReceiveRequest(IReplyChannel channel, TimeSpan timeout)57         internal static RequestContext HelpReceiveRequest(IReplyChannel channel, TimeSpan timeout)
58         {
59             RequestContext requestContext;
60             if (channel.TryReceiveRequest(timeout, out requestContext))
61             {
62                 return requestContext;
63             }
64             else
65             {
66                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
67                     ReplyChannel.CreateReceiveRequestTimedOutException(channel, timeout));
68             }
69         }
70 
HelpBeginReceiveRequest(IReplyChannel channel, TimeSpan timeout, AsyncCallback callback, object state)71         internal static IAsyncResult HelpBeginReceiveRequest(IReplyChannel channel, TimeSpan timeout, AsyncCallback callback, object state)
72         {
73             return new HelpReceiveRequestAsyncResult(channel, timeout, callback, state);
74         }
75 
HelpEndReceiveRequest(IAsyncResult result)76         internal static RequestContext HelpEndReceiveRequest(IAsyncResult result)
77         {
78             return HelpReceiveRequestAsyncResult.End(result);
79         }
80 
81         class HelpReceiveRequestAsyncResult : AsyncResult
82         {
83             IReplyChannel channel;
84             TimeSpan timeout;
85             static AsyncCallback onReceiveRequest = Fx.ThunkCallback(new AsyncCallback(OnReceiveRequest));
86             RequestContext requestContext;
87 
HelpReceiveRequestAsyncResult(IReplyChannel channel, TimeSpan timeout, AsyncCallback callback, object state)88             public HelpReceiveRequestAsyncResult(IReplyChannel channel, TimeSpan timeout, AsyncCallback callback, object state)
89                 : base(callback, state)
90             {
91                 this.channel = channel;
92                 this.timeout = timeout;
93                 IAsyncResult result = channel.BeginTryReceiveRequest(timeout, onReceiveRequest, this);
94 
95                 if (!result.CompletedSynchronously)
96                 {
97                     return;
98                 }
99 
100                 HandleReceiveRequestComplete(result);
101                 base.Complete(true);
102             }
103 
End(IAsyncResult result)104             public static RequestContext End(IAsyncResult result)
105             {
106                 HelpReceiveRequestAsyncResult thisPtr = AsyncResult.End<HelpReceiveRequestAsyncResult>(result);
107                 return thisPtr.requestContext;
108             }
109 
HandleReceiveRequestComplete(IAsyncResult result)110             void HandleReceiveRequestComplete(IAsyncResult result)
111             {
112                 if (!this.channel.EndTryReceiveRequest(result, out this.requestContext))
113                 {
114                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
115                         ReplyChannel.CreateReceiveRequestTimedOutException(this.channel, this.timeout));
116                 }
117             }
118 
OnReceiveRequest(IAsyncResult result)119             static void OnReceiveRequest(IAsyncResult result)
120             {
121                 if (result.CompletedSynchronously)
122                 {
123                     return;
124                 }
125 
126                 HelpReceiveRequestAsyncResult thisPtr = (HelpReceiveRequestAsyncResult)result.AsyncState;
127                 Exception completionException = null;
128                 try
129                 {
130                     thisPtr.HandleReceiveRequestComplete(result);
131                 }
132 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
133                 catch (Exception e)
134                 {
135                     if (Fx.IsFatal(e))
136                     {
137                         throw;
138                     }
139 
140                     completionException = e;
141                 }
142 
143                 thisPtr.Complete(false, completionException);
144             }
145         }
146 
CreateReceiveRequestTimedOutException(IReplyChannel channel, TimeSpan timeout)147         static Exception CreateReceiveRequestTimedOutException(IReplyChannel channel, TimeSpan timeout)
148         {
149             if (channel.LocalAddress != null)
150             {
151                 return new TimeoutException(SR.GetString(SR.ReceiveRequestTimedOut, channel.LocalAddress.Uri.AbsoluteUri, timeout));
152             }
153             else
154             {
155                 return new TimeoutException(SR.GetString(SR.ReceiveRequestTimedOutNoLocalAddress, timeout));
156             }
157         }
158         #endregion
159 
160 
ReceiveRequest()161         public RequestContext ReceiveRequest()
162         {
163             return this.ReceiveRequest(this.DefaultReceiveTimeout);
164         }
165 
ReceiveRequest(TimeSpan timeout)166         public RequestContext ReceiveRequest(TimeSpan timeout)
167         {
168             if (timeout < TimeSpan.Zero)
169                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
170                     new ArgumentOutOfRangeException("timeout", timeout, SR.GetString(SR.SFxTimeoutOutOfRange0)));
171 
172             this.ThrowPending();
173             return ReplyChannel.HelpReceiveRequest(this, timeout);
174         }
175 
BeginReceiveRequest(AsyncCallback callback, object state)176         public IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state)
177         {
178             return this.BeginReceiveRequest(this.DefaultReceiveTimeout, callback, state);
179         }
180 
BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)181         public IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
182         {
183             if (timeout < TimeSpan.Zero)
184             {
185                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
186                     new ArgumentOutOfRangeException("timeout", timeout, SR.GetString(SR.SFxTimeoutOutOfRange0)));
187             }
188 
189             this.ThrowPending();
190             return ReplyChannel.HelpBeginReceiveRequest(this, timeout, callback, state);
191         }
192 
EndReceiveRequest(IAsyncResult result)193         public RequestContext EndReceiveRequest(IAsyncResult result)
194         {
195             return ReplyChannel.HelpEndReceiveRequest(result);
196         }
197 
TryReceiveRequest(TimeSpan timeout, out RequestContext context)198         public bool TryReceiveRequest(TimeSpan timeout, out RequestContext context)
199         {
200             if (timeout < TimeSpan.Zero)
201                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
202                     new ArgumentOutOfRangeException("timeout", timeout, SR.GetString(SR.SFxTimeoutOutOfRange0)));
203 
204             this.ThrowPending();
205             return base.Dequeue(timeout, out context);
206         }
207 
BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)208         public IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
209         {
210             if (timeout < TimeSpan.Zero)
211                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
212                     new ArgumentOutOfRangeException("timeout", timeout, SR.GetString(SR.SFxTimeoutOutOfRange0)));
213 
214             this.ThrowPending();
215             return base.BeginDequeue(timeout, callback, state);
216         }
217 
EndTryReceiveRequest(IAsyncResult result, out RequestContext context)218         public bool EndTryReceiveRequest(IAsyncResult result, out RequestContext context)
219         {
220             return base.EndDequeue(result, out context);
221         }
222 
WaitForRequest(TimeSpan timeout)223         public bool WaitForRequest(TimeSpan timeout)
224         {
225             if (timeout < TimeSpan.Zero)
226                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
227                     new ArgumentOutOfRangeException("timeout", timeout, SR.GetString(SR.SFxTimeoutOutOfRange0)));
228 
229             this.ThrowPending();
230             return base.WaitForItem(timeout);
231         }
232 
BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state)233         public IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state)
234         {
235             if (timeout < TimeSpan.Zero)
236                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
237                     new ArgumentOutOfRangeException("timeout", timeout, SR.GetString(SR.SFxTimeoutOutOfRange0)));
238 
239             this.ThrowPending();
240             return base.BeginWaitForItem(timeout, callback, state);
241         }
242 
EndWaitForRequest(IAsyncResult result)243         public bool EndWaitForRequest(IAsyncResult result)
244         {
245             return base.EndWaitForItem(result);
246         }
247     }
248 }
249