// // TransactionFlowBindingElement.cs // // Author: // Atsushi Enomoto <atsushi@ximian.com> // // Copyright (C) 2006 Novell, Inc. http://www.novell.com // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; using System.ServiceModel.Description; using System.ServiceModel.Security; using System.ServiceModel.Channels; using System.Transactions; namespace System.ServiceModel.Channels { public class TransactionFlowBindingElement : BindingElement { TransactionProtocol protocol; // Funny, but since it uses OLE TX, Mono will never support this constructor. [MonoTODO] public TransactionFlowBindingElement () : this (TransactionProtocol.Default) { } public TransactionFlowBindingElement (TransactionProtocol transactionProtocol) { this.protocol = transactionProtocol; } public TransactionProtocol TransactionProtocol { get { return protocol; } } public override BindingElement Clone () { return new TransactionFlowBindingElement (protocol); } [MonoTODO] public override T GetProperty<T> (BindingContext context) { return context.GetInnerProperty<T> (); } public override bool CanBuildChannelFactory<TChannel> (BindingContext context) { return context.CanBuildInnerChannelFactory<TChannel> (); } [MonoTODO] public override bool CanBuildChannelListener<TChannel> (BindingContext context) { return context.CanBuildInnerChannelListener<TChannel> (); } public override IChannelFactory<TChannel> BuildChannelFactory<TChannel> (BindingContext context) { if (protocol == null) throw new InvalidOperationException ("Set transaction protocol in prior to build a channel factory."); if (protocol == TransactionProtocol.Default) throw new NotSupportedException ("Mono does not support DTC."); if (!CanBuildChannelFactory<TChannel> (context.Clone ())) throw new ArgumentException (String.Format ("The channel type '{0}' is not supported", typeof (TChannel))); return new TransactionChannelFactory<TChannel> (context.BuildInnerChannelFactory<TChannel> (), protocol); } public override IChannelListener<TChannel> BuildChannelListener<TChannel> (BindingContext context) { if (protocol == null) throw new InvalidOperationException ("Set transaction protocol in prior to build a channel listener."); if (protocol == TransactionProtocol.Default) throw new NotSupportedException ("Mono does not support DTC."); if (!CanBuildChannelListener<TChannel> (context.Clone ())) throw new ArgumentException (String.Format ("The channel type '{0}' is not supported", typeof (TChannel))); return new TransactionChannelListener<TChannel> ( context.BuildInnerChannelListener<TChannel> (), protocol); } } internal class TransactionChannelFactory<TChannel> : ChannelFactoryBase<TChannel> { IChannelFactory<TChannel> inner_factory; TransactionScope txscope; TransactionProtocol protocol; public TransactionChannelFactory (IChannelFactory<TChannel> innerFactory, TransactionProtocol protocol) { this.inner_factory = innerFactory; this.protocol = protocol; } void ProcessOpen () { CommittableTransaction tx = new CommittableTransaction (); txscope = new TransactionScope (tx); } protected override void OnOpen (TimeSpan timeout) { ProcessOpen (); inner_factory.Open (timeout); } protected override IAsyncResult OnBeginOpen (TimeSpan timeout, AsyncCallback callback, object state) { ProcessOpen (); return inner_factory.BeginOpen (timeout, callback, state); } protected override void OnEndOpen (IAsyncResult result) { inner_factory.EndOpen (result); } protected override TChannel OnCreateChannel ( EndpointAddress remoteAddress, Uri via) { return inner_factory.CreateChannel (remoteAddress, via); } protected override void OnClose (TimeSpan timeout) { inner_factory.Close (timeout); txscope.Complete (); } } internal class TransactionChannelListener<TChannel> : ChannelListenerBase<TChannel> where TChannel : class, IChannel { IChannelListener<TChannel> inner_listener; TransactionScope txscope; TransactionProtocol protocol; public TransactionChannelListener (IChannelListener<TChannel> innerListener, TransactionProtocol protocol) { this.inner_listener = innerListener; this.protocol = protocol; } public override T GetProperty<T> () { return inner_listener.GetProperty<T> () ?? base.GetProperty<T> (); } public override Uri Uri { get { return inner_listener.Uri; } } protected override void OnAbort () { inner_listener.Abort (); } protected override void OnOpen (TimeSpan timeout) { CommittableTransaction tx = new CommittableTransaction (); txscope = new TransactionScope (tx); inner_listener.Open (timeout); } protected override IAsyncResult OnBeginOpen (TimeSpan timeout, AsyncCallback callback, object state) { return inner_listener.BeginOpen (timeout, callback, state); } protected override void OnEndOpen (IAsyncResult result) { inner_listener.EndOpen (result); } protected override void OnClose (TimeSpan timeout) { inner_listener.Close (timeout); txscope.Complete (); } protected override IAsyncResult OnBeginClose (TimeSpan timeout, AsyncCallback callback, object state) { return inner_listener.BeginClose (timeout, callback, state); } protected override void OnEndClose (IAsyncResult result) { inner_listener.EndClose (result); } protected override bool OnWaitForChannel (TimeSpan timeout) { return inner_listener.WaitForChannel (timeout); } protected override IAsyncResult OnBeginWaitForChannel (TimeSpan timeout, AsyncCallback callback, object state) { return inner_listener.BeginWaitForChannel (timeout, callback, state); } protected override bool OnEndWaitForChannel (IAsyncResult result) { return inner_listener.EndWaitForChannel (result); } protected override TChannel OnAcceptChannel (TimeSpan timeout) { return inner_listener.AcceptChannel (timeout); } protected override IAsyncResult OnBeginAcceptChannel (TimeSpan timeout, AsyncCallback callback, object asyncState) { return inner_listener.BeginAcceptChannel (timeout, callback, asyncState); } protected override TChannel OnEndAcceptChannel (IAsyncResult result) { return inner_listener.EndAcceptChannel (result); } } }