< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Dispatcher.MessageRpc
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/MessageRpc.cs
Line coverage
69%
Covered lines: 138
Uncovered lines: 61
Coverable lines: 199
Total lines: 580
Line coverage: 69.3%
Branch coverage
69%
Covered branches: 57
Total branches: 82
Branch coverage: 69.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%44100%
AbortAsync()100%110%
AbortRequestContextAsync()50%4458.33%
AbortRequestContextAsync()83.33%6683.33%
TraceCallDurationInDispatcherIfNecessary(...)100%11100%
CloseRequestContextAsync()100%66100%
DisposeRequestContextAsync()75%4492.3%
AbortChannel()50%6622.22%
CloseChannelAsync()50%6620%
AbortInstanceContext()66.66%6644.44%
EnsureReceive()100%11100%
ProcessError(...)50%8871.42%
DisposeParameters(...)100%22100%
DisposeParametersCore(...)75%8864.28%
DisposeParameterList(...)75%8854.54%
ProcessAsync()64.28%141472%
UnPause()100%110%
UnlockInvokeContinueGate(...)100%110%
PrepareInvokeContinueGate()100%110%
IncrementBusyCount()100%11100%
DecrementBusyCount()100%11100%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/MessageRpc.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.Collections.ObjectModel;
 6using System.Diagnostics;
 7using System.Threading;
 8using System.Threading.Tasks;
 9using System.Xml;
 10using CoreWCF.Channels;
 11using CoreWCF.Runtime;
 12
 13namespace CoreWCF.Dispatcher
 14{
 15    internal delegate Task<MessageRpc> MessageRpcProcessor(MessageRpc rpc);
 16
 17    internal delegate Task MessageRpcErrorHandler(MessageRpc rpc);
 18
 19    // TODO: Pool MessageRpc objects. These are zero cost on .NET Framework as it's a struct but passing things by ref i
 20    // when using async/await. This causes an allocation per request so pool them to remove that allocation.
 21    internal class MessageRpc
 22    {
 23        internal readonly ServiceChannel Channel;
 24        internal readonly ChannelHandler ChannelHandler;
 25        internal readonly object[] Correlation;
 26        internal readonly ServiceHostBase Host;
 27        internal readonly OperationContext OperationContext;
 28        //internal ServiceModelActivity Activity;
 29        internal Guid ResponseActivityId;
 30        internal IAsyncResult AsyncResult;
 31        internal Task TaskResult;
 32        internal bool CanSendReply;
 33        internal bool SuccessfullySendReply;
 34        internal object[] InputParameters;
 35        internal object[] OutputParameters;
 36        internal object ReturnParameter;
 37        internal bool ParametersDisposed;
 38        internal bool DidDeserializeRequestBody;
 39        //internal TransactionMessageProperty TransactionMessageProperty;
 40        //internal TransactedBatchContext TransactedBatchContext;
 41        internal Exception Error;
 42        internal MessageRpcErrorHandler ErrorProcessor;
 43        internal ErrorHandlerFaultInfo FaultInfo;
 44        internal bool HasSecurityContext;
 45        internal object Instance;
 46        internal bool MessageRpcOwnsInstanceContextThrottle;
 47        internal MessageRpcProcessor AsyncProcessor;
 48        internal Collection<MessageHeaderInfo> NotUnderstoodHeaders;
 49        internal DispatchOperationRuntime Operation;
 50        internal Message Request;
 51        internal RequestContext RequestContext;
 52        internal bool RequestContextThrewOnReply;
 53        internal UniqueId RequestID;
 54        internal Message Reply;
 55        internal TimeoutHelper ReplyTimeoutHelper;
 56        internal RequestReplyCorrelator.ReplyToInfo ReplyToInfo;
 57        internal MessageVersion RequestVersion;
 58        internal ServiceSecurityContext SecurityContext;
 59        internal InstanceContext InstanceContext;
 60        internal bool SuccessfullyBoundInstance;
 61        internal bool SuccessfullyIncrementedActivity;
 62        internal bool SuccessfullyLockedInstance;
 63        internal /* ReceiveContextRPCFacet */ ReceiveContext ReceiveContext;
 64        //internal TransactionRpcFacet transaction;
 65        //internal IAspNetMessageProperty HostingProperty;
 66        //internal MessageRpcInvokeNotification InvokeNotification;
 67        //internal EventTraceActivity EventTraceActivity;
 68        internal bool _processCallReturned;
 69        private bool _isInstanceContextSingleton;
 70        private SignalGate<IAsyncResult> _invokeContinueGate;
 71
 253872        internal MessageRpc(RequestContext requestContext, Message request, DispatchOperationRuntime operation,
 253873            ServiceChannel channel, ServiceHostBase host, ChannelHandler channelHandler, bool cleanThread,
 253874            OperationContext operationContext, InstanceContext instanceContext/*, EventTraceActivity eventTraceActivity*
 75        {
 76            Fx.Assert((operationContext != null), "correwcf.Dispatcher.MessageRpc.MessageRpc(), operationContext == null
 77            // TODO: ChannelHandler supplied an ErrorHandler, need to supply this some other way.
 78            //Fx.Assert(channelHandler != null, "System.ServiceModel.Dispatcher.MessageRpc.MessageRpc(), channelHandler 
 79
 80            //this.Activity = null;
 81            //this.EventTraceActivity = eventTraceActivity;
 253882            AsyncResult = null;
 253883            TaskResult = null;
 253884            CanSendReply = true;
 253885            Channel = channel;
 253886            ChannelHandler = channelHandler;
 253887            Correlation = EmptyArray.Allocate(operation.Parent.CorrelationCount);
 253888            DidDeserializeRequestBody = false;
 253889            Error = null;
 253890            ErrorProcessor = null;
 253891            FaultInfo = new ErrorHandlerFaultInfo(request.Version.Addressing.DefaultFaultAction);
 253892            HasSecurityContext = false;
 253893            Host = host;
 253894            Instance = null;
 253895            AsyncProcessor = null;
 253896            NotUnderstoodHeaders = null;
 253897            Operation = operation;
 253898            OperationContext = operationContext;
 253899            IsPaused = false;
 2538100            ParametersDisposed = false;
 2538101            ReceiveContext = null;
 2538102            Request = request;
 2538103            RequestContext = requestContext;
 2538104            RequestContextThrewOnReply = false;
 2538105            SuccessfullySendReply = false;
 2538106            RequestVersion = request.Version;
 2538107            Reply = null;
 2538108            ReplyTimeoutHelper = new TimeoutHelper();
 2538109            SecurityContext = null;
 2538110            InstanceContext = instanceContext;
 2538111            SuccessfullyBoundInstance = false;
 2538112            SuccessfullyIncrementedActivity = false;
 2538113            SuccessfullyLockedInstance = false;
 2538114            SwitchedThreads = !cleanThread;
 115            //this.transaction = null;
 2538116            InputParameters = null;
 2538117            OutputParameters = null;
 2538118            ReturnParameter = null;
 2538119            _isInstanceContextSingleton = InstanceContextProviderBase.IsProviderSingleton(Channel.DispatchRuntime.Instan
 2538120            _invokeContinueGate = null;
 121
 2538122            if (!operation.IsOneWay && !operation.Parent.ManualAddressing)
 123            {
 683124                RequestID = request.Headers.MessageId;
 683125                ReplyToInfo = new RequestReplyCorrelator.ReplyToInfo(request);
 126            }
 127            else
 128            {
 1855129                RequestID = null;
 1855130                ReplyToInfo = new RequestReplyCorrelator.ReplyToInfo();
 131            }
 132
 133            //if (DiagnosticUtility.ShouldUseActivity)
 134            //{
 135            //    this.Activity = TraceUtility.ExtractActivity(this.Request);
 136            //}
 137
 138            //if (DiagnosticUtility.ShouldUseActivity || TraceUtility.ShouldPropagateActivity)
 139            //{
 140            //    this.ResponseActivityId = ActivityIdHeader.ExtractActivityId(this.Request);
 141            //}
 142            //else
 143            //{
 2538144            ResponseActivityId = Guid.Empty;
 145            //}
 146
 147            //if (this.EventTraceActivity == null && FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
 148            //{
 149            //    if (this.Request != null)
 150            //    {
 151            //        this.EventTraceActivity = EventTraceActivityHelper.TryExtractActivity(this.Request, true);
 152            //    }
 153            //}
 2538154        }
 155
 2538156        internal bool IsPaused { get; private set; }
 157
 0158        internal bool SwitchedThreads { get; }
 159
 160        internal bool IsInstanceContextSingleton
 161        {
 162            set
 163            {
 0164                _isInstanceContextSingleton = value;
 0165            }
 166        }
 167
 168        //internal TransactionRpcFacet Transaction
 169        //{
 170        //    get
 171        //    {
 172        //        if (this.transaction == null)
 173        //        {
 174        //            this.transaction = new TransactionRpcFacet(ref this);
 175        //        }
 176        //        return this.transaction;
 177        //    }
 178        //}
 179
 180        internal async ValueTask AbortAsync()
 181        {
 0182            await AbortRequestContextAsync();
 0183            AbortChannel();
 0184            AbortInstanceContext();
 0185        }
 186
 187        private async ValueTask AbortRequestContextAsync(RequestContext requestContext)
 188        {
 189            try
 190            {
 54191                requestContext.Abort();
 192
 54193                /* ReceiveContextRPCFacet */ ReceiveContext receiveContext = ReceiveContext;
 194
 54195                if (receiveContext != null)
 196                {
 53197                    ReceiveContext = null;
 198
 53199                    await receiveContext.AbandonAsync(CancellationToken.None);
 200                }
 54201            }
 0202            catch (Exception e)
 203            {
 0204                if (Fx.IsFatal(e))
 205                {
 0206                    throw;
 207                }
 208
 0209                ChannelHandler.HandleError(e);
 0210            }
 54211        }
 212
 213        internal async ValueTask AbortRequestContextAsync()
 214        {
 53215            if (OperationContext.RequestContext != null)
 216            {
 0217                await AbortRequestContextAsync(OperationContext.RequestContext);
 218            }
 53219            if ((RequestContext != null) && (RequestContext != OperationContext.RequestContext))
 220            {
 53221                await AbortRequestContextAsync(RequestContext);
 222            }
 223
 53224            TraceCallDurationInDispatcherIfNecessary(false);
 53225        }
 226
 227        private void TraceCallDurationInDispatcherIfNecessary(bool requestContextWasClosedSuccessfully)
 228        {
 229            // only need to trace once (either for the failure or success case)
 230            //if (TD.DispatchFailedIsEnabled())
 231            //{
 232            //    if (requestContextWasClosedSuccessfully)
 233            //    {
 234            //        TD.DispatchSuccessful(this.EventTraceActivity, this.Operation.Name);
 235            //    }
 236            //    else
 237            //    {
 238            //        TD.DispatchFailed(this.EventTraceActivity, this.Operation.Name);
 239            //    }
 240            //}
 2538241        }
 242
 243        internal async Task CloseRequestContextAsync()
 244        {
 2485245            if (OperationContext.RequestContext != null)
 246            {
 728247                await DisposeRequestContextAsync(OperationContext.RequestContext);
 248            }
 2485249            if ((RequestContext != null) && (RequestContext != OperationContext.RequestContext))
 250            {
 1757251                await DisposeRequestContextAsync(RequestContext);
 252            }
 2485253            TraceCallDurationInDispatcherIfNecessary(true);
 2485254        }
 255
 256        private async ValueTask DisposeRequestContextAsync(RequestContext context)
 257        {
 258            try
 259            {
 2485260                await context.CloseAsync();
 261
 2485262                /* ReceiveContextRPCFacet */ ReceiveContext receiveContext = ReceiveContext;
 2485263                if (receiveContext != null)
 264                {
 1650265                    ReceiveContext = null;
 1650266                    await receiveContext.CompleteAsync(CancellationToken.None);
 267                }
 2484268            }
 1269            catch (Exception e)
 270            {
 1271                if (Fx.IsFatal(e))
 272                {
 0273                    throw;
 274                }
 275
 1276                await AbortRequestContextAsync(context);
 1277                ChannelHandler.HandleError(e);
 1278            }
 2485279        }
 280
 281        internal void AbortChannel()
 282        {
 53283            if ((Channel != null) && Channel.HasSession)
 284            {
 285                try
 286                {
 0287                    Channel.Abort();
 0288                }
 0289                catch (Exception e)
 290                {
 0291                    if (Fx.IsFatal(e))
 292                    {
 0293                        throw;
 294                    }
 295
 0296                    ChannelHandler.HandleError(e);
 0297                }
 298            }
 53299        }
 300
 301        internal async Task CloseChannelAsync()
 302        {
 5303            if ((Channel != null) && Channel.HasSession)
 304            {
 305                try
 306                {
 0307                    var helper = new TimeoutHelper(ChannelHandler.CloseAfterFaultTimeout);
 0308                    await Channel.CloseAsync(helper.GetCancellationToken());
 0309                }
 0310                catch (Exception e)
 311                {
 0312                    if (Fx.IsFatal(e))
 313                    {
 0314                        throw;
 315                    }
 316
 0317                    ChannelHandler.HandleError(e);
 0318                }
 319            }
 5320        }
 321
 322        internal void AbortInstanceContext()
 323        {
 58324            if (InstanceContext != null && !_isInstanceContextSingleton)
 325            {
 326                try
 327                {
 58328                    InstanceContext.Abort();
 58329                }
 0330                catch (Exception e)
 331                {
 0332                    if (Fx.IsFatal(e))
 333                    {
 0334                        throw;
 335                    }
 336
 0337                    ChannelHandler.HandleError(e);
 0338                }
 339            }
 58340        }
 341
 342        internal void EnsureReceive()
 343        {
 344            //using (ServiceModelActivity.BoundOperation(this.Activity))
 345            //{
 2536346            ChannelHandler.EnsureReceive();
 347            //}
 2536348        }
 349
 350        private bool ProcessError(Exception e)
 351        {
 163352            MessageRpcErrorHandler handler = ErrorProcessor;
 353            try
 354            {
 163355                Type exceptionType = e.GetType();
 356
 163357                if (exceptionType.IsAssignableFrom(typeof(FaultException)))
 358                {
 93359                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 360                }
 361                else
 362                {
 70363                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
 364                }
 365
 366                //if (TraceUtility.MessageFlowTracingOnly)
 367                //{
 368                //    TraceUtility.SetActivityId(this.Request.Properties);
 369                //    if (Guid.Empty == DiagnosticTraceBase.ActivityId)
 370                //    {
 371                //        Guid receivedActivityId = TraceUtility.ExtractActivityId(this.Request);
 372                //        if (Guid.Empty != receivedActivityId)
 373                //        {
 374                //            DiagnosticTraceBase.ActivityId = receivedActivityId;
 375                //        }
 376                //    }
 377                //}
 378
 379
 163380                Error = e;
 381
 163382                if (ErrorProcessor != null)
 383                {
 163384                    ErrorProcessor(this);
 385                }
 386
 163387                return (Error == null);
 388            }
 0389            catch (Exception e2)
 390            {
 0391                if (Fx.IsFatal(e2))
 392                {
 0393                    throw;
 394                }
 395
 0396                return ((handler != ErrorProcessor) && ProcessError(e2));
 397            }
 163398        }
 399
 400        internal void DisposeParameters(bool excludeInput)
 401        {
 2538402            if (Operation.DisposeParameters)
 403            {
 365404                DisposeParametersCore(excludeInput);
 405            }
 2538406        }
 407
 408        internal void DisposeParametersCore(bool excludeInput)
 409        {
 365410            if (!ParametersDisposed)
 411            {
 365412                if (!excludeInput)
 413                {
 365414                    DisposeParameterList(InputParameters);
 415                }
 416
 365417                DisposeParameterList(OutputParameters);
 418
 365419                if (ReturnParameter is IDisposable disposableParameter)
 420                {
 421                    try
 422                    {
 26423                        disposableParameter.Dispose();
 26424                    }
 0425                    catch (Exception e)
 426                    {
 0427                        if (Fx.IsFatal(e))
 428                        {
 0429                            throw;
 430                        }
 431
 0432                        ChannelHandler.HandleError(e);
 0433                    }
 434                }
 435
 365436                ParametersDisposed = true;
 437            }
 365438        }
 439
 440        private void DisposeParameterList(object[] parameters)
 441        {
 730442            if (parameters != null)
 443            {
 2130444                foreach (object obj in parameters)
 445                {
 377446                    if (obj is IDisposable disposableParameter)
 447                    {
 448                        try
 449                        {
 43450                            disposableParameter.Dispose();
 43451                        }
 0452                        catch (Exception e)
 453                        {
 0454                            if (Fx.IsFatal(e))
 455                            {
 0456                                throw;
 457                            }
 458
 0459                            ChannelHandler.HandleError(e);
 0460                        }
 461                    }
 462                }
 463            }
 730464        }
 465
 466        internal async Task<MessageRpc> ProcessAsync(bool isOperationContextSet)
 467        {
 468            MessageRpc result = this;
 469            //using (ServiceModelActivity.BoundOperation(this.Activity))
 470            //{
 471            // bool completed = true;
 472
 473            OperationContext originalContext;
 2538474            if (!isOperationContextSet)
 475            {
 2538476                originalContext = OperationContext.Current;
 477            }
 478            else
 479            {
 0480                originalContext = null;
 481            }
 2538482            IncrementBusyCount();
 483
 484            try
 485            {
 2538486                if (!isOperationContextSet)
 487                {
 2538488                    OperationContext.Current = OperationContext;
 489                }
 490
 2538491                await AsyncProcessor(this);
 492
 2375493                OperationContext.SetClientReply(null, false);
 2375494            }
 163495            catch (Exception e)
 496            {
 163497                if (Fx.IsFatal(e))
 498                {
 0499                    throw;
 500                }
 163501                if (!ProcessError(e) && FaultInfo.Fault == null)
 502                {
 0503                    await AbortAsync();
 504                }
 505            }
 506            finally
 507            {
 508                try
 509                {
 2538510                    DecrementBusyCount();
 511
 2538512                    if (!isOperationContextSet)
 513                    {
 2538514                        OperationContext.Current = originalContext;
 515                    }
 516
 2538517                    OperationContext.ClearClientReplyNoThrow();
 2538518                }
 0519                catch (Exception e)
 520                {
 0521                    if (Fx.IsFatal(e))
 522                    {
 523#pragma warning disable CA2219 // Do not raise exceptions in finally clauses - Fx.IsFatal filters out non-process ending
 0524                        throw;
 525#pragma warning restore CA2219 // Do not raise exceptions in finally clauses
 526                    }
 0527                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(e.Message, e);
 528                }
 529            }
 530
 2538531            return this;
 532            //}
 2538533        }
 534
 535        // UnPause is called on the original MessageRpc to continue work on the current thread, and the copy is ignored.
 536        // Since the copy is ignored, Decrement the BusyCount
 537        internal void UnPause()
 538        {
 0539            IsPaused = false;
 0540            DecrementBusyCount();
 0541        }
 542
 543        internal bool UnlockInvokeContinueGate(out IAsyncResult result)
 544        {
 0545            return _invokeContinueGate.Unlock(out result);
 546        }
 547
 548        internal void PrepareInvokeContinueGate()
 549        {
 0550            _invokeContinueGate = new SignalGate<IAsyncResult>();
 0551        }
 552
 553        private void IncrementBusyCount()
 554        {
 555            // TODO: Do we want a way to keep track of bust count? I believe this originally drove PerformanceCounters s
 556            // Only increment the counter on the service side.
 557            //if (Host != null)
 558            //{
 559            //Host.IncrementBusyCount();
 560            //if (AspNetEnvironment.Current.TraceIncrementBusyCountIsEnabled())
 561            //{
 562            //    AspNetEnvironment.Current.TraceIncrementBusyCount(SR.Format(SR.ServiceBusyCountTrace, this.Operation.A
 563            //}
 564            //}
 2538565        }
 566
 567        private void DecrementBusyCount()
 568        {
 569            // See comment on IncrementBusyCount
 570            //if (Host != null)
 571            //{
 572            //    Host.DecrementBusyCount();
 573            //if (AspNetEnvironment.Current.TraceDecrementBusyCountIsEnabled())
 574            //{
 575            //    AspNetEnvironment.Current.TraceDecrementBusyCount(SR.Format(SR.ServiceBusyCountTrace, this.Operation.A
 576            //}
 577            //}
 2538578        }
 579    }
 580}