You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,484 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Description;
|
||||
using System.Transactions;
|
||||
using System.Runtime.Diagnostics;
|
||||
using System.ServiceModel.Diagnostics;
|
||||
|
||||
static class ClientFactory
|
||||
{
|
||||
public static IRoutingClient Create(RoutingEndpointTrait endpointTrait, RoutingService service, bool impersonating)
|
||||
{
|
||||
Type contractType = endpointTrait.RouterContract;
|
||||
IRoutingClient client;
|
||||
if (contractType == typeof(ISimplexDatagramRouter))
|
||||
{
|
||||
client = new SimplexDatagramClient(endpointTrait, service.RoutingConfig, impersonating);
|
||||
}
|
||||
else if (contractType == typeof(IRequestReplyRouter))
|
||||
{
|
||||
client = new RequestReplyClient(endpointTrait, service.RoutingConfig, impersonating);
|
||||
}
|
||||
else if (contractType == typeof(ISimplexSessionRouter))
|
||||
{
|
||||
client = new SimplexSessionClient(endpointTrait, service.RoutingConfig, impersonating);
|
||||
}
|
||||
else //if (contractType == typeof(IDuplexSessionRouter))
|
||||
{
|
||||
Fx.Assert(contractType == typeof(IDuplexSessionRouter), "Only one contract type remaining.");
|
||||
client = new DuplexSessionClient(service, endpointTrait, impersonating);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
abstract class RoutingClientBase<TChannel> : ClientBase<TChannel>, IRoutingClient
|
||||
where TChannel : class
|
||||
{
|
||||
bool openCompleted;
|
||||
object thisLock;
|
||||
Queue<OperationAsyncResult> waiters;
|
||||
|
||||
protected RoutingClientBase(RoutingEndpointTrait endpointTrait, RoutingConfiguration routingConfig, bool impersonating)
|
||||
: base(endpointTrait.Endpoint.Binding, endpointTrait.Endpoint.Address)
|
||||
{
|
||||
Initialize(endpointTrait, routingConfig, impersonating);
|
||||
}
|
||||
|
||||
protected RoutingClientBase(RoutingEndpointTrait endpointTrait, RoutingConfiguration routingConfig, object callbackInstance, bool impersonating)
|
||||
: base(new InstanceContext(callbackInstance), endpointTrait.Endpoint.Binding, endpointTrait.Endpoint.Address)
|
||||
{
|
||||
Initialize(endpointTrait, routingConfig, impersonating);
|
||||
}
|
||||
|
||||
public RoutingEndpointTrait Key
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public event EventHandler Faulted;
|
||||
|
||||
static void ConfigureImpersonation(ServiceEndpoint endpoint, bool impersonating)
|
||||
{
|
||||
// Used for both impersonation and ASP.NET Compatibilty Mode. Both currently require
|
||||
// everything to be synchronous.
|
||||
if (impersonating)
|
||||
{
|
||||
CustomBinding binding = endpoint.Binding as CustomBinding;
|
||||
if (binding == null)
|
||||
{
|
||||
binding = new CustomBinding(endpoint.Binding);
|
||||
}
|
||||
|
||||
SynchronousSendBindingElement syncSend = binding.Elements.Find<SynchronousSendBindingElement>();
|
||||
if (syncSend == null)
|
||||
{
|
||||
binding.Elements.Insert(0, new SynchronousSendBindingElement());
|
||||
endpoint.Binding = binding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ConfigureTransactionFlow(ServiceEndpoint endpoint)
|
||||
{
|
||||
CustomBinding binding = endpoint.Binding as CustomBinding;
|
||||
if (binding == null)
|
||||
{
|
||||
binding = new CustomBinding(endpoint.Binding);
|
||||
}
|
||||
TransactionFlowBindingElement transactionFlow = binding.Elements.Find<TransactionFlowBindingElement>();
|
||||
if (transactionFlow != null)
|
||||
{
|
||||
transactionFlow.AllowWildcardAction = true;
|
||||
endpoint.Binding = binding;
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize(RoutingEndpointTrait endpointTrait, RoutingConfiguration routingConfig, bool impersonating)
|
||||
{
|
||||
this.thisLock = new object();
|
||||
this.Key = endpointTrait;
|
||||
if (TD.RoutingServiceCreatingClientForEndpointIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceCreatingClientForEndpoint(this.Key.ToString());
|
||||
}
|
||||
ServiceEndpoint clientEndpoint = endpointTrait.Endpoint;
|
||||
ServiceEndpoint endpoint = this.Endpoint;
|
||||
KeyedByTypeCollection<IEndpointBehavior> behaviors = endpoint.Behaviors;
|
||||
endpoint.ListenUri = clientEndpoint.ListenUri;
|
||||
endpoint.ListenUriMode = clientEndpoint.ListenUriMode;
|
||||
endpoint.Name = clientEndpoint.Name;
|
||||
foreach (IEndpointBehavior behavior in clientEndpoint.Behaviors)
|
||||
{
|
||||
// Remove if present, ok to call if not there (will simply return false)
|
||||
behaviors.Remove(behavior.GetType());
|
||||
behaviors.Add(behavior);
|
||||
}
|
||||
|
||||
// If the configuration doesn't explicitly add MustUnderstandBehavior (to override us)
|
||||
// add it here, with mustunderstand = false.
|
||||
if (behaviors.Find<MustUnderstandBehavior>() == null)
|
||||
{
|
||||
behaviors.Add(new MustUnderstandBehavior(false));
|
||||
}
|
||||
|
||||
// If the configuration doesn't explicitly turn off marshaling we add it here.
|
||||
if (routingConfig.SoapProcessingEnabled && behaviors.Find<SoapProcessingBehavior>() == null)
|
||||
{
|
||||
behaviors.Add(new SoapProcessingBehavior());
|
||||
}
|
||||
|
||||
ConfigureTransactionFlow(endpoint);
|
||||
ConfigureImpersonation(endpoint, impersonating);
|
||||
}
|
||||
|
||||
protected override TChannel CreateChannel()
|
||||
{
|
||||
TChannel channel = base.CreateChannel();
|
||||
((ICommunicationObject)channel).Faulted += this.InnerChannelFaulted;
|
||||
return channel;
|
||||
}
|
||||
|
||||
public IAsyncResult BeginOperation(Message message, Transaction transaction, AsyncCallback callback, object state)
|
||||
{
|
||||
return new OperationAsyncResult(this, message, transaction, callback, state);
|
||||
}
|
||||
|
||||
public Message EndOperation(IAsyncResult result)
|
||||
{
|
||||
return OperationAsyncResult.End(result);
|
||||
}
|
||||
|
||||
protected abstract IAsyncResult OnBeginOperation(Message message, AsyncCallback callback, object state);
|
||||
protected abstract Message OnEndOperation(IAsyncResult asyncResult);
|
||||
|
||||
void InnerChannelFaulted(object sender, EventArgs args)
|
||||
{
|
||||
EventHandler handlers = this.Faulted;
|
||||
if (handlers != null)
|
||||
{
|
||||
handlers(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
class OperationAsyncResult : TransactedAsyncResult
|
||||
{
|
||||
static AsyncCompletion openComplete = OpenComplete;
|
||||
static AsyncCompletion operationComplete = OperationComplete;
|
||||
static Action<object> signalWaiter;
|
||||
|
||||
RoutingClientBase<TChannel> parent;
|
||||
Message replyMessage;
|
||||
Message requestMessage;
|
||||
Transaction transaction;
|
||||
|
||||
public OperationAsyncResult(RoutingClientBase<TChannel> parent, Message requestMessage, Transaction transaction, AsyncCallback callback, object state)
|
||||
: base(callback, state)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.requestMessage = requestMessage;
|
||||
this.transaction = transaction;
|
||||
|
||||
bool shouldOpen = false;
|
||||
|
||||
if (!this.parent.openCompleted)
|
||||
{
|
||||
lock (this.parent.thisLock)
|
||||
{
|
||||
if (!this.parent.openCompleted)
|
||||
{
|
||||
//The first to open initializes the waiters queue others add themselves to it.
|
||||
if (this.parent.waiters == null)
|
||||
{
|
||||
//it's our job to open the proxy
|
||||
this.parent.waiters = new Queue<OperationAsyncResult>();
|
||||
shouldOpen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Someone beat us to it, just join the list of waiters.
|
||||
this.parent.waiters.Enqueue(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldOpen)
|
||||
{
|
||||
//we are the first so we need to open this channel
|
||||
IAsyncResult asyncResult;
|
||||
using (this.PrepareTransactionalCall(this.transaction))
|
||||
{
|
||||
//This will use the binding's OpenTimeout.
|
||||
asyncResult = ((ICommunicationObject)this.parent).BeginOpen(this.PrepareAsyncCompletion(openComplete), this);
|
||||
}
|
||||
if (this.SyncContinue(asyncResult))
|
||||
{
|
||||
this.Complete(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.CallOperation())
|
||||
{
|
||||
this.Complete(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Message End(IAsyncResult result)
|
||||
{
|
||||
OperationAsyncResult thisPtr = AsyncResult.End<OperationAsyncResult>(result);
|
||||
return thisPtr.replyMessage;
|
||||
}
|
||||
|
||||
static bool OpenComplete(IAsyncResult openResult)
|
||||
{
|
||||
OperationAsyncResult thisPtr = (OperationAsyncResult)openResult.AsyncState;
|
||||
try
|
||||
{
|
||||
((ICommunicationObject)thisPtr.parent).EndOpen(openResult);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Queue<OperationAsyncResult> localWaiters = null;
|
||||
|
||||
lock (thisPtr.parent.thisLock)
|
||||
{
|
||||
localWaiters = thisPtr.parent.waiters;
|
||||
thisPtr.parent.waiters = null;
|
||||
thisPtr.parent.openCompleted = true;
|
||||
}
|
||||
|
||||
if (localWaiters != null && localWaiters.Count > 0)
|
||||
{
|
||||
if (signalWaiter == null)
|
||||
{
|
||||
signalWaiter = new Action<object>(SignalWaiter);
|
||||
}
|
||||
|
||||
//foreach over Queue<T> goes FIFO
|
||||
foreach (OperationAsyncResult waiter in localWaiters)
|
||||
{
|
||||
ActionItem.Schedule(signalWaiter, waiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
return thisPtr.CallOperation();
|
||||
}
|
||||
|
||||
bool CallOperation()
|
||||
{
|
||||
IAsyncResult asyncResult;
|
||||
using (this.PrepareTransactionalCall(this.transaction))
|
||||
{
|
||||
asyncResult = this.parent.OnBeginOperation(this.requestMessage, this.PrepareAsyncCompletion(operationComplete), this);
|
||||
}
|
||||
return this.SyncContinue(asyncResult);
|
||||
}
|
||||
|
||||
static bool OperationComplete(IAsyncResult result)
|
||||
{
|
||||
OperationAsyncResult thisPtr = (OperationAsyncResult)result.AsyncState;
|
||||
thisPtr.replyMessage = thisPtr.parent.OnEndOperation(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void SignalWaiter(object state)
|
||||
{
|
||||
OperationAsyncResult waiter = (OperationAsyncResult)state;
|
||||
try
|
||||
{
|
||||
if (waiter.CallOperation())
|
||||
{
|
||||
waiter.Complete(false);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (Fx.IsFatal(exception))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
waiter.Complete(false, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SimplexDatagramClient : RoutingClientBase<ISimplexDatagramRouter>
|
||||
{
|
||||
public SimplexDatagramClient(RoutingEndpointTrait endpointTrait, RoutingConfiguration routingConfig, bool impersonating)
|
||||
: base(endpointTrait, routingConfig, impersonating)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IAsyncResult OnBeginOperation(Message message, AsyncCallback callback, object state)
|
||||
{
|
||||
return this.Channel.BeginProcessMessage(message, callback, state);
|
||||
}
|
||||
|
||||
protected override Message OnEndOperation(IAsyncResult result)
|
||||
{
|
||||
this.Channel.EndProcessMessage(result);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class SimplexSessionClient : RoutingClientBase<ISimplexSessionRouter>
|
||||
{
|
||||
public SimplexSessionClient(RoutingEndpointTrait endointTrait, RoutingConfiguration routingConfig, bool impersonating)
|
||||
: base(endointTrait, routingConfig, impersonating)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IAsyncResult OnBeginOperation(Message message, AsyncCallback callback, object state)
|
||||
{
|
||||
return this.Channel.BeginProcessMessage(message, callback, state);
|
||||
}
|
||||
|
||||
protected override Message OnEndOperation(IAsyncResult result)
|
||||
{
|
||||
this.Channel.EndProcessMessage(result);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class DuplexSessionClient : RoutingClientBase<IDuplexSessionRouter>
|
||||
{
|
||||
public DuplexSessionClient(RoutingService service, RoutingEndpointTrait endpointTrait, bool impersonating)
|
||||
: base(endpointTrait, service.RoutingConfig, new DuplexCallbackProxy(service.ChannelExtension.ActivityID, endpointTrait.CallbackInstance), impersonating)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IAsyncResult OnBeginOperation(Message message, AsyncCallback callback, object state)
|
||||
{
|
||||
return this.Channel.BeginProcessMessage(message, callback, state);
|
||||
}
|
||||
|
||||
protected override Message OnEndOperation(IAsyncResult result)
|
||||
{
|
||||
this.Channel.EndProcessMessage(result);
|
||||
return null;
|
||||
}
|
||||
|
||||
class DuplexCallbackProxy : IDuplexRouterCallback
|
||||
{
|
||||
Guid activityID;
|
||||
IDuplexRouterCallback callbackInstance;
|
||||
EventTraceActivity eventTraceActivity;
|
||||
|
||||
public DuplexCallbackProxy(Guid activityID, IDuplexRouterCallback callbackInstance)
|
||||
{
|
||||
this.activityID = activityID;
|
||||
this.callbackInstance = callbackInstance;
|
||||
if (Fx.Trace.IsEtwProviderEnabled)
|
||||
{
|
||||
this.eventTraceActivity = new EventTraceActivity(activityID);
|
||||
}
|
||||
}
|
||||
|
||||
IAsyncResult IDuplexRouterCallback.BeginProcessMessage(Message message, AsyncCallback callback, object state)
|
||||
{
|
||||
FxTrace.Trace.SetAndTraceTransfer(this.activityID, true);
|
||||
try
|
||||
{
|
||||
return new CallbackAsyncResult(this.callbackInstance, message, callback, state);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (TD.RoutingServiceDuplexCallbackExceptionIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceDuplexCallbackException(this.eventTraceActivity, "DuplexCallbackProxy.BeginProcessMessage", e);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void IDuplexRouterCallback.EndProcessMessage(IAsyncResult result)
|
||||
{
|
||||
FxTrace.Trace.SetAndTraceTransfer(this.activityID, true);
|
||||
try
|
||||
{
|
||||
CallbackAsyncResult.End(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (TD.RoutingServiceDuplexCallbackExceptionIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceDuplexCallbackException(this.eventTraceActivity, "DuplexCallbackProxy.EndProcessMessage", e);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// We have to have an AsyncResult implementation here in order to handle the
|
||||
// TransactionScope appropriately (use PrepareTransactionalCall, SyncContinue, etc...)
|
||||
class CallbackAsyncResult : TransactedAsyncResult
|
||||
{
|
||||
static AsyncCompletion processCallback = ProcessCallback;
|
||||
IDuplexRouterCallback callbackInstance;
|
||||
|
||||
public CallbackAsyncResult(IDuplexRouterCallback callbackInstance, Message message, AsyncCallback callback, object state)
|
||||
: base(callback, state)
|
||||
{
|
||||
this.callbackInstance = callbackInstance;
|
||||
|
||||
IAsyncResult result;
|
||||
using (this.PrepareTransactionalCall(TransactionMessageProperty.TryGetTransaction(message)))
|
||||
{
|
||||
result = this.callbackInstance.BeginProcessMessage(message,
|
||||
this.PrepareAsyncCompletion(processCallback), this);
|
||||
}
|
||||
|
||||
if (this.SyncContinue(result))
|
||||
{
|
||||
this.Complete(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void End(IAsyncResult result)
|
||||
{
|
||||
AsyncResult.End<CallbackAsyncResult>(result);
|
||||
}
|
||||
|
||||
static bool ProcessCallback(IAsyncResult result)
|
||||
{
|
||||
CallbackAsyncResult thisPtr = (CallbackAsyncResult)result.AsyncState;
|
||||
thisPtr.callbackInstance.EndProcessMessage(result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RequestReplyClient : RoutingClientBase<IRequestReplyRouter>
|
||||
{
|
||||
public RequestReplyClient(RoutingEndpointTrait endpointTrait, RoutingConfiguration routingConfig, bool impersonating)
|
||||
: base(endpointTrait, routingConfig, impersonating)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IAsyncResult OnBeginOperation(Message message, AsyncCallback callback, object state)
|
||||
{
|
||||
return this.Channel.BeginProcessRequest(message, callback, state);
|
||||
}
|
||||
|
||||
protected override Message OnEndOperation(IAsyncResult result)
|
||||
{
|
||||
return this.Channel.EndProcessRequest(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user