1 // 2 // ServiceRuntimeChannel.cs 3 // 4 // Author: 5 // Atsushi Enomoto <atsushi@ximian.com> 6 // 7 // Copyright (C) 2007 Novell, Inc. http://www.novell.com 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining 10 // a copy of this software and associated documentation files (the 11 // "Software"), to deal in the Software without restriction, including 12 // without limitation the rights to use, copy, modify, merge, publish, 13 // distribute, sublicense, and/or sell copies of the Software, and to 14 // permit persons to whom the Software is furnished to do so, subject to 15 // the following conditions: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 // 28 using System; 29 using System.Collections.Generic; 30 using System.Reflection; 31 using System.ServiceModel.Channels; 32 using System.ServiceModel.Description; 33 using System.ServiceModel.Dispatcher; 34 using System.ServiceModel.MonoInternal; 35 36 namespace System.ServiceModel.MonoInternal 37 { 38 #if DISABLE_REAL_PROXY 39 // FIXME: this is a (similar) workaround for bug 571907. 40 public 41 #endif 42 class DuplexServiceRuntimeChannel : ServiceRuntimeChannel, IDuplexContextChannel, IInternalContextChannel 43 { DuplexServiceRuntimeChannel(IChannel channel, DispatchRuntime runtime)44 public DuplexServiceRuntimeChannel (IChannel channel, DispatchRuntime runtime) 45 : base (channel, runtime) 46 { 47 if (channel == null) 48 throw new ArgumentNullException ("channel"); 49 // setup callback ClientRuntimeChannel. 50 var crt = runtime.CallbackClientRuntime; 51 if (crt == null) 52 throw new InvalidOperationException ("The DispatchRuntime does not have CallbackClientRuntime"); 53 contract = ContractDescriptionGenerator.GetCallbackContract (runtime.Type, crt.CallbackClientType); 54 client = new ClientRuntimeChannel (crt, contract, this.DefaultOpenTimeout, this.DefaultCloseTimeout, channel, null, 55 runtime.ChannelDispatcher.MessageVersion, this.RemoteAddress, null); 56 } 57 58 ClientRuntimeChannel client; 59 ContractDescription contract; 60 61 public override bool AllowOutputBatching { 62 get { return client.AllowOutputBatching; } 63 set { client.AllowOutputBatching = value; } 64 } 65 66 public override TimeSpan OperationTimeout { 67 get { return client.OperationTimeout; } 68 set { client.OperationTimeout = value; } 69 } 70 71 public bool AutomaticInputSessionShutdown { 72 get { throw new NotImplementedException (); } 73 set { throw new NotImplementedException (); } 74 } 75 76 public InstanceContext CallbackInstance { get; set; } 77 78 public ContractDescription Contract { 79 get { return contract; } 80 } 81 82 public OperationContext Context { 83 set { } 84 } 85 86 Action<TimeSpan> session_shutdown_delegate; 87 CloseOutputSession(TimeSpan timeout)88 public void CloseOutputSession (TimeSpan timeout) 89 { 90 throw new NotImplementedException (); 91 } 92 BeginCloseOutputSession(TimeSpan timeout, AsyncCallback callback, object state)93 public IAsyncResult BeginCloseOutputSession (TimeSpan timeout, AsyncCallback callback, object state) 94 { 95 if (session_shutdown_delegate == null) 96 session_shutdown_delegate = new Action<TimeSpan> (CloseOutputSession); 97 return session_shutdown_delegate.BeginInvoke (timeout, callback, state); 98 } 99 EndCloseOutputSession(IAsyncResult result)100 public void EndCloseOutputSession (IAsyncResult result) 101 { 102 session_shutdown_delegate.EndInvoke (result); 103 } 104 105 // proxy base implementation. 106 BeginProcess(MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState)107 public IAsyncResult BeginProcess (MethodBase method, string operationName, object [] parameters, AsyncCallback callback, object asyncState) 108 { 109 return client.BeginProcess (method, operationName, parameters, callback, asyncState); 110 } 111 EndProcess(MethodBase method, string operationName, object [] parameters, IAsyncResult result)112 public object EndProcess (MethodBase method, string operationName, object [] parameters, IAsyncResult result) 113 { 114 return client.EndProcess (method, operationName, parameters, result); 115 } 116 Process(MethodBase method, string operationName, object [] parameters, OperationContext context)117 public object Process (MethodBase method, string operationName, object [] parameters, OperationContext context) 118 { 119 return client.Process (method, operationName, parameters, context); 120 } 121 } 122 123 // Its lifetime is per-session. 124 // InputOrReplyRequestProcessor's lifetime is per-call. 125 #if DISABLE_REAL_PROXY 126 // FIXME: this is a (similar) workaround for bug 571907. 127 public 128 #endif 129 class ServiceRuntimeChannel : CommunicationObject, IServiceChannel, IDisposable 130 { 131 IExtensionCollection<IContextChannel> extensions; 132 readonly IChannel channel; 133 readonly DispatchRuntime runtime; 134 ServiceRuntimeChannel(IChannel channel, DispatchRuntime runtime)135 public ServiceRuntimeChannel (IChannel channel, DispatchRuntime runtime) 136 { 137 this.channel = channel; 138 this.runtime = runtime; 139 } 140 OnChannelClose(object o, EventArgs e)141 void OnChannelClose (object o, EventArgs e) 142 { 143 Close (); 144 } 145 146 #region IContextChannel 147 148 [MonoTODO] 149 public virtual bool AllowOutputBatching { get; set; } 150 151 public IInputSession InputSession { 152 get { 153 var ch = channel as ISessionChannel<IInputSession>; 154 if (ch != null) 155 return ch.Session; 156 var dch = channel as ISessionChannel<IDuplexSession>; 157 return dch != null ? dch.Session : null; 158 } 159 } 160 161 public EndpointAddress LocalAddress { 162 get { 163 if (channel is IReplyChannel) 164 return ((IReplyChannel) channel).LocalAddress; 165 if (channel is IInputChannel) 166 return ((IInputChannel) channel).LocalAddress; 167 return null; 168 } 169 } 170 171 [MonoTODO] 172 public virtual TimeSpan OperationTimeout { get; set; } 173 174 public IOutputSession OutputSession { 175 get { 176 var dch = channel as ISessionChannel<IDuplexSession>; 177 return dch != null ? dch.Session : null; 178 } 179 } 180 181 public EndpointAddress RemoteAddress { 182 get { 183 if (channel is IDuplexChannel) 184 return ((IDuplexChannel) channel).RemoteAddress; 185 return null; 186 } 187 } 188 189 public string SessionId { 190 get { return InputSession != null ? InputSession.Id : null; } 191 } 192 193 #endregion 194 195 // CommunicationObject 196 protected internal override TimeSpan DefaultOpenTimeout { 197 get { return runtime.ChannelDispatcher.DefaultOpenTimeout; } 198 } 199 200 protected internal override TimeSpan DefaultCloseTimeout { 201 get { return runtime.ChannelDispatcher.DefaultCloseTimeout; } 202 } 203 OnAbort()204 protected override void OnAbort () 205 { 206 channel.Abort (); 207 } 208 209 Action<TimeSpan> close_delegate; 210 OnBeginClose( TimeSpan timeout, AsyncCallback callback, object state)211 protected override IAsyncResult OnBeginClose ( 212 TimeSpan timeout, AsyncCallback callback, object state) 213 { 214 if (close_delegate == null) 215 close_delegate = new Action<TimeSpan> (OnClose); 216 return close_delegate.BeginInvoke (timeout, callback, state); 217 } 218 OnEndClose(IAsyncResult result)219 protected override void OnEndClose (IAsyncResult result) 220 { 221 close_delegate.EndInvoke (result); 222 } 223 OnClose(TimeSpan timeout)224 protected override void OnClose (TimeSpan timeout) 225 { 226 channel.Closing -= OnChannelClose; 227 } 228 OnBeginOpen( TimeSpan timeout, AsyncCallback callback, object state)229 protected override IAsyncResult OnBeginOpen ( 230 TimeSpan timeout, AsyncCallback callback, object state) 231 { 232 return channel.BeginOpen (timeout, callback, state); 233 } 234 OnEndOpen(IAsyncResult result)235 protected override void OnEndOpen (IAsyncResult result) 236 { 237 channel.EndOpen (result); 238 } 239 OnOpen(TimeSpan timeout)240 protected override void OnOpen (TimeSpan timeout) 241 { 242 if (channel.State == CommunicationState.Created) 243 channel.Open (timeout); 244 } 245 246 // IChannel 247 public T GetProperty<T> () where T : class 248 { 249 return channel.GetProperty<T> (); 250 } 251 252 // IExtensibleObject<IContextChannel> 253 public IExtensionCollection<IContextChannel> Extensions { 254 get { 255 if (extensions == null) 256 extensions = new ExtensionCollection<IContextChannel> (this); 257 return extensions; 258 } 259 } 260 261 public Uri ListenUri { 262 get { return runtime.ChannelDispatcher.Listener.Uri; } 263 } 264 265 #region IDisposable Members 266 Dispose()267 public void Dispose () 268 { 269 Close (); 270 } 271 272 #endregion 273 } 274 } 275