Click here to Skip to main content
15,897,704 members
Articles / Programming Languages / XML

NullTransport for WCF

Rate me:
Please Sign up or sign in to vote.
4.91/5 (48 votes)
1 Oct 200712 min read 189.9K   1.7K   121  
This article describes design, implementation and the usage of the custom in-process transport for Microsoft Windows Communication Foundation (WCF) model.
//*****************************************************************************
//    Description.....Null Transport 
//                                
//    Author..........Roman Kiss, rkiss@pathcom.com
//    Copyright © 2007 ATZ Consulting Inc.  (see included license.rtf file)     
//                        
//    Date Created:    07/07/07
//
//    Date        Modified By     Description
//-----------------------------------------------------------------------------
//    07/07/07    Roman Kiss     Initial Revision
//*****************************************************************************
//  
#region Namespaces
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Threading;
#endregion


namespace RKiss.NullChannelLib
{
    #region NullRequestContextCollection
    public class NullAsyncRequestContextCollection 
    {
        Dictionary<Guid, NullAsyncRequestContext> collection = new Dictionary<Guid,NullAsyncRequestContext>();

        public void Add(NullAsyncRequestContext context)
        {
            lock (collection)
            {
                collection.Add(context.Id, context);
            }
        }

        public void Close(NullAsyncRequestContext context)
        {
            lock (collection)
            {
                if (collection.ContainsKey(context.Id))
                {
                    collection.Remove(context.Id);
                }
                context.Close();
            }
        }
        public void AbortAll()
        {
            lock (collection)
            {
                Dictionary<Guid, NullAsyncRequestContext>.Enumerator en = collection.GetEnumerator();
                while (en.MoveNext())
                {
                    en.Current.Value.Abort();
                }
                collection.Clear();
            }
        }
    }
    #endregion

    #region NullAsyncRequestContext
    public class NullAsyncRequestContext : RequestContext, IAsyncResult
    {
        #region Private Members
        Guid _id;
        Message _request = null;
        Message _response = null;
        Exception _requestException = null;
        ManualResetEvent _waitForReply = null;
        bool _aborted = false;
        bool _replySent = false;
        object _thisLock = new object();
        CommunicationState _state = CommunicationState.Opened;
        TimeSpan _timeout;
        AsyncCallback _callback = null;
        object _apiState = null;
        bool _completedSynchronously = false;
        bool _endCalled = false;
        #endregion

        #region Constructors
        public NullAsyncRequestContext(Message message, TimeSpan timeout)
            : this(message, timeout, null, null)
        {         
            _waitForReply = new ManualResetEvent(false);
        }
        public NullAsyncRequestContext(Message message, TimeSpan timeout, AsyncCallback callback, object state)
            : base()
        {
            MessageBuffer buffer = message.CreateBufferedCopy(int.MaxValue);
            _request = buffer.CreateMessage();
            _id = Guid.NewGuid();
            _timeout = timeout;
            _callback = callback;
            _apiState = state;
        }
        #endregion

        #region Helpers
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (disposing)
            {
                if (_replySent)
                    this.Close();
                else
                    this.Abort();
            }
            if (_waitForReply != null)
            {
                _waitForReply.Close();
                _waitForReply = null;
            }
        }

        protected object ThisLock
        {
            get { return _thisLock; }
        }

        protected void ThrowIfInvalidReply()
        {
            if ((_state == CommunicationState.Closed) || (_state == CommunicationState.Closing))
            {
                if (_aborted)
                {
                    throw new CommunicationObjectAbortedException("RequestContext has been Aborted");
                }
                throw new ObjectDisposedException(base.GetType().FullName);
            }
            if (_replySent)
            {
                throw new InvalidOperationException("Reply has been already sent");
            }
        }
        #endregion

        #region Abort
        public void Abort(string reason)
        {
            this.SetRequestException = new Exception(reason);
            this.Abort();
        }
        public void Abort(Exception exception)
        {
            this.SetRequestException = exception;
            this.Abort();
        }
        public override void Abort()
        {
            lock (ThisLock)
            {
                if (_aborted)
                    return;

                _state = CommunicationState.Closed;
                _aborted = true;

                if (_waitForReply != null)
                {
                    _waitForReply.Set();
                }
            }
                      
        }
        #endregion

