// // TransactionFlowBindingElement.cs // // Author: // Atsushi Enomoto // // 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 (BindingContext context) { return context.GetInnerProperty (); } public override bool CanBuildChannelFactory (BindingContext context) { return context.CanBuildInnerChannelFactory (); } [MonoTODO] public override bool CanBuildChannelListener (BindingContext context) { return context.CanBuildInnerChannelListener (); } public override IChannelFactory BuildChannelFactory (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 (context.Clone ())) throw new ArgumentException (String.Format ("The channel type '{0}' is not supported", typeof (TChannel))); return new TransactionChannelFactory (context.BuildInnerChannelFactory (), protocol); } public override IChannelListener BuildChannelListener (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 (context.Clone ())) throw new ArgumentException (String.Format ("The channel type '{0}' is not supported", typeof (TChannel))); return new TransactionChannelListener ( context.BuildInnerChannelListener (), protocol); } } internal class TransactionChannelFactory : ChannelFactoryBase { IChannelFactory inner_factory; TransactionScope txscope; TransactionProtocol protocol; public TransactionChannelFactory (IChannelFactory 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 : ChannelListenerBase where TChannel : class, IChannel { IChannelListener inner_listener; TransactionScope txscope; TransactionProtocol protocol; public TransactionChannelListener (IChannelListener innerListener, TransactionProtocol protocol) { this.inner_listener = innerListener; this.protocol = protocol; } public override T GetProperty () { return inner_listener.GetProperty () ?? base.GetProperty (); } 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); } } }