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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing.Configuration
|
||||
{
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Description;
|
||||
|
||||
sealed class ClientEndpointLoader : ChannelFactory
|
||||
{
|
||||
ClientEndpointLoader(string configurationName)
|
||||
{
|
||||
base.InitializeEndpoint(configurationName, null);
|
||||
base.Endpoint.Name = configurationName;
|
||||
}
|
||||
|
||||
public static ServiceEndpoint LoadEndpoint(string configurationName)
|
||||
{
|
||||
using (ClientEndpointLoader loader = new ClientEndpointLoader(configurationName))
|
||||
{
|
||||
return loader.Endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
protected override ServiceEndpoint CreateDescription()
|
||||
{
|
||||
ServiceEndpoint ep = new ServiceEndpoint(new ContractDescription("contract"));
|
||||
ep.Contract.ConfigurationName = "*";
|
||||
return ep;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing.Configuration
|
||||
{
|
||||
static class ConfigurationStrings
|
||||
{
|
||||
internal const string BackupList = "backupList";
|
||||
internal const string BackupLists = "backupLists";
|
||||
internal const string CustomType = "customType";
|
||||
internal const string EndpointName = "endpointName";
|
||||
internal const string Endpoints = "endpoints";
|
||||
internal const string Entries = "entries";
|
||||
internal const string Filter = "filter";
|
||||
internal const string Filter1 = "filter1";
|
||||
internal const string Filter2 = "filter2";
|
||||
internal const string FilterData = "filterData";
|
||||
internal const string FilterName = "filterName";
|
||||
internal const string Filters = "filters";
|
||||
internal const string FilterTable = "filterTable";
|
||||
internal const string FilterTableName = "filterTableName";
|
||||
internal const string FilterTables = "filterTables";
|
||||
internal const string FilterType = "filterType";
|
||||
//internal const string Impersonation = "impersonation";
|
||||
internal const string Name = "name";
|
||||
internal const string Namespace = "namespace";
|
||||
internal const string NamespaceTable = "namespaceTable";
|
||||
internal const string Prefix = "prefix";
|
||||
internal const string Priority = "priority";
|
||||
internal const string ProcessMessages = "processMessages";
|
||||
internal const string RouteOnHeadersOnly = "routeOnHeadersOnly";
|
||||
internal const string SoapProcessingEnabled = "soapProcessingEnabled";
|
||||
internal const string EnsureOrderedDispatch = "ensureOrderedDispatch";
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing.Configuration
|
||||
{
|
||||
using System;
|
||||
|
||||
public enum FilterType
|
||||
{
|
||||
Action,
|
||||
EndpointAddress,
|
||||
PrefixEndpointAddress,
|
||||
And,
|
||||
Custom,
|
||||
EndpointName,
|
||||
MatchAll,
|
||||
XPath
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing.Configuration
|
||||
{
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Configuration;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Configuration;
|
||||
using System.ServiceModel.Description;
|
||||
|
||||
public sealed class RoutingExtensionElement : BehaviorExtensionElement
|
||||
{
|
||||
public RoutingExtensionElement()
|
||||
{
|
||||
this.RouteOnHeadersOnly = RoutingConfiguration.DefaultRouteOnHeadersOnly;
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Configuration, FxCop.Rule.ConfigurationPropertyAttributeRule, Justification = "this is not a configuration property")]
|
||||
public override Type BehaviorType
|
||||
{
|
||||
get { return typeof(RoutingBehavior); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty(ConfigurationStrings.RouteOnHeadersOnly, DefaultValue = RoutingConfiguration.DefaultRouteOnHeadersOnly, Options = ConfigurationPropertyOptions.None)]
|
||||
public bool RouteOnHeadersOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this[ConfigurationStrings.RouteOnHeadersOnly];
|
||||
}
|
||||
set
|
||||
{
|
||||
this[ConfigurationStrings.RouteOnHeadersOnly] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Configuration, FxCop.Rule.ConfigurationValidatorAttributeRule, Justification = "fxcop didn't like [StringValidator(MinLength = 0)]")]
|
||||
[ConfigurationProperty(ConfigurationStrings.FilterTableName, DefaultValue = null)]
|
||||
public string FilterTableName
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)this[ConfigurationStrings.FilterTableName];
|
||||
}
|
||||
set
|
||||
{
|
||||
this[ConfigurationStrings.FilterTableName] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(ConfigurationStrings.SoapProcessingEnabled, DefaultValue = RoutingConfiguration.DefaultSoapProcessingEnabled)]
|
||||
public bool SoapProcessingEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this[ConfigurationStrings.SoapProcessingEnabled];
|
||||
}
|
||||
set
|
||||
{
|
||||
this[ConfigurationStrings.SoapProcessingEnabled] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(ConfigurationStrings.EnsureOrderedDispatch, DefaultValue = RoutingConfiguration.DefaultEnsureOrderedDispatch)]
|
||||
public bool EnsureOrderedDispatch
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this[ConfigurationStrings.EnsureOrderedDispatch];
|
||||
}
|
||||
set
|
||||
{
|
||||
this[ConfigurationStrings.EnsureOrderedDispatch] = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected internal override object CreateBehavior()
|
||||
{
|
||||
RoutingConfiguration config;
|
||||
if (string.IsNullOrEmpty(this.FilterTableName))
|
||||
{
|
||||
config = new RoutingConfiguration();
|
||||
config.RouteOnHeadersOnly = this.RouteOnHeadersOnly;
|
||||
}
|
||||
else
|
||||
{
|
||||
config = new RoutingConfiguration(RoutingSection.CreateFilterTable(this.FilterTableName), this.RouteOnHeadersOnly);
|
||||
}
|
||||
|
||||
config.SoapProcessingEnabled = this.SoapProcessingEnabled;
|
||||
config.EnsureOrderedDispatch = this.EnsureOrderedDispatch;
|
||||
RoutingBehavior behavior = new RoutingBehavior(config);
|
||||
//behavior.Impersonation = this.Impersonation;
|
||||
return behavior;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,41 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing.Configuration
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.ServiceModel.Configuration;
|
||||
using System.Configuration;
|
||||
|
||||
public class SoapProcessingExtensionElement : BehaviorExtensionElement
|
||||
{
|
||||
[SuppressMessage(FxCop.Category.Configuration, FxCop.Rule.ConfigurationPropertyAttributeRule, Justification = "this is not a configuration property")]
|
||||
public override Type BehaviorType
|
||||
{
|
||||
get { return typeof(SoapProcessingBehavior); }
|
||||
}
|
||||
|
||||
protected internal override object CreateBehavior()
|
||||
{
|
||||
SoapProcessingBehavior behavior = new SoapProcessingBehavior();
|
||||
behavior.ProcessMessages = this.ProcessMessages;
|
||||
return behavior;
|
||||
}
|
||||
|
||||
[ConfigurationProperty(ConfigurationStrings.ProcessMessages, DefaultValue = true, Options = ConfigurationPropertyOptions.None)]
|
||||
public bool ProcessMessages
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this[ConfigurationStrings.ProcessMessages];
|
||||
}
|
||||
set
|
||||
{
|
||||
this[ConfigurationStrings.ProcessMessages] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Xml;
|
||||
using System.Runtime;
|
||||
|
||||
class DelegatingHeader : MessageHeader
|
||||
{
|
||||
int index;
|
||||
MessageHeaderInfo info;
|
||||
MessageHeaders originalHeaders;
|
||||
|
||||
public DelegatingHeader(MessageHeaderInfo info, MessageHeaders originalHeaders)
|
||||
{
|
||||
Fx.Assert(info != null, "info is required");
|
||||
Fx.Assert(originalHeaders != null, "originalHeaders is required");
|
||||
|
||||
this.info = info;
|
||||
this.originalHeaders = originalHeaders;
|
||||
this.index = -1;
|
||||
}
|
||||
|
||||
void EnsureIndex()
|
||||
{
|
||||
if (this.index < 0)
|
||||
{
|
||||
this.index = this.originalHeaders.FindHeader(this.info.Name, this.info.Namespace);
|
||||
if (this.index < 0)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.SourceHeaderNotFound(this.info.Name, this.info.Namespace)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
|
||||
{
|
||||
this.EnsureIndex();
|
||||
this.originalHeaders.WriteHeaderContents(index, writer);
|
||||
this.index = -1;
|
||||
}
|
||||
|
||||
protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
|
||||
{
|
||||
this.EnsureIndex();
|
||||
this.originalHeaders.WriteStartHeader(this.index, writer);
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return this.info.Name; }
|
||||
}
|
||||
|
||||
public override string Namespace
|
||||
{
|
||||
get { return this.info.Namespace; }
|
||||
}
|
||||
|
||||
public override bool MustUnderstand
|
||||
{
|
||||
get { return this.info.MustUnderstand; }
|
||||
}
|
||||
|
||||
public override string Actor
|
||||
{
|
||||
get { return this.info.Actor; }
|
||||
}
|
||||
|
||||
public override bool IsReferenceParameter
|
||||
{
|
||||
get { return this.info.IsReferenceParameter; }
|
||||
}
|
||||
|
||||
public override bool Relay
|
||||
{
|
||||
get { return base.Relay; }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Description;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
|
||||
sealed class GenericTransactionFlowAttribute : Attribute, IOperationBehavior
|
||||
{
|
||||
TransactionFlowAttribute transactionFlowAttribute;
|
||||
|
||||
public GenericTransactionFlowAttribute(TransactionFlowOption flowOption)
|
||||
{
|
||||
this.transactionFlowAttribute = new TransactionFlowAttribute(flowOption);
|
||||
}
|
||||
|
||||
void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
|
||||
{
|
||||
((IOperationBehavior)this.transactionFlowAttribute).AddBindingParameters(operationDescription, bindingParameters);
|
||||
}
|
||||
|
||||
void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
|
||||
{
|
||||
((IOperationBehavior)this.transactionFlowAttribute).ApplyClientBehavior(operationDescription, clientOperation);
|
||||
}
|
||||
|
||||
void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
|
||||
{
|
||||
((IOperationBehavior)this.transactionFlowAttribute).ApplyDispatchBehavior(operationDescription, dispatchOperation);
|
||||
}
|
||||
|
||||
void IOperationBehavior.Validate(OperationDescription operationDescription)
|
||||
{
|
||||
((IOperationBehavior)this.transactionFlowAttribute).Validate(operationDescription);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
|
||||
[ServiceContract(Namespace = RoutingUtilities.RoutingNamespace, SessionMode = SessionMode.Allowed)]
|
||||
interface IDuplexRouterCallback
|
||||
{
|
||||
[OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]
|
||||
[GenericTransactionFlow(TransactionFlowOption.Allowed)]
|
||||
IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback, object state);
|
||||
|
||||
void EndProcessMessage(IAsyncResult result);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
|
||||
[ServiceContract(Namespace = RoutingUtilities.RoutingNamespace, SessionMode = SessionMode.Required, CallbackContract = typeof(IDuplexRouterCallback))]
|
||||
public interface IDuplexSessionRouter
|
||||
{
|
||||
[OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]
|
||||
[GenericTransactionFlow(TransactionFlowOption.Allowed)]
|
||||
IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback, object state);
|
||||
|
||||
void EndProcessMessage(IAsyncResult result);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
|
||||
[ServiceContract(Namespace = RoutingUtilities.RoutingNamespace, SessionMode = SessionMode.Allowed)]
|
||||
public interface IRequestReplyRouter
|
||||
{
|
||||
[OperationContract(AsyncPattern = true, IsOneWay = false, Action = "*", ReplyAction = "*")]
|
||||
[GenericTransactionFlow(TransactionFlowOption.Allowed)]
|
||||
IAsyncResult BeginProcessRequest(Message message, AsyncCallback callback, object state);
|
||||
|
||||
Message EndProcessRequest(IAsyncResult result);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Transactions;
|
||||
|
||||
interface IRoutingClient
|
||||
{
|
||||
IAsyncResult BeginOperation(Message message, Transaction transaction, AsyncCallback callback, object state);
|
||||
Message EndOperation(IAsyncResult result);
|
||||
event EventHandler Faulted;
|
||||
RoutingEndpointTrait Key { get; }
|
||||
CommunicationState State { get; }
|
||||
void Open();
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
|
||||
[ServiceContract(Namespace = RoutingUtilities.RoutingNamespace, SessionMode = SessionMode.Allowed)]
|
||||
public interface ISimplexDatagramRouter
|
||||
{
|
||||
[OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]
|
||||
IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback, object state);
|
||||
|
||||
void EndProcessMessage(IAsyncResult result);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
|
||||
[ServiceContract(Namespace = RoutingUtilities.RoutingNamespace, SessionMode = SessionMode.Required)]
|
||||
public interface ISimplexSessionRouter
|
||||
{
|
||||
[OperationContract(AsyncPattern = true, IsOneWay = true, Action = "*")]
|
||||
IAsyncResult BeginProcessMessage(Message message, AsyncCallback callback, object state);
|
||||
|
||||
void EndProcessMessage(IAsyncResult result);
|
||||
}
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Runtime;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Activation;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Description;
|
||||
using System.ServiceModel.Security;
|
||||
using System.Transactions;
|
||||
using SR2 = System.ServiceModel.Routing.SR;
|
||||
using System.Security.Principal;
|
||||
using System.Runtime.Diagnostics;
|
||||
using System.ServiceModel.Diagnostics;
|
||||
|
||||
// This class wraps a Message, MessageBuffer (if requested), and the OperationContext
|
||||
// The message is not buffered if nobody calls MessageRpc.CreateBuffer. If the message
|
||||
// is buffered, then we hang on to the buffer so it can be reused and Clone the message
|
||||
// which became invalid when we buffered this message.
|
||||
class MessageRpc
|
||||
{
|
||||
const int ERROR_BAD_IMPERSONATION_LEVEL = 1346;
|
||||
|
||||
Message originalMessage;
|
||||
Message clonedMessage;
|
||||
MessageBuffer messageBuffer;
|
||||
string uniqueID;
|
||||
Transaction transaction;
|
||||
ReceiveContext receiveContext;
|
||||
IList<SendOperation> operations;
|
||||
WindowsIdentity windowsIdentity;
|
||||
EventTraceActivity eventTraceActivity;
|
||||
|
||||
public MessageRpc(Message message, OperationContext operationContext, bool impersonationRequired)
|
||||
{
|
||||
Fx.Assert(message != null, "message cannot be null");
|
||||
Fx.Assert(operationContext != null, "operationContext cannot be null");
|
||||
|
||||
this.originalMessage = message;
|
||||
this.OperationContext = operationContext;
|
||||
|
||||
if (Fx.Trace.IsEtwProviderEnabled)
|
||||
{
|
||||
this.eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
|
||||
}
|
||||
|
||||
//passing in true causes this to return null if the thread is not impersonating.
|
||||
this.windowsIdentity = WindowsIdentity.GetCurrent(true);
|
||||
if (impersonationRequired && !AspNetEnvironment.Current.AspNetCompatibilityEnabled)
|
||||
{
|
||||
if (this.windowsIdentity == null || this.windowsIdentity.ImpersonationLevel != TokenImpersonationLevel.Impersonation)
|
||||
{
|
||||
//Temporarily revert impersonation to process token to throw an exception
|
||||
IDisposable autoRevert = null;
|
||||
try
|
||||
{
|
||||
try { }
|
||||
finally
|
||||
{
|
||||
autoRevert = WindowsIdentity.Impersonate(IntPtr.Zero);
|
||||
}
|
||||
|
||||
Win32Exception errorDetail = new Win32Exception(ERROR_BAD_IMPERSONATION_LEVEL);
|
||||
throw FxTrace.Exception.AsError(new SecurityNegotiationException(errorDetail.Message));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (autoRevert != null)
|
||||
{
|
||||
autoRevert.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReceiveContext.TryGet(message, out this.receiveContext);
|
||||
|
||||
this.transaction = Transaction.Current;
|
||||
if (this.transaction == null)
|
||||
{
|
||||
this.transaction = TransactionMessageProperty.TryGetTransaction(message);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool Impersonating
|
||||
{
|
||||
get { return this.windowsIdentity != null; }
|
||||
}
|
||||
|
||||
internal EventTraceActivity EventTraceActivity
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.eventTraceActivity;
|
||||
}
|
||||
}
|
||||
|
||||
public OperationContext OperationContext
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string UniqueID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.uniqueID == null)
|
||||
{
|
||||
if (this.Message.Version != MessageVersion.None &&
|
||||
this.Message.Headers.MessageId != null)
|
||||
{
|
||||
this.uniqueID = this.originalMessage.Headers.MessageId.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.uniqueID = this.GetHashCode().ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
return this.uniqueID;
|
||||
}
|
||||
}
|
||||
|
||||
public Message Message
|
||||
{
|
||||
get
|
||||
{
|
||||
// If we've created a MessageBuffer then the originalMessage has already been consumed
|
||||
if (this.messageBuffer != null)
|
||||
{
|
||||
Fx.Assert(this.clonedMessage != null, "Need to set clonedMessage if we buffered the message");
|
||||
return this.clonedMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Haven't buffered, can use the original.
|
||||
return this.originalMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ReceiveContext ReceiveContext
|
||||
{
|
||||
get { return this.receiveContext; }
|
||||
}
|
||||
|
||||
public IList<SendOperation> Operations
|
||||
{
|
||||
get { return this.operations; }
|
||||
}
|
||||
|
||||
public Transaction Transaction
|
||||
{
|
||||
get { return this.transaction; }
|
||||
}
|
||||
|
||||
public MessageBuffer CreateBuffer()
|
||||
{
|
||||
if (this.messageBuffer == null)
|
||||
{
|
||||
this.messageBuffer = this.originalMessage.CreateBufferedCopy(int.MaxValue);
|
||||
this.clonedMessage = this.messageBuffer.CreateMessage();
|
||||
}
|
||||
return this.messageBuffer;
|
||||
}
|
||||
|
||||
public IDisposable PrepareCall()
|
||||
{
|
||||
return new CallState(this);
|
||||
}
|
||||
|
||||
public void RouteToSingleEndpoint<TContract>(RoutingConfiguration routingConfig)
|
||||
{
|
||||
IEnumerable<ServiceEndpoint> result;
|
||||
if (routingConfig.RouteOnHeadersOnly)
|
||||
{
|
||||
if (TD.RoutingServiceFilterTableMatchStartIsEnabled()) { TD.RoutingServiceFilterTableMatchStart(this.eventTraceActivity); }
|
||||
routingConfig.InternalFilterTable.GetMatchingValue(this.Message, out result);
|
||||
if (TD.RoutingServiceFilterTableMatchStopIsEnabled()) { TD.RoutingServiceFilterTableMatchStop(this.eventTraceActivity); }
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBuffer buffer = this.CreateBuffer();
|
||||
|
||||
if (TD.RoutingServiceFilterTableMatchStartIsEnabled()) { TD.RoutingServiceFilterTableMatchStart(this.eventTraceActivity); }
|
||||
routingConfig.InternalFilterTable.GetMatchingValue(buffer, out result);
|
||||
if (TD.RoutingServiceFilterTableMatchStopIsEnabled()) { TD.RoutingServiceFilterTableMatchStop(this.eventTraceActivity); }
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.NoFilterMatched));
|
||||
}
|
||||
|
||||
if (TD.RoutingServiceMessageRoutedToEndpointsIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceMessageRoutedToEndpoints(this.eventTraceActivity, this.UniqueID, "1");
|
||||
}
|
||||
|
||||
this.operations = new List<SendOperation>(1);
|
||||
this.operations.Add(new SendOperation(result, typeof(TContract), this.OperationContext));
|
||||
}
|
||||
|
||||
public void RouteToEndpoints<TContract>(RoutingConfiguration routingConfig)
|
||||
{
|
||||
List<IEnumerable<ServiceEndpoint>> endpointLists = new List<IEnumerable<ServiceEndpoint>>();
|
||||
if (routingConfig.RouteOnHeadersOnly)
|
||||
{
|
||||
if (TD.RoutingServiceFilterTableMatchStartIsEnabled()) { TD.RoutingServiceFilterTableMatchStart(this.eventTraceActivity); }
|
||||
routingConfig.InternalFilterTable.GetMatchingValues(this.Message, endpointLists);
|
||||
if (TD.RoutingServiceFilterTableMatchStopIsEnabled()) { TD.RoutingServiceFilterTableMatchStop(this.eventTraceActivity); }
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBuffer messageBuffer = this.CreateBuffer();
|
||||
|
||||
if (TD.RoutingServiceFilterTableMatchStartIsEnabled()) { TD.RoutingServiceFilterTableMatchStart(this.eventTraceActivity); }
|
||||
routingConfig.InternalFilterTable.GetMatchingValues(messageBuffer, endpointLists);
|
||||
if (TD.RoutingServiceFilterTableMatchStopIsEnabled()) { TD.RoutingServiceFilterTableMatchStop(this.eventTraceActivity); }
|
||||
}
|
||||
|
||||
if (TD.RoutingServiceMessageRoutedToEndpointsIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceMessageRoutedToEndpoints(this.eventTraceActivity, this.UniqueID, endpointLists.Count.ToString(TD.Culture));
|
||||
}
|
||||
if (endpointLists.Count == 0)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR2.NoFilterMatched));
|
||||
}
|
||||
this.operations = new List<SendOperation>(endpointLists.Count);
|
||||
foreach (IEnumerable<ServiceEndpoint> endpointList in endpointLists)
|
||||
{
|
||||
this.operations.Add(new SendOperation(endpointList, typeof(TContract), this.OperationContext));
|
||||
}
|
||||
}
|
||||
|
||||
class CallState : IDisposable
|
||||
{
|
||||
OperationContextScope nullContextScope;
|
||||
WindowsImpersonationContext impersonation;
|
||||
|
||||
public CallState (MessageRpc messageRpc)
|
||||
{
|
||||
this.nullContextScope = new OperationContextScope((OperationContext)null);
|
||||
|
||||
if (messageRpc.windowsIdentity != null)
|
||||
{
|
||||
this.impersonation = messageRpc.windowsIdentity.Impersonate();
|
||||
}
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
if (this.impersonation != null)
|
||||
{
|
||||
this.impersonation.Dispose();
|
||||
}
|
||||
this.nullContextScope.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,281 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Runtime;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
using System.ServiceModel.Security;
|
||||
using System.Threading;
|
||||
using System.Transactions;
|
||||
//using System.Security.Principal;
|
||||
|
||||
class ProcessRequestAsyncResult<TContract> : TransactedAsyncResult
|
||||
{
|
||||
static AsyncCompletion operationCallback = new AsyncCompletion(OperationCallback);
|
||||
RoutingService service;
|
||||
IRoutingClient currentClient;
|
||||
MessageRpc messageRpc;
|
||||
Message replyMessage;
|
||||
bool allCompletedSync;
|
||||
bool abortedRetry;
|
||||
|
||||
public ProcessRequestAsyncResult(RoutingService service, Message message, AsyncCallback callback, object state)
|
||||
: base(callback, state)
|
||||
{
|
||||
this.allCompletedSync = true;
|
||||
this.service = service;
|
||||
this.messageRpc = new MessageRpc(message, OperationContext.Current, service.ChannelExtension.ImpersonationRequired);
|
||||
if (TD.RoutingServiceProcessingMessageIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceProcessingMessage(this.messageRpc.EventTraceActivity, this.messageRpc.UniqueID,
|
||||
message.Headers.Action, this.messageRpc.OperationContext.EndpointDispatcher.EndpointAddress.Uri.ToString(), messageRpc.Transaction != null ? "True" : "False");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
EndpointNameMessageFilter.Set(this.messageRpc.Message.Properties, service.ChannelExtension.EndpointName);
|
||||
this.messageRpc.RouteToSingleEndpoint<TContract>(this.service.RoutingConfig);
|
||||
}
|
||||
catch (MultipleFilterMatchesException matchesException)
|
||||
{
|
||||
// Wrap this exception with one that is more meaningful to users of RoutingService:
|
||||
throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR.ReqReplyMulticastNotSupported(this.messageRpc.OperationContext.Channel.LocalAddress), matchesException));
|
||||
}
|
||||
|
||||
while (this.StartProcessing())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
bool StartProcessing()
|
||||
{
|
||||
bool callAgain = false;
|
||||
SendOperation sendOperation = this.messageRpc.Operations[0];
|
||||
this.currentClient = this.service.GetOrCreateClient<TContract>(sendOperation.CurrentEndpoint, this.messageRpc.Impersonating);
|
||||
|
||||
if (TD.RoutingServiceTransmittingMessageIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceTransmittingMessage(this.messageRpc.EventTraceActivity, this.messageRpc.UniqueID, "0", this.currentClient.Key.ToString());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (messageRpc.Transaction != null && sendOperation.HasAlternate)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR.ErrorHandlingNotSupportedReqReplyTxn(this.messageRpc.OperationContext.Channel.LocalAddress)));
|
||||
}
|
||||
|
||||
// We always work on cloned message when there are backup endpoints to handle exception cases
|
||||
Message message;
|
||||
if (sendOperation.AlternateEndpointCount > 0)
|
||||
{
|
||||
message = messageRpc.CreateBuffer().CreateMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
message = messageRpc.Message;
|
||||
}
|
||||
|
||||
sendOperation.PrepareMessage(message);
|
||||
|
||||
IAsyncResult result = null;
|
||||
using (this.PrepareTransactionalCall(messageRpc.Transaction))
|
||||
{
|
||||
IDisposable impersonationContext = null;
|
||||
try
|
||||
{
|
||||
//Perform the assignment in a finally block so it won't be interrupted asynchronously
|
||||
try { }
|
||||
finally
|
||||
{
|
||||
impersonationContext = messageRpc.PrepareCall();
|
||||
}
|
||||
result = this.currentClient.BeginOperation(message, messageRpc.Transaction, this.PrepareAsyncCompletion(operationCallback), this);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (impersonationContext != null)
|
||||
{
|
||||
impersonationContext.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.CheckSyncContinue(result))
|
||||
{
|
||||
if (this.OperationComplete(result))
|
||||
{
|
||||
this.Complete(this.allCompletedSync);
|
||||
}
|
||||
else
|
||||
{
|
||||
callAgain = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (Fx.IsFatal(exception))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
if (!this.HandleClientOperationFailure(exception))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
callAgain = true;
|
||||
}
|
||||
return callAgain;
|
||||
}
|
||||
|
||||
static bool OperationCallback(IAsyncResult result)
|
||||
{
|
||||
ProcessRequestAsyncResult<TContract> thisPtr = (ProcessRequestAsyncResult<TContract>)result.AsyncState;
|
||||
FxTrace.Trace.SetAndTraceTransfer(thisPtr.service.ChannelExtension.ActivityID, true);
|
||||
thisPtr.allCompletedSync = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (thisPtr.OperationComplete(result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (Fx.IsFatal(exception))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
if (!thisPtr.HandleClientOperationFailure(exception))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
while (thisPtr.StartProcessing())
|
||||
{
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if we're all done and can complete this AsyncResult now
|
||||
bool OperationComplete(IAsyncResult result)
|
||||
{
|
||||
bool completeSelf = false;
|
||||
Message responseMsg = this.currentClient.EndOperation(result);
|
||||
|
||||
if (TD.RoutingServiceTransmitSucceededIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceTransmitSucceeded(this.messageRpc.EventTraceActivity, this.messageRpc.UniqueID, "0", this.currentClient.Key.ToString());
|
||||
}
|
||||
|
||||
if (responseMsg == null || !responseMsg.IsFault)
|
||||
{
|
||||
if (TD.RoutingServiceSendingResponseIsEnabled())
|
||||
{
|
||||
string action = (responseMsg != null) ? responseMsg.Headers.Action : string.Empty;
|
||||
TD.RoutingServiceSendingResponse(this.messageRpc.EventTraceActivity, action);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TD.RoutingServiceSendingFaultResponseIsEnabled()) { TD.RoutingServiceSendingFaultResponse(this.messageRpc.EventTraceActivity, responseMsg.Headers.Action); }
|
||||
}
|
||||
this.replyMessage = responseMsg;
|
||||
completeSelf = true;
|
||||
|
||||
if (TD.RoutingServiceCompletingTwoWayIsEnabled()) { TD.RoutingServiceCompletingTwoWay(this.messageRpc.EventTraceActivity); }
|
||||
return completeSelf;
|
||||
}
|
||||
|
||||
internal static Message End(IAsyncResult result)
|
||||
{
|
||||
ProcessRequestAsyncResult<TContract> processRequest = AsyncResult.End<ProcessRequestAsyncResult<TContract>>(result);
|
||||
return processRequest.replyMessage;
|
||||
}
|
||||
|
||||
bool HandleClientOperationFailure(Exception exception)
|
||||
{
|
||||
SendOperation sendOperation = this.messageRpc.Operations[0];
|
||||
if (TD.RoutingServiceTransmitFailedIsEnabled()) { TD.RoutingServiceTransmitFailed(this.messageRpc.EventTraceActivity, sendOperation.CurrentEndpoint.ToString(), exception); }
|
||||
|
||||
if (!(exception is CommunicationException || exception is TimeoutException))
|
||||
{
|
||||
//We only move to backup for CommunicationExceptions and TimeoutExceptions
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((exception is CommunicationObjectAbortedException || exception is CommunicationObjectFaultedException) &&
|
||||
!this.service.ChannelExtension.HasSession)
|
||||
{
|
||||
// Messages on a non sessionful channel share outbound connections and can
|
||||
// fail due to other messages failing on the same channel
|
||||
if (messageRpc.Transaction == null && !this.abortedRetry)
|
||||
{
|
||||
//No session and non transactional, retry the message 1 time (before moving to backup)
|
||||
this.abortedRetry = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (exception is EndpointNotFoundException)
|
||||
{
|
||||
// The channel may not fault for this exception for bindings other than netTcpBinding
|
||||
// We abort the channel in that case. We proactively clean up so that we don't have to cleanup later
|
||||
SessionChannels sessionChannels = this.service.GetSessionChannels(this.messageRpc.Impersonating);
|
||||
if (sessionChannels != null)
|
||||
{
|
||||
sessionChannels.AbortChannel(sendOperation.CurrentEndpoint);
|
||||
}
|
||||
}
|
||||
else if (exception is MessageSecurityException)
|
||||
{
|
||||
// The service may have been stopped and restarted without the routing service knowledge.
|
||||
// When we try to use a cached channel to the service, the channel can fault due to this exception
|
||||
// The faulted channel gets cleaned up and we retry one more time only when service has backup
|
||||
// If there is no backup, we do not retry since we do not create a buffered message to prevent performance degradation
|
||||
if (!this.abortedRetry && (sendOperation.AlternateEndpointCount > 0))
|
||||
{
|
||||
this.abortedRetry = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (exception is ProtocolException)
|
||||
{
|
||||
// This exception may happen when the current cached channel was closed due to end service recycles.
|
||||
// We abort the channel in this case and clean it up from the session.
|
||||
// We will then retry the request one more time only. In retried request, it will create a new channel because the cached channel has been cleaned up.
|
||||
if (!this.abortedRetry)
|
||||
{
|
||||
SessionChannels sessionChannels = this.service.GetSessionChannels(this.messageRpc.Impersonating);
|
||||
if (sessionChannels != null)
|
||||
{
|
||||
this.abortedRetry = true;
|
||||
sessionChannels.AbortChannel(sendOperation.CurrentEndpoint);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sendOperation.TryMoveToAlternate(exception))
|
||||
{
|
||||
if (TD.RoutingServiceMovedToBackupIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceMovedToBackup(this.messageRpc.EventTraceActivity, messageRpc.UniqueID, "0", sendOperation.CurrentEndpoint.ToString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,282 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Activation;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Description;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
|
||||
[Fx.Tag.XamlVisible(false)]
|
||||
public sealed class RoutingBehavior : IServiceBehavior
|
||||
{
|
||||
RoutingConfiguration configuration;
|
||||
|
||||
public RoutingBehavior(RoutingConfiguration routingConfiguration)
|
||||
{
|
||||
if (routingConfiguration == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("routingConfiguration");
|
||||
}
|
||||
|
||||
this.configuration = routingConfiguration;
|
||||
}
|
||||
|
||||
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
|
||||
{
|
||||
}
|
||||
|
||||
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
|
||||
{
|
||||
RoutingExtension routingExtension = new RoutingExtension(this.configuration);
|
||||
serviceHostBase.Extensions.Add(routingExtension);
|
||||
for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
|
||||
{
|
||||
ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
|
||||
if (channelDispatcher != null)
|
||||
{
|
||||
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
|
||||
{
|
||||
if (!endpointDispatcher.IsSystemEndpoint &&
|
||||
RoutingUtilities.IsRoutingServiceNamespace(endpointDispatcher.ContractNamespace))
|
||||
{
|
||||
DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
|
||||
//Since we use PerSession instancing this concurrency only applies to messages
|
||||
//in the same session, also needed to maintain order.
|
||||
dispatchRuntime.ConcurrencyMode = ConcurrencyMode.Single;
|
||||
dispatchRuntime.EnsureOrderedDispatch = this.configuration.EnsureOrderedDispatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
|
||||
{
|
||||
HashSet<string> endpoints = new HashSet<string>();
|
||||
foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
|
||||
{
|
||||
if (!endpoint.IsSystemEndpoint &&
|
||||
RoutingUtilities.IsRoutingServiceNamespace(endpoint.Contract.Namespace))
|
||||
{
|
||||
endpoint.Behaviors.Add(new RoutingEndpointBehavior(endpoint));
|
||||
endpoints.Add(endpoint.Name);
|
||||
}
|
||||
}
|
||||
EndpointNameMessageFilter.Validate(this.configuration.InternalFilterTable.Keys, endpoints);
|
||||
}
|
||||
|
||||
public static Type GetContractForDescription(ContractDescription description)
|
||||
{
|
||||
if (description == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("description");
|
||||
}
|
||||
|
||||
if (description.CallbackContractType != null)
|
||||
{
|
||||
return typeof(IDuplexSessionRouter);
|
||||
}
|
||||
|
||||
bool allOneWay = true;
|
||||
foreach (OperationDescription operation in description.Operations)
|
||||
{
|
||||
if (!operation.IsOneWay)
|
||||
{
|
||||
allOneWay = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allOneWay)
|
||||
{
|
||||
if (description.SessionMode == SessionMode.Required)
|
||||
{
|
||||
return typeof(ISimplexSessionRouter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return typeof(ISimplexDatagramRouter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return typeof(IRequestReplyRouter);
|
||||
}
|
||||
}
|
||||
|
||||
internal class RoutingEndpointBehavior : IEndpointBehavior, IChannelInitializer, IInputSessionShutdown
|
||||
{
|
||||
public RoutingEndpointBehavior(ServiceEndpoint endpoint)
|
||||
{
|
||||
this.Endpoint = endpoint;
|
||||
this.EndpointName = endpoint.Name;
|
||||
}
|
||||
|
||||
internal ChannelDispatcher ChannelDispatcher
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal ServiceEndpoint Endpoint
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal string EndpointName
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal bool ImpersonationRequired
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal bool ReceiveContextEnabled
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
internal bool TransactedReceiveEnabled
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
|
||||
{
|
||||
//Turn on ReceiveContext here if supported
|
||||
IReceiveContextSettings receiveContextSettings = endpoint.Binding.GetProperty<IReceiveContextSettings>(bindingParameters);
|
||||
if (receiveContextSettings != null)
|
||||
{
|
||||
receiveContextSettings.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
|
||||
{
|
||||
this.ChannelDispatcher = endpointDispatcher.ChannelDispatcher;
|
||||
this.ChannelDispatcher.ChannelInitializers.Add(this);
|
||||
endpointDispatcher.DispatchRuntime.InputSessionShutdownHandlers.Add(this);
|
||||
endpointDispatcher.DispatchRuntime.AutomaticInputSessionShutdown = false;
|
||||
|
||||
if (endpointDispatcher.DispatchRuntime.ImpersonateCallerForAllOperations)
|
||||
{
|
||||
this.ImpersonationRequired = true;
|
||||
}
|
||||
else if (AspNetEnvironment.Current.AspNetCompatibilityEnabled)
|
||||
{
|
||||
this.ImpersonationRequired = true;
|
||||
}
|
||||
|
||||
BindingParameterCollection bindingParams = new BindingParameterCollection();
|
||||
if (RoutingUtilities.IsTransactedReceive(endpoint.Binding, bindingParams))
|
||||
{
|
||||
foreach (OperationDescription operation in endpoint.Contract.Operations)
|
||||
{
|
||||
if (operation.Behaviors.Find<TransactedReceiveOperationBehavior>() == null)
|
||||
{
|
||||
operation.Behaviors.Add(new TransactedReceiveOperationBehavior());
|
||||
}
|
||||
}
|
||||
this.ChannelDispatcher.IsTransactedReceive = true;
|
||||
endpointDispatcher.DispatchRuntime.TransactionAutoCompleteOnSessionClose = true;
|
||||
this.TransactedReceiveEnabled = true;
|
||||
}
|
||||
|
||||
IReceiveContextSettings rcSettings = endpoint.Binding.GetProperty<IReceiveContextSettings>(bindingParams);
|
||||
if (rcSettings != null && rcSettings.Enabled)
|
||||
{
|
||||
foreach (OperationDescription operation in endpoint.Contract.Operations)
|
||||
{
|
||||
ReceiveContextEnabledAttribute rcEnabled = new ReceiveContextEnabledAttribute();
|
||||
rcEnabled.ManualControl = true;
|
||||
operation.Behaviors.Add(rcEnabled);
|
||||
}
|
||||
this.ReceiveContextEnabled = true;
|
||||
|
||||
//Switch TransactedReceive off, because we don't want the Dispatcher creating any Transaction
|
||||
endpointDispatcher.ChannelDispatcher.IsTransactedReceive = false;
|
||||
endpointDispatcher.DispatchRuntime.TransactionAutoCompleteOnSessionClose = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Validate(ServiceEndpoint endpoint)
|
||||
{
|
||||
}
|
||||
|
||||
void IChannelInitializer.Initialize(IClientChannel channel)
|
||||
{
|
||||
RoutingChannelExtension channelState = RoutingChannelExtension.Create(this);
|
||||
channel.Extensions.Add(channelState);
|
||||
}
|
||||
|
||||
void IInputSessionShutdown.ChannelFaulted(IDuplexContextChannel channel)
|
||||
{
|
||||
RoutingChannelExtension channelExtension = channel.Extensions.Find<RoutingChannelExtension>();
|
||||
if (channelExtension != null)
|
||||
{
|
||||
channelExtension.Fault(new CommunicationObjectFaultedException());
|
||||
}
|
||||
else
|
||||
{
|
||||
RoutingUtilities.Abort(channel, channel.LocalAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void IInputSessionShutdown.DoneReceiving(IDuplexContextChannel channel)
|
||||
{
|
||||
RoutingChannelExtension channelExtension = channel.Extensions.Find<RoutingChannelExtension>();
|
||||
channelExtension.DoneReceiving(this.Endpoint.Binding.CloseTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
class TransactedReceiveOperationBehavior : IOperationBehavior
|
||||
{
|
||||
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
|
||||
{
|
||||
if (operationDescription.Behaviors.Find<ReceiveContextEnabledAttribute>() == null)
|
||||
{
|
||||
dispatchOperation.TransactionRequired = true;
|
||||
}
|
||||
|
||||
ContractDescription contract = operationDescription.DeclaringContract;
|
||||
if (dispatchOperation.IsOneWay && contract.SessionMode == SessionMode.Required)
|
||||
{
|
||||
dispatchOperation.Parent.ConcurrencyMode = ConcurrencyMode.Single;
|
||||
dispatchOperation.Parent.ReleaseServiceInstanceOnTransactionComplete = false;
|
||||
dispatchOperation.TransactionAutoComplete = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Validate(OperationDescription operationDescription)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,289 @@
|
||||
//----------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Routing
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
abstract class RoutingChannelExtension : IExtension<IContextChannel>
|
||||
{
|
||||
static AsyncCallback closeChannelsCallback = Fx.ThunkCallback(CloseChannelsCallback);
|
||||
static AsyncCallback shutdownCallback = Fx.ThunkCallback(ShutdownCallback);
|
||||
IContextChannel channel;
|
||||
bool hasSession;
|
||||
RoutingBehavior.RoutingEndpointBehavior endpointBehavior;
|
||||
RoutingService sessionService;
|
||||
volatile SessionChannels sessionChannels;
|
||||
[Fx.Tag.SynchronizationObject]
|
||||
object thisLock;
|
||||
|
||||
public RoutingChannelExtension(RoutingBehavior.RoutingEndpointBehavior endpointBehavior)
|
||||
{
|
||||
this.ActivityID = Guid.NewGuid();
|
||||
this.endpointBehavior = endpointBehavior;
|
||||
this.thisLock = new object();
|
||||
}
|
||||
|
||||
internal Guid ActivityID
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string EndpointName
|
||||
{
|
||||
get { return this.endpointBehavior.EndpointName; }
|
||||
}
|
||||
|
||||
public bool HasSession
|
||||
{
|
||||
get { return this.hasSession; }
|
||||
}
|
||||
|
||||
public bool ImpersonationRequired
|
||||
{
|
||||
get { return this.endpointBehavior.ImpersonationRequired; }
|
||||
}
|
||||
|
||||
public TimeSpan OperationTimeout
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool ReceiveContextEnabled
|
||||
{
|
||||
get { return this.endpointBehavior.ReceiveContextEnabled; }
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "get_SessionChannels is called by RoutingService..ctor")]
|
||||
public SessionChannels SessionChannels
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.sessionChannels == null)
|
||||
{
|
||||
lock (this.thisLock)
|
||||
{
|
||||
if (this.sessionChannels == null)
|
||||
{
|
||||
Fx.AssertAndThrow(!(this.ImpersonationRequired && !this.HasSession), "Shouldn't allocate SessionChannels if session-less and impersonating");
|
||||
this.sessionChannels = new SessionChannels(this.ActivityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.sessionChannels;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TransactedReceiveEnabled
|
||||
{
|
||||
get { return this.endpointBehavior.TransactedReceiveEnabled; }
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "AttachService is called by RoutingService..ctor")]
|
||||
public void AttachService(RoutingService service)
|
||||
{
|
||||
SessionChannels channelsToClose = null;
|
||||
lock (this.thisLock)
|
||||
{
|
||||
if (!this.hasSession)
|
||||
{
|
||||
RoutingConfiguration oldConfig = null;
|
||||
if (this.sessionService != null)
|
||||
{
|
||||
oldConfig = this.sessionService.RoutingConfig;
|
||||
}
|
||||
|
||||
if (oldConfig != null && !object.ReferenceEquals(service.RoutingConfig, oldConfig))
|
||||
{
|
||||
//The RoutingConfiguration has changed. We need to release any old channels that are cached.
|
||||
channelsToClose = this.sessionChannels;
|
||||
this.sessionChannels = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Fx.Assert(this.sessionService == null, "There must only be one RoutingService created for a sessionful channel");
|
||||
}
|
||||
this.sessionService = service;
|
||||
}
|
||||
|
||||
if (channelsToClose != null)
|
||||
{
|
||||
channelsToClose.BeginClose(this.channel.OperationTimeout, closeChannelsCallback, channelsToClose);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract IAsyncResult BeginShutdown(RoutingService service, TimeSpan timeout, AsyncCallback callback, object state);
|
||||
|
||||
static void CloseChannelsCallback(IAsyncResult asyncResult)
|
||||
{
|
||||
SessionChannels channelsToClose = (SessionChannels)asyncResult.AsyncState;
|
||||
Exception exception = null;
|
||||
try
|
||||
{
|
||||
channelsToClose.EndClose(asyncResult);
|
||||
}
|
||||
catch (CommunicationException communicationException)
|
||||
{
|
||||
exception = communicationException;
|
||||
}
|
||||
catch (TimeoutException timeoutException)
|
||||
{
|
||||
exception = timeoutException;
|
||||
}
|
||||
|
||||
if (exception != null && TD.RoutingServiceHandledExceptionIsEnabled())
|
||||
{
|
||||
TD.RoutingServiceHandledException(null, exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void ShutdownCallback(IAsyncResult result)
|
||||
{
|
||||
if (result.CompletedSynchronously)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RoutingChannelExtension thisPtr = (RoutingChannelExtension)result.AsyncState;
|
||||
try
|
||||
{
|
||||
thisPtr.ShutdownComplete(result);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (Fx.IsFatal(exception))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
thisPtr.Fault(exception);
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownComplete(IAsyncResult result)
|
||||
{
|
||||
this.EndShutdown(result);
|
||||
this.channel.Close();
|
||||
}
|
||||
|
||||
public static RoutingChannelExtension Create(RoutingBehavior.RoutingEndpointBehavior endpointBehavior)
|
||||
{
|
||||
Type contractType = endpointBehavior.Endpoint.Contract.ContractType;
|
||||
if (contractType == typeof(IDuplexSessionRouter))
|
||||
{
|
||||
return new RoutingChannelExtension<IDuplexSessionRouter>(endpointBehavior);
|
||||
}
|
||||
else if (contractType == typeof(ISimplexDatagramRouter))
|
||||
{
|
||||
return new RoutingChannelExtension<ISimplexDatagramRouter>(endpointBehavior);
|
||||
}
|
||||
else if (contractType == typeof(IRequestReplyRouter))
|
||||
{
|
||||
return new RoutingChannelExtension<IRequestReplyRouter>(endpointBehavior);
|
||||
}
|
||||
else
|
||||
{
|
||||
Fx.Assert(contractType == typeof(ISimplexSessionRouter), "Was a new contract added?");
|
||||
return new RoutingChannelExtension<ISimplexSessionRouter>(endpointBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
public void DoneReceiving(TimeSpan closeTimeout)
|
||||
{
|
||||
FxTrace.Trace.SetAndTraceTransfer(this.ActivityID, true);
|
||||
try
|
||||
{
|
||||
if (this.sessionService != null)
|
||||
{
|
||||
IAsyncResult result = this.BeginShutdown(this.sessionService, closeTimeout, shutdownCallback, this);
|
||||
if (result.CompletedSynchronously)
|
||||
{
|
||||
this.ShutdownComplete(result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.channel.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (Fx.IsFatal(exception))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
this.Fault(exception);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void EndShutdown(IAsyncResult result);
|
||||
|
||||
public void Fault(Exception exception)
|
||||
{
|
||||
FxTrace.Trace.SetAndTraceTransfer(this.ActivityID, true);
|
||||
|
||||
//Notify the error handlers that a problem occurred
|
||||
foreach (IErrorHandler errorHandler in this.endpointBehavior.ChannelDispatcher.ErrorHandlers)
|
||||
{
|
||||
if (errorHandler.HandleError(exception))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SessionChannels channelsToAbort;
|
||||
lock (this.thisLock)
|
||||
{
|
||||
channelsToAbort = this.sessionChannels;
|
||||
this.sessionChannels = null;
|
||||
}
|
||||
|
||||
if (channelsToAbort != null)
|
||||
{
|
||||
channelsToAbort.AbortAll();
|
||||
}
|
||||
|
||||
RoutingUtilities.Abort(this.channel, this.channel.LocalAddress);
|
||||
}
|
||||
|
||||
void IExtension<IContextChannel>.Attach(IContextChannel owner)
|
||||
{
|
||||
this.channel = owner;
|
||||
this.hasSession = (owner.InputSession != null);
|
||||
this.OperationTimeout = owner.OperationTimeout;
|
||||
}
|
||||
|
||||
void IExtension<IContextChannel>.Detach(IContextChannel owner)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
sealed class RoutingChannelExtension<T> : RoutingChannelExtension
|
||||
{
|
||||
public RoutingChannelExtension(RoutingBehavior.RoutingEndpointBehavior endpointBehavior)
|
||||
: base(endpointBehavior)
|
||||
{
|
||||
}
|
||||
|
||||
public override IAsyncResult BeginShutdown(RoutingService service, TimeSpan timeout, AsyncCallback callback, object state)
|
||||
{
|
||||
return new ProcessMessagesAsyncResult<T>(null, service, timeout, callback, state);
|
||||
}
|
||||
|
||||
public override void EndShutdown(IAsyncResult result)
|
||||
{
|
||||
ProcessMessagesAsyncResult<T>.End(result);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user