< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.RequestContextMessageProperty
Assembly: CoreWCF.RabbitMQ
File(s): /home/runner/work/CoreWCF/CoreWCF/src/Common/src/CoreWCF/Channels/RequestContextBase.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 23
Coverable lines: 23
Total lines: 311
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 4
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
System.IDisposable.Dispose()0%440%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/Common/src/CoreWCF/Channels/RequestContextBase.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Diagnostics;
 6using System.Threading;
 7using System.Threading.Tasks;
 8using CoreWCF.Runtime;
 9
 10namespace CoreWCF.Channels
 11{
 12    internal abstract class RequestContextBase : RequestContext
 13    {
 14        private TimeSpan _defaultSendTimeout;
 15        private TimeSpan _defaultCloseTimeout;
 16        private CommunicationState _state = CommunicationState.Opened;
 17        private Message _requestMessage;
 18        private Exception _requestMessageException;
 19        private bool _replySent;
 20
 21        protected RequestContextBase(Message requestMessage, TimeSpan defaultCloseTimeout, TimeSpan defaultSendTimeout)
 22        {
 23            _defaultSendTimeout = defaultSendTimeout;
 24            _defaultCloseTimeout = defaultCloseTimeout;
 25            _requestMessage = requestMessage;
 26        }
 27
 28        public void ReInitialize(Message requestMessage)
 29        {
 30            _state = CommunicationState.Opened;
 31            _requestMessageException = null;
 32            _replySent = false;
 33            ReplyInitiated = false;
 34            Aborted = false;
 35            _requestMessage = requestMessage;
 36        }
 37
 38        public override Message RequestMessage
 39        {
 40            get
 41            {
 42                if (_requestMessageException != null)
 43                {
 44                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(_requestMessageException);
 45                }
 46
 47                return _requestMessage;
 48            }
 49        }
 50
 51        protected void SetRequestMessage(Message requestMessage)
 52        {
 53            Fx.Assert(_requestMessageException == null, "Cannot have both a requestMessage and a requestException.");
 54            _requestMessage = requestMessage;
 55        }
 56
 57        protected void SetRequestMessage(Exception requestMessageException)
 58        {
 59            Fx.Assert(_requestMessage == null, "Cannot have both a requestMessage and a requestException.");
 60            _requestMessageException = requestMessageException;
 61        }
 62
 63        protected bool ReplyInitiated { get; private set; }
 64
 65        protected object ThisLock { get; } = new object();
 66
 67        public bool Aborted { get; private set; }
 68
 69        public TimeSpan DefaultCloseTimeout
 70        {
 71            get { return _defaultCloseTimeout; }
 72        }
 73
 74        public TimeSpan DefaultSendTimeout
 75        {
 76            get { return _defaultSendTimeout; }
 77        }
 78
 79        public override void Abort()
 80        {
 81            lock (ThisLock)
 82            {
 83                if (_state == CommunicationState.Closed)
 84                {
 85                    return;
 86                }
 87
 88                _state = CommunicationState.Closing;
 89
 90                Aborted = true;
 91            }
 92
 93            //if (DiagnosticUtility.ShouldTraceWarning)
 94            //{
 95            //    TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.RequestContextAbort,
 96            //        SRCommon.Format(SRCommon.TraceCodeRequestContextAbort), this);
 97            //}
 98
 99            try
 100            {
 101                OnAbort();
 102            }
 103            finally
 104            {
 105                _state = CommunicationState.Closed;
 106            }
 107        }
 108
 109        public override Task CloseAsync()
 110        {
 111            var helper = new TimeoutHelper(_defaultCloseTimeout);
 112            return CloseAsync(helper.GetCancellationToken());
 113        }
 114
 115        public override async Task CloseAsync(CancellationToken token)
 116        {
 117            bool sendAck = false;
 118            lock (ThisLock)
 119            {
 120                if (_state != CommunicationState.Opened)
 121                {
 122                    return;
 123                }
 124
 125                if (TryInitiateReply())
 126                {
 127                    sendAck = true;
 128                }
 129
 130                _state = CommunicationState.Closing;
 131            }
 132
 133            bool throwing = true;
 134
 135            try
 136            {
 137                if (sendAck)
 138                {
 139                    await OnReplyAsync(null, token);
 140                }
 141
 142                await OnCloseAsync(token);
 143                _state = CommunicationState.Closed;
 144                throwing = false;
 145            }
 146            finally
 147            {
 148                if (throwing)
 149                {
 150                    Abort();
 151                }
 152            }
 153        }
 154
 155        protected override void Dispose(bool disposing)
 156        {
 157            base.Dispose(disposing);
 158
 159            if (!disposing)
 160            {
 161                return;
 162            }
 163
 164            if (_replySent)
 165            {
 166                CloseAsync().GetAwaiter().GetResult();
 167            }
 168            else
 169            {
 170                Abort();
 171            }
 172        }
 173
 174        protected abstract void OnAbort();
 175        protected abstract Task OnCloseAsync(CancellationToken token);
 176        protected abstract Task OnReplyAsync(Message message, CancellationToken token);
 177
 178        protected void ThrowIfInvalidReply()
 179        {
 180            if (_state == CommunicationState.Closed || _state == CommunicationState.Closing)
 181            {
 182                if (Aborted)
 183                {
 184                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationObjectAbortedException(SR
 185                }
 186                else
 187                {
 188                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(GetType().Full
 189                }
 190            }
 191
 192            if (ReplyInitiated)
 193            {
 194                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRCommon.ReplyAl
 195            }
 196        }
 197
 198        /// <summary>
 199        /// Attempts to initiate the reply. If a reply is not initiated already (and the object is opened),
 200        /// then it initiates the reply and returns true. Otherwise, it returns false.
 201        /// </summary>
 202        protected bool TryInitiateReply()
 203        {
 204            lock (ThisLock)
 205            {
 206                if ((_state != CommunicationState.Opened) || ReplyInitiated)
 207                {
 208                    return false;
 209                }
 210                else
 211                {
 212                    ReplyInitiated = true;
 213                    return true;
 214                }
 215            }
 216        }
 217
 218        public override Task ReplyAsync(Message message)
 219        {
 220            var helper = new TimeoutHelper(_defaultSendTimeout);
 221            return ReplyAsync(message, helper.GetCancellationToken());
 222        }
 223
 224        public override async Task ReplyAsync(Message message, CancellationToken token)
 225        {
 226            // "null" is a valid reply (signals a 202-style "ack"), so we don't have a null-check here
 227            lock (ThisLock)
 228            {
 229                ThrowIfInvalidReply();
 230                ReplyInitiated = true;
 231            }
 232
 233            await OnReplyAsync(message, token);
 234            _replySent = true;
 235        }
 236
 237        // This method is designed for WebSocket only, and will only be used once the WebSocket response was sent.
 238        // For WebSocket, we never call HttpRequestContext.Reply to send the response back.
 239        // Instead we call AcceptWebSocket directly. So we need to set the replyInitiated and
 240        // replySent boolean to be true once the response was sent successfully. Otherwise when we
 241        // are disposing the HttpRequestContext, we will see a bunch of warnings in trace log.
 242        protected void SetReplySent()
 243        {
 244            lock (ThisLock)
 245            {
 246                ThrowIfInvalidReply();
 247                ReplyInitiated = true;
 248            }
 249
 250            _replySent = true;
 251        }
 252    }
 253
 254    internal class RequestContextMessageProperty : IDisposable
 255    {
 256        private RequestContext _context;
 0257        private readonly object _thisLock = new object();
 258
 0259        public RequestContextMessageProperty(RequestContext context)
 260        {
 0261            _context = context;
 0262        }
 263
 264        public static string Name
 265        {
 0266            get { return "requestContext"; }
 267        }
 268
 269        void IDisposable.Dispose()
 270        {
 0271            bool success = false;
 272            RequestContext thisContext;
 273
 0274            lock (_thisLock)
 275            {
 0276                if (_context == null)
 277                {
 0278                    return;
 279                }
 280
 0281                thisContext = _context;
 0282                _context = null;
 0283            }
 284
 285            try
 286            {
 0287                thisContext.CloseAsync().GetAwaiter().GetResult();
 0288                success = true;
 0289            }
 290            catch (CommunicationException e)
 291            {
 0292                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0293            }
 294            catch (TimeoutException e)
 295            {
 296                //if (TD.CloseTimeoutIsEnabled())
 297                //{
 298                //    TD.CloseTimeout(e.Message);
 299                //}
 0300                DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 0301            }
 302            finally
 303            {
 0304                if (!success)
 305                {
 0306                    thisContext.Abort();
 307                }
 0308            }
 0309        }
 310    }
 311}