using System.ServiceModel.Dispatcher;
using System.ServiceModel.Security;
using System.Threading;
+using System.Xml;
namespace System.ServiceModel
{
-#if TARGET_DOTNET
- [MonoTODO]
- public
+#if NET_2_1
+ internal class DuplexClientRuntimeChannel
+ {
+ }
#else
- internal
+ internal class DuplexClientRuntimeChannel
+ : ClientRuntimeChannel, IDuplexContextChannel
+ {
+ public DuplexClientRuntimeChannel (ServiceEndpoint endpoint,
+ ChannelFactory factory, EndpointAddress remoteAddress, Uri via)
+ : base (endpoint, factory, remoteAddress, via)
+ {
+ }
+
+ public bool AutomaticInputSessionShutdown {
+ get { throw new NotImplementedException (); }
+ set { throw new NotImplementedException (); }
+ }
+
+ public InstanceContext CallbackInstance { get; set; }
+
+ Action<TimeSpan> session_shutdown_delegate;
+
+ public void CloseOutputSession (TimeSpan timeout)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public IAsyncResult BeginCloseOutputSession (TimeSpan timeout, AsyncCallback callback, object state)
+ {
+ if (session_shutdown_delegate == null)
+ session_shutdown_delegate = new Action<TimeSpan> (CloseOutputSession);
+ return session_shutdown_delegate.BeginInvoke (timeout, callback, state);
+ }
+
+ public void EndCloseOutputSession (IAsyncResult result)
+ {
+ session_shutdown_delegate.EndInvoke (result);
+ }
+ }
#endif
- class ClientRuntimeChannel
+
+ internal class ClientRuntimeChannel
: CommunicationObject, IClientChannel
{
ClientRuntime runtime;
- ChannelFactory factory;
- IRequestChannel request_channel;
- IOutputChannel output_channel; // could also be IDuplexChannel instance.
+ EndpointAddress remote_address;
+ ContractDescription contract;
+ MessageVersion message_version;
+ TimeSpan default_open_timeout, default_close_timeout;
+ IChannel channel;
+ IChannelFactory factory;
#region delegates
readonly ProcessDelegate _processDelegate;
#endregion
public ClientRuntimeChannel (ServiceEndpoint endpoint,
- ChannelFactory factory)
+ ChannelFactory channelFactory, EndpointAddress remoteAddress, Uri via)
+ : this (endpoint.CreateRuntime (), endpoint.Contract, channelFactory.DefaultOpenTimeout, channelFactory.DefaultCloseTimeout, null, channelFactory.OpenedChannelFactory, endpoint.Binding.MessageVersion, remoteAddress, via)
+ {
+ }
+
+ public ClientRuntimeChannel (ClientRuntime runtime, ContractDescription contract, TimeSpan openTimeout, TimeSpan closeTimeout, IChannel contextChannel, IChannelFactory factory, MessageVersion messageVersion, EndpointAddress remoteAddress, Uri via)
{
- this.runtime = endpoint.CreateRuntime ();
- this.factory = factory;
+ this.runtime = runtime;
+ this.remote_address = remoteAddress;
+ runtime.Via = via;
+ this.contract = contract;
+ this.message_version = messageVersion;
+ default_open_timeout = openTimeout;
+ default_close_timeout = closeTimeout;
_processDelegate = new ProcessDelegate (Process);
requestDelegate = new RequestDelegate (Request);
sendDelegate = new SendDelegate (Send);
AllowInitializationUI = true;
OperationTimeout = TimeSpan.FromMinutes (1);
- // determine operation channel to create.
- if (factory.OpenedChannelFactory is IChannelFactory<IRequestChannel> ||
- factory.OpenedChannelFactory is IChannelFactory<IRequestSessionChannel>)
- SetupRequestChannel ();
- else
- SetupOutputChannel ();
+ if (contextChannel != null)
+ channel = contextChannel;
+ else {
+ var method = factory.GetType ().GetMethod ("CreateChannel", new Type [] {typeof (EndpointAddress), typeof (Uri)});
+ channel = (IChannel) method.Invoke (factory, new object [] {remote_address, Via});
+ this.factory = factory;
+ }
}
public ClientRuntime Runtime {
get { return runtime; }
}
+ IRequestChannel RequestChannel {
+ get { return channel as IRequestChannel; }
+ }
+
+ IOutputChannel OutputChannel {
+ get { return channel as IOutputChannel; }
+ }
+
#region IClientChannel
bool did_interactive_initialization;
public IInputSession InputSession {
get {
- ISessionChannel<IInputSession> ch = request_channel as ISessionChannel<IInputSession>;
- ch = ch ?? output_channel as ISessionChannel<IInputSession>;
- return ch != null ? ch.Session : null;
+ ISessionChannel<IInputSession> ch = RequestChannel as ISessionChannel<IInputSession>;
+ ch = ch ?? OutputChannel as ISessionChannel<IInputSession>;
+ if (ch != null)
+ return ch.Session;
+ var dch = OutputChannel as ISessionChannel<IDuplexSession>;
+ return dch != null ? dch.Session : null;
}
}
public IOutputSession OutputSession {
get {
- ISessionChannel<IOutputSession> ch = request_channel as ISessionChannel<IOutputSession>;
- ch = ch ?? output_channel as ISessionChannel<IOutputSession>;
- return ch != null ? ch.Session : null;
+ ISessionChannel<IOutputSession> ch = RequestChannel as ISessionChannel<IOutputSession>;
+ ch = ch ?? OutputChannel as ISessionChannel<IOutputSession>;
+ if (ch != null)
+ return ch.Session;
+ var dch = OutputChannel as ISessionChannel<IDuplexSession>;
+ return dch != null ? dch.Session : null;
}
}
public EndpointAddress RemoteAddress {
- get { return request_channel != null ? request_channel.RemoteAddress : output_channel.RemoteAddress; }
+ get { return RequestChannel != null ? RequestChannel.RemoteAddress : OutputChannel.RemoteAddress; }
}
public string SessionId {
// CommunicationObject
protected internal override TimeSpan DefaultOpenTimeout {
- get { return factory.DefaultOpenTimeout; }
+ get { return default_open_timeout; }
}
protected internal override TimeSpan DefaultCloseTimeout {
- get { return factory.DefaultCloseTimeout; }
+ get { return default_close_timeout; }
}
protected override void OnAbort ()
{
- factory.Abort ();
+ channel.Abort ();
+ if (factory != null)
+ factory.Abort ();
}
+ Action<TimeSpan> close_delegate;
+
protected override IAsyncResult OnBeginClose (
TimeSpan timeout, AsyncCallback callback, object state)
{
- return factory.BeginClose (timeout, callback, state);
+ if (close_delegate == null)
+ close_delegate = new Action<TimeSpan> (OnClose);
+ return close_delegate.BeginInvoke (timeout, callback, state);
}
protected override void OnEndClose (IAsyncResult result)
{
- factory.EndClose (result);
+ close_delegate.EndInvoke (result);
}
protected override void OnClose (TimeSpan timeout)
{
- factory.Close (timeout);
+ DateTime start = DateTime.Now;
+ channel.Close (timeout);
+ if (factory != null)
+ factory.Close (timeout - (DateTime.Now - start));
}
protected override IAsyncResult OnBeginOpen (
// IChannel
IChannel OperationChannel {
- get { return (IChannel) request_channel ?? output_channel; }
+ get { return channel; }
}
public T GetProperty<T> () where T : class
operation = Runtime.OperationSelector.SelectOperation (method, parameters);
else
operation = operationName;
- OperationDescription od = factory.Endpoint.Contract.Operations.Find (operation);
+ OperationDescription od = contract.Operations.Find (operation);
if (od == null)
throw new Exception (String.Format ("OperationDescription for operation '{0}' was not found in its internally-generated contract.", operation));
return od;
}
- BindingParameterCollection CreateBindingParameters ()
- {
- BindingParameterCollection pl =
- new BindingParameterCollection ();
-
- ContractDescription cd = factory.Endpoint.Contract;
-#if !NET_2_1
- pl.Add (ChannelProtectionRequirements.CreateFromContract (cd));
-
- foreach (IEndpointBehavior behavior in factory.Endpoint.Behaviors)
- behavior.AddBindingParameters (factory.Endpoint, pl);
-#endif
-
- return pl;
- }
-
- // This handles IDuplexChannel, IOutputChannel, and those for session channels.
- void SetupOutputChannel ()
- {
- if (output_channel != null)
- return;
-
- EndpointAddress address = factory.Endpoint.Address;
- Uri via = Runtime.Via;
-
- var method = factory.OpenedChannelFactory.GetType ().GetMethod ("CreateChannel", new Type [] {typeof (EndpointAddress), typeof (Uri)});
- output_channel = (IOutputChannel) method.Invoke (factory.OpenedChannelFactory, new object [] {address, via});
- }
-
- // This handles both IRequestChannel and IRequestSessionChannel.
- void SetupRequestChannel ()
- {
- if (request_channel != null)
- return;
-
- EndpointAddress address = factory.Endpoint.Address;
- Uri via = Runtime.Via;
-
- var method = factory.OpenedChannelFactory.GetType ().GetMethod ("CreateChannel", new Type [] {typeof (EndpointAddress), typeof (Uri)});
- request_channel = (IRequestChannel) method.Invoke (factory.OpenedChannelFactory, new object [] {address, via});
- }
-
void Output (OperationDescription od, object [] parameters)
{
- if (output_channel.State != CommunicationState.Opened)
- output_channel.Open ();
+ if (OutputChannel.State != CommunicationState.Opened)
+ OutputChannel.Open ();
ClientOperation op = runtime.Operations [od.Name];
Send (CreateRequest (op, parameters), OperationTimeout);
// They are internal for ClientBase<T>.ChannelBase use.
internal Message Request (Message msg, TimeSpan timeout)
{
- if (request_channel != null)
- return request_channel.Request (msg, timeout);
+ if (RequestChannel != null)
+ return RequestChannel.Request (msg, timeout);
else {
DateTime startTime = DateTime.Now;
- output_channel.Send (msg, timeout);
- return ((IDuplexChannel) output_channel).Receive (timeout - (DateTime.Now - startTime));
+ OutputChannel.Send (msg, timeout);
+ return ((IDuplexChannel) OutputChannel).Receive (timeout - (DateTime.Now - startTime));
}
}
internal void Send (Message msg, TimeSpan timeout)
{
- output_channel.Send (msg, timeout);
+ OutputChannel.Send (msg, timeout);
}
internal IAsyncResult BeginSend (Message msg, TimeSpan timeout, AsyncCallback callback, object state)
Message CreateRequest (ClientOperation op, object [] parameters)
{
- MessageVersion version = factory.Endpoint.Binding.MessageVersion;
+ MessageVersion version = message_version;
if (version == null)
version = MessageVersion.Default;
version, parameters);
else
msg = (Message) parameters [0];
+
+ if (OutputSession != null)
+ msg.Headers.MessageId = new UniqueId (OutputSession.Id);
msg.Properties.AllowOutputBatching = AllowOutputBatching;
+
return msg;
}