        #region Close
        public override void Close(TimeSpan timeout)
        {
            this.Close();
        }

        public override void Close()
        {
            lock (ThisLock)
            {
                if (_state != CommunicationState.Opened)
                    return;
                _state = CommunicationState.Closed;
            }
        }
        #endregion

        #region Reply
        public override IAsyncResult BeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state)
        {
            this.Reply(message, timeout);
            return new CompletedAsyncResult(callback, state);
        }

        public override IAsyncResult BeginReply(Message message, AsyncCallback callback, object state)
        {
            this.Reply(message);
            return new CompletedAsyncResult(callback, state);
        }

        public override void EndReply(IAsyncResult result)
        {
            CompletedAsyncResult.End(result);
        }

        public override void Reply(Message message, TimeSpan timeout)
        {
            lock (ThisLock)
            {
                ThrowIfInvalidReply();

                if (message != null)
                {
                    MessageBuffer buffer = message.CreateBufferedCopy(int.MaxValue);
                    _response = buffer.CreateMessage();
                }
                else
                {
                    _response = null;
                }
                _replySent = true;

                if (_waitForReply != null)
                {
                    _waitForReply.Set();
                }
            }

            if (_callback != null)
            {
                // in the case of the BeginRequest/EndRequest: call callback for reply is done
                _callback(this);
            }
        }

        public override void Reply(Message message)
        {
            this.Reply(message, _timeout);
        }

        public Message WaitForReply()
        {
            return WaitForReply(_timeout);
        }

        public Message WaitForReply(TimeSpan timeout)
        {
            bool retval = this.AsyncWaitHandle.WaitOne((int)timeout.TotalMilliseconds, false);
            lock (ThisLock)
            {
                this.Dispose(false);
        
                if (_aborted)
                {
                    if (_requestException != null)
                        throw _requestException;
                    else
                        throw new CommunicationObjectAbortedException("RequestContext aborted");
                }
                if (retval == false)
                {
                    this.Abort();
                    throw new CommunicationObjectAbortedException("RequestContext timeout");
                }
            }
            return _response;
        }    
        #endregion

        #region IAsyncResult Members
        public object AsyncState
        {
            get { return _apiState; }
        }

        public WaitHandle AsyncWaitHandle
        {
            get
            {
                if (_waitForReply != null)
                {
                    return _waitForReply;
                }

                lock (ThisLock)
                {
                    if (_waitForReply == null)
                    {
                        _waitForReply = new ManualResetEvent(_replySent);
                    }
                }
                return _waitForReply;
            }
        }

        public bool CompletedSynchronously
        {
            get { return _completedSynchronously; }
        }

        public bool IsCompleted
        {
            get { return _replySent; }
        }
        #endregion

        #region End
        public static Message End(IAsyncResult result)          
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            NullAsyncRequestContext asyncResult = result as NullAsyncRequestContext;

            if (asyncResult == null)
            {
                throw new ArgumentException("Invalid async result.", "result");
            }
            if (asyncResult._endCalled)
            {
                throw new InvalidOperationException("Async object already ended.");
            }

            asyncResult._endCalled = true;

            if (asyncResult._replySent == false)
            {
                // blocking method
                asyncResult.WaitForReply();
            }
            if (asyncResult._requestException != null)
            {
                throw asyncResult._requestException;
            }

            return asyncResult._response;
        }
        #endregion

        #region Get Methods
        public Guid Id
        {
            get { return _id; }
        }

        public Exception SetRequestException
        {
            set { _requestException = value; }
        }

        public override Message RequestMessage
        {
            get
            {
                if (_requestException != null)
                {
                    throw _requestException;
                }
                return _request;
            }
        }

        public Message ResponseMessage
        {
            get { return _response; }
        }
        #endregion
    }
    #endregion
}

       

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions