public void AcceptDistributedTraceHeaders <T>(T carrier, Func <T, string, IEnumerable <string> > getter, int transportType)
 {
     try
     {
         using (new IgnoreWork())
         {
             _apiSupportabilityMetricCounters.Record(ApiMethod.AcceptDistributedTraceHeaders);
             _transaction.AcceptDistributedTraceHeaders(carrier, getter, GetTransportTypeValue(transportType));
         }
     }
     catch (Exception ex)
     {
         try
         {
             Log.ErrorFormat("Error in AcceptDistributedTraceHeaders<T>(T, Func<T, string, IEnumerable<string>>, TransportType): {0}", ex);
         }
         catch (Exception)
         {
             //Swallow the error
         }
     }
 }
        public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall instrumentedMethodCall, IAgent agent, ITransaction transaction)
        {
            var transactionAlreadyExists = transaction.IsValid;

            var methodInfo = TryGetMethodInfo(instrumentedMethodCall);

            if (methodInfo == null)
            {
                throw new NullReferenceException("methodInfo");
            }

            var instrumentedMethodName = instrumentedMethodCall.MethodCall.Method.MethodName;
            var parameters             = GetParameters(instrumentedMethodCall.MethodCall, methodInfo, instrumentedMethodCall.MethodCall.MethodArguments, agent);

            ReportSupportabilityMetric_InvocationMethod(agent, instrumentedMethodName);

            var isTAP = instrumentedMethodCall.InstrumentedMethodInfo.Method.Type.Name == TAPTypeNameShort;
            var shouldTryProcessInboundCatOrDT = _methodNamesStart.Contains(instrumentedMethodName);
            var shouldTryEndTransaction        = _methodNamesEndTrx.Contains(instrumentedMethodName);

            var uri = OperationContext.Current?.IncomingMessageHeaders?.To;

            var transactionName = GetTransactionName(agent, uri, methodInfo);

            // In all cases, we should record this work in a transaction.
            // either create it or use the one that is already there
            // For InvokeEnd, we expect a transaction to be there, but create it
            // just in case.
            if (!transactionAlreadyExists)
            {
                transaction = agent.CreateTransaction(
                    isWeb: true,
                    category: EnumNameCache <WebTransactionType> .GetName(WebTransactionType.WCF),
                    transactionDisplayName: "Windows Communication Foundation",
                    doNotTrackAsUnitOfWork: false);

                transaction.GetExperimentalApi().SetWrapperToken(_wrapperToken);
            }

            var requestPath = uri?.AbsolutePath;

            if (!string.IsNullOrEmpty(requestPath))
            {
                transaction.SetUri(requestPath);
            }

            // For InvokeBegin, Invoke, or InvokeAsync, Set the transaction name and process
            // CAT or DT request information.
            if (shouldTryProcessInboundCatOrDT)
            {
                transaction.SetWebTransactionName(WebTransactionType.WCF, transactionName, TransactionNamePriority.FrameworkHigh);
                transaction.SetRequestParameters(parameters);

                if (!transactionAlreadyExists)
                {
                    var transportType = TransportType.Other;

                    var msgProperties = OperationContext.Current?.IncomingMessageProperties;
                    if (msgProperties != null && msgProperties.TryGetValue(HttpRequestMessageProperty.Name, out var httpRequestMessageObject))
                    {
                        if (httpRequestMessageObject is HttpRequestMessageProperty)
                        {
                            transportType = TransportType.HTTP;
                        }
                    }

                    transaction.AcceptDistributedTraceHeaders(OperationContext.Current, ExtractHeaderValue, transportType);
                }
            }

            // Don't create a segment to cover the EndInvoke on TAP Invocation
            // but we need to instrument the EndInvoke so that we can close the
            // transaction and send the CAT Response.  The continuation that
            // is used for TAP will not reliably have access to the OperationContext
            ISegment segment = null;

            if (!isTAP || _methodNamesStart.Contains(instrumentedMethodName))
            {
                segment = transaction.StartTransactionSegment(instrumentedMethodCall.MethodCall, transactionName);
                if (isTAP)
                {
                    segment.AlwaysDeductChildDuration = true;
                }
            }

            Guid?wrapperExecutionID = null;

            void WriteLogMessage(string message)
            {
                if (!agent.Logger.IsEnabledFor(Agent.Extensions.Logging.Level.Finest))
                {
                    return;
                }

                if (wrapperExecutionID == null)
                {
                    wrapperExecutionID = Guid.NewGuid();
                }

                transaction.LogFinest($"Execution {wrapperExecutionID} - {instrumentedMethodName}: {message}");
            }

            var handledException  = false;
            var isTAPContinuation = false;

            // This continuation method is meant for TAP Async only (InvokeAsync)
            // We don't end the transaction at this point because we dont
            // have access to the OperationContext.  We rely on the (InvokeEnd)
            // to handle this part.
            void HandleContinuation(System.Threading.Tasks.Task t)
            {
                WriteLogMessage("Continuation");

                if (t.IsFaulted)
                {
                    WriteLogMessage("Continuation - Notice Exception");
                    transaction.NoticeError(t.Exception);
                }

                if (segment != null)
                {
                    WriteLogMessage("Continuation - End Segment");
                    segment.End();
                }
            }

            return(Delegates.GetDelegateFor(

                       // This could occur on the Invoke, InvokeBegin, InvokeEnd
                       onFailure: (Exception ex) =>
            {
                WriteLogMessage("OnFailure");

                transaction.NoticeError(ex);
                handledException = true;
            },

                       // This will get called on both Begin/End and TAP (InvokeAsync)
                       onSuccess: (System.Threading.Tasks.Task result) =>
            {
                // If it is TAP, need to wait until the async work is done.
                // attach continuation to determine if exception has occurred and
                // to end the segment.  For Begin/End, there is nothing to do
                // in the continuation.
                if (isTAP)
                {
                    WriteLogMessage("OnSuccess - Schedule Continuation");
                    isTAPContinuation = true;
                    result.ContinueWith(HandleContinuation);
                }
            },

                       onComplete: () =>
            {
                // If this is the TAP InvokeAsync, there is nothing to do here
                // The continuation has been set up and it will determine if there
                // are any problems and to end the segment.
                if (isTAPContinuation)
                {
                    WriteLogMessage("OnComplete - NoOp wait for continuation");
                    return;
                }

                // In all cases, there is a segment, we want to end it.
                // The only case where we wouldn't have a segment would be
                // in the InvokeEnd for TAP
                if (segment != null)
                {
                    WriteLogMessage("OnComplete - End Segment");
                    segment.End();
                }

                // If an exception has occurred or if this is Invoke or InvokeEnd,
                // the transaction should be closed and CAT Response prepared.
                if (handledException || shouldTryEndTransaction)
                {
                    var wcfStartedTransaction = transaction.GetExperimentalApi().GetWrapperToken() == _wrapperToken;

                    if (wcfStartedTransaction)
                    {
                        WriteLogMessage("OnComplete - End transaction");
                        transaction.End();

                        ProcessResponse(transaction, OperationContext.Current);
                    }
                }
            }));
        }