343 lines
13 KiB
C#
343 lines
13 KiB
C#
|
//----------------------------------------------------------------------------
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//----------------------------------------------------------------------------
|
||
|
namespace System.ServiceModel.Channels
|
||
|
{
|
||
|
using System.Collections.Generic;
|
||
|
using System.Runtime;
|
||
|
using System.ServiceModel;
|
||
|
using System.ServiceModel.Description;
|
||
|
using System.ServiceModel.Security;
|
||
|
using SR = System.ServiceModel.SR;
|
||
|
|
||
|
sealed class TransactionChannelFactory<TChannel> : LayeredChannelFactory<TChannel>, ITransactionChannelManager
|
||
|
{
|
||
|
TransactionFlowOption flowIssuedTokens;
|
||
|
SecurityStandardsManager standardsManager;
|
||
|
Dictionary<DirectionalAction, TransactionFlowOption> dictionary;
|
||
|
TransactionProtocol transactionProtocol;
|
||
|
bool allowWildcardAction;
|
||
|
|
||
|
public TransactionChannelFactory(
|
||
|
TransactionProtocol transactionProtocol,
|
||
|
BindingContext context,
|
||
|
Dictionary<DirectionalAction, TransactionFlowOption> dictionary,
|
||
|
bool allowWildcardAction)
|
||
|
: base(context.Binding, context.BuildInnerChannelFactory<TChannel>())
|
||
|
{
|
||
|
this.dictionary = dictionary;
|
||
|
this.TransactionProtocol = transactionProtocol;
|
||
|
this.allowWildcardAction = allowWildcardAction;
|
||
|
this.standardsManager = SecurityStandardsHelper.CreateStandardsManager(this.TransactionProtocol);
|
||
|
}
|
||
|
|
||
|
public TransactionProtocol TransactionProtocol
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return this.transactionProtocol;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (!TransactionProtocol.IsDefined(value))
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
||
|
new ArgumentException(SR.GetString(SR.SFxBadTransactionProtocols)));
|
||
|
this.transactionProtocol = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public TransactionFlowOption FlowIssuedTokens
|
||
|
{
|
||
|
get { return this.flowIssuedTokens; }
|
||
|
set { this.flowIssuedTokens = value; }
|
||
|
}
|
||
|
|
||
|
public SecurityStandardsManager StandardsManager
|
||
|
{
|
||
|
get { return this.standardsManager; }
|
||
|
set
|
||
|
{
|
||
|
this.standardsManager = (value != null ? value : SecurityStandardsHelper.CreateStandardsManager(this.transactionProtocol));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public IDictionary<DirectionalAction, TransactionFlowOption> Dictionary
|
||
|
{
|
||
|
get { return this.dictionary; }
|
||
|
}
|
||
|
|
||
|
public TransactionFlowOption GetTransaction(MessageDirection direction, string action)
|
||
|
{
|
||
|
TransactionFlowOption txOption;
|
||
|
if (!dictionary.TryGetValue(new DirectionalAction(direction, action), out txOption))
|
||
|
{
|
||
|
//Fixinng this for clients that opted in for lesser validation before flowing out a transaction
|
||
|
if (this.allowWildcardAction && dictionary.TryGetValue(new DirectionalAction(direction, MessageHeaders.WildcardAction), out txOption))
|
||
|
{
|
||
|
return txOption;
|
||
|
}
|
||
|
else
|
||
|
return TransactionFlowOption.NotAllowed;
|
||
|
}
|
||
|
|
||
|
else
|
||
|
return txOption;
|
||
|
}
|
||
|
|
||
|
protected override TChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)
|
||
|
{
|
||
|
TChannel innerChannel = ((IChannelFactory<TChannel>)InnerChannelFactory).CreateChannel(remoteAddress, via);
|
||
|
return CreateTransactionChannel(innerChannel);
|
||
|
}
|
||
|
|
||
|
TChannel CreateTransactionChannel(TChannel innerChannel)
|
||
|
{
|
||
|
if (typeof(TChannel) == typeof(IDuplexSessionChannel))
|
||
|
{
|
||
|
return (TChannel)(object)new TransactionDuplexSessionChannel(this, (IDuplexSessionChannel)(object)innerChannel);
|
||
|
}
|
||
|
else if (typeof(TChannel) == typeof(IRequestSessionChannel))
|
||
|
{
|
||
|
return (TChannel)(object)new TransactionRequestSessionChannel(this, (IRequestSessionChannel)(object)innerChannel);
|
||
|
}
|
||
|
else if (typeof(TChannel) == typeof(IOutputSessionChannel))
|
||
|
{
|
||
|
return (TChannel)(object)new TransactionOutputSessionChannel(this, (IOutputSessionChannel)(object)innerChannel);
|
||
|
}
|
||
|
else if (typeof(TChannel) == typeof(IOutputChannel))
|
||
|
{
|
||
|
return (TChannel)(object)new TransactionOutputChannel(this, (IOutputChannel)(object)innerChannel);
|
||
|
}
|
||
|
else if (typeof(TChannel) == typeof(IRequestChannel))
|
||
|
{
|
||
|
return (TChannel)(object)new TransactionRequestChannel(this, (IRequestChannel)(object)innerChannel);
|
||
|
}
|
||
|
else if (typeof(TChannel) == typeof(IDuplexChannel))
|
||
|
{
|
||
|
return (TChannel)(object)new TransactionDuplexChannel(this, (IDuplexChannel)(object)innerChannel);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateChannelTypeNotSupportedException(typeof(TChannel)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================
|
||
|
// Transaction Output Channel classes
|
||
|
//===========================================================
|
||
|
|
||
|
sealed class TransactionOutputChannel : TransactionOutputChannelGeneric<IOutputChannel>
|
||
|
{
|
||
|
public TransactionOutputChannel(ChannelManagerBase channelManager, IOutputChannel innerChannel)
|
||
|
: base(channelManager, innerChannel)
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sealed class TransactionRequestChannel : TransactionRequestChannelGeneric<IRequestChannel>
|
||
|
{
|
||
|
public TransactionRequestChannel(ChannelManagerBase channelManager, IRequestChannel innerChannel)
|
||
|
: base(channelManager, innerChannel)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
sealed class TransactionDuplexChannel : TransactionOutputDuplexChannelGeneric<IDuplexChannel>
|
||
|
{
|
||
|
public TransactionDuplexChannel(ChannelManagerBase channelManager, IDuplexChannel innerChannel)
|
||
|
: base(channelManager, innerChannel)
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sealed class TransactionOutputSessionChannel : TransactionOutputChannelGeneric<IOutputSessionChannel>, IOutputSessionChannel
|
||
|
{
|
||
|
public TransactionOutputSessionChannel(ChannelManagerBase channelManager, IOutputSessionChannel innerChannel)
|
||
|
: base(channelManager, innerChannel)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public IOutputSession Session { get { return InnerChannel.Session; } }
|
||
|
|
||
|
}
|
||
|
|
||
|
sealed class TransactionRequestSessionChannel : TransactionRequestChannelGeneric<IRequestSessionChannel>, IRequestSessionChannel
|
||
|
{
|
||
|
public TransactionRequestSessionChannel(ChannelManagerBase channelManager, IRequestSessionChannel innerChannel)
|
||
|
: base(channelManager, innerChannel)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public IOutputSession Session { get { return InnerChannel.Session; } }
|
||
|
|
||
|
}
|
||
|
|
||
|
sealed class TransactionDuplexSessionChannel : TransactionOutputDuplexChannelGeneric<IDuplexSessionChannel>, IDuplexSessionChannel
|
||
|
{
|
||
|
public TransactionDuplexSessionChannel(ChannelManagerBase channelManager, IDuplexSessionChannel innerChannel)
|
||
|
: base(channelManager, innerChannel)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public IDuplexSession Session { get { return InnerChannel.Session; } }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static class SecurityStandardsHelper
|
||
|
{
|
||
|
static SecurityStandardsManager SecurityStandardsManager2007 =
|
||
|
CreateStandardsManager(MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12);
|
||
|
|
||
|
static SecurityStandardsManager CreateStandardsManager(MessageSecurityVersion securityVersion)
|
||
|
{
|
||
|
return new SecurityStandardsManager(
|
||
|
securityVersion,
|
||
|
new WSSecurityTokenSerializer(securityVersion.SecurityVersion, securityVersion.TrustVersion, securityVersion.SecureConversationVersion, false, null, null, null));
|
||
|
}
|
||
|
|
||
|
public static SecurityStandardsManager CreateStandardsManager(TransactionProtocol transactionProtocol)
|
||
|
{
|
||
|
if (transactionProtocol == TransactionProtocol.WSAtomicTransactionOctober2004 ||
|
||
|
transactionProtocol == TransactionProtocol.OleTransactions)
|
||
|
{
|
||
|
return SecurityStandardsManager.DefaultInstance;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return SecurityStandardsHelper.SecurityStandardsManager2007;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//==============================================================
|
||
|
// Transaction channel base generic classes
|
||
|
//==============================================================
|
||
|
|
||
|
class TransactionOutputChannelGeneric<TChannel> : TransactionChannel<TChannel>, IOutputChannel
|
||
|
where TChannel : class, IOutputChannel
|
||
|
{
|
||
|
public TransactionOutputChannelGeneric(ChannelManagerBase channelManager, TChannel innerChannel)
|
||
|
: base(channelManager, innerChannel)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public EndpointAddress RemoteAddress
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return InnerChannel.RemoteAddress;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Uri Via
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return InnerChannel.Via;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state)
|
||
|
{
|
||
|
return this.BeginSend(message, this.DefaultSendTimeout, callback, state);
|
||
|
}
|
||
|
|
||
|
public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback asyncCallback, object state)
|
||
|
{
|
||
|
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
|
||
|
WriteTransactionDataToMessage(message, MessageDirection.Input);
|
||
|
return InnerChannel.BeginSend(message, timeoutHelper.RemainingTime(), asyncCallback, state);
|
||
|
|
||
|
}
|
||
|
|
||
|
public void EndSend(IAsyncResult result)
|
||
|
{
|
||
|
InnerChannel.EndSend(result);
|
||
|
}
|
||
|
|
||
|
public void Send(Message message)
|
||
|
{
|
||
|
this.Send(message, this.DefaultSendTimeout);
|
||
|
}
|
||
|
|
||
|
public void Send(Message message, TimeSpan timeout)
|
||
|
{
|
||
|
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
|
||
|
WriteTransactionDataToMessage(message, MessageDirection.Input);
|
||
|
InnerChannel.Send(message, timeoutHelper.RemainingTime());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
class TransactionRequestChannelGeneric<TChannel> : TransactionChannel<TChannel>, IRequestChannel
|
||
|
where TChannel : class, IRequestChannel
|
||
|
{
|
||
|
public TransactionRequestChannelGeneric(ChannelManagerBase channelManager, TChannel innerChannel)
|
||
|
: base(channelManager, innerChannel)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public EndpointAddress RemoteAddress
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return InnerChannel.RemoteAddress;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Uri Via
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return InnerChannel.Via;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state)
|
||
|
{
|
||
|
return this.BeginRequest(message, this.DefaultSendTimeout, callback, state);
|
||
|
}
|
||
|
|
||
|
public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback asyncCallback, object state)
|
||
|
{
|
||
|
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
|
||
|
WriteTransactionDataToMessage(message, MessageDirection.Input);
|
||
|
return InnerChannel.BeginRequest(message, timeoutHelper.RemainingTime(), asyncCallback, state);
|
||
|
}
|
||
|
|
||
|
public Message EndRequest(IAsyncResult result)
|
||
|
{
|
||
|
Message reply = InnerChannel.EndRequest(result);
|
||
|
if (reply != null)
|
||
|
this.ReadIssuedTokens(reply, MessageDirection.Output);
|
||
|
return reply;
|
||
|
}
|
||
|
|
||
|
public Message Request(Message message)
|
||
|
{
|
||
|
return this.Request(message, this.DefaultSendTimeout);
|
||
|
}
|
||
|
|
||
|
public Message Request(Message message, TimeSpan timeout)
|
||
|
{
|
||
|
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
|
||
|
WriteTransactionDataToMessage(message, MessageDirection.Input);
|
||
|
Message reply = InnerChannel.Request(message, timeoutHelper.RemainingTime());
|
||
|
if (reply != null)
|
||
|
this.ReadIssuedTokens(reply, MessageDirection.Output);
|
||
|
return reply;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class TransactionOutputDuplexChannelGeneric<TChannel> : TransactionDuplexChannelGeneric<TChannel>
|
||
|
where TChannel : class, IDuplexChannel
|
||
|
{
|
||
|
public TransactionOutputDuplexChannelGeneric(ChannelManagerBase channelManager, TChannel innerChannel)
|
||
|
: base(channelManager, innerChannel, MessageDirection.Output)
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
}
|