private static void HookOrProcessResult(HttpWebRequest request)
        {
            IAsyncResult writeAsyncContext = writeAResultAccessor(request);

            if (writeAsyncContext == null || !(asyncCallbackAccessor(writeAsyncContext)?.Target is AsyncCallbackWrapper writeAsyncContextCallback))
            {
                // If we already hooked into the read result during ProcessRequest or we hooked up after the fact already we don't need to do anything here.
                return;
            }

            // If we got here it means the user called [Begin]GetRequestStream[Async] and we have to hook the read result after the fact.

            IAsyncResult readAsyncContext = readAResultAccessor(request);

            if (readAsyncContext == null)
            {
                // We're still trying to establish the connection (no read has started).
                return;
            }

            // Clear our saved callback so we know not to process again.
            asyncCallbackModifier(writeAsyncContext, null);

            if (endCalledAccessor.Invoke(readAsyncContext) || readAsyncContext.CompletedSynchronously)
            {
                // We need to process the result directly because the read callback has already fired. Force a copy because response has likely already been disposed.
                ProcessResult(readAsyncContext, null, writeAsyncContextCallback.Activity, resultAccessor(readAsyncContext), true);
                return;
            }

            // Hook into the result callback if it hasn't already fired.
            AsyncCallbackWrapper callback = new AsyncCallbackWrapper(writeAsyncContextCallback.Request, writeAsyncContextCallback.Activity, asyncCallbackAccessor(readAsyncContext));

            asyncCallbackModifier(readAsyncContext, callback.AsyncCallback);
        }
        private void RaiseRequestEvent(HttpWebRequest request)
        {
            if (this.IsRequestInstrumented(request))
            {
                // This request was instrumented by previous RaiseRequestEvent, such is the case with redirect responses where the same request is sent again.
                return;
            }

            if (this.IsEnabled(ActivityName, request))
            {
                // We don't call StartActivity here because it will fire into user code before the headers are added.

                var activity = new Activity(ActivityName);
                activity.Start();

                IAsyncResult asyncContext = readAResultAccessor(request);
                if (asyncContext != null)
                {
                    // Flow here is for [Begin]GetResponse[Async] without a prior call to [Begin]GetRequestStream[Async].

                    AsyncCallbackWrapper callback = new AsyncCallbackWrapper(request, activity, asyncCallbackAccessor(asyncContext));
                    asyncCallbackModifier(asyncContext, callback.AsyncCallback);
                }
                else
                {
                    // Flow here is for [Begin]GetRequestStream[Async].

                    asyncContext = writeAResultAccessor(request);
                    AsyncCallbackWrapper callback = new AsyncCallbackWrapper(request, activity, asyncCallbackAccessor(asyncContext));
                    asyncCallbackModifier(asyncContext, callback.AsyncCallback);
                }

                InstrumentRequest(request, activity);

                // Only send start event to users who subscribed for it, but start activity anyway
                if (this.IsEnabled(RequestStartName))
                {
                    this.Write(activity.OperationName + ".Start", new { Request = request });
                }
            }
        }
        private static void ProcessRequest(HttpWebRequest request)
        {
            if (!WebRequestActivitySource.HasListeners() || IsRequestInstrumented(request))
            {
                // No subscribers to the ActivitySource or this request was instrumented by previous
                // ProcessRequest, such is the case with redirect responses where the same request is sent again.
                return;
            }

            var activity = WebRequestActivitySource.StartActivity(ActivityName, ActivityKind.Client);

            if (activity == null)
            {
                // There is a listener but it decided not to sample the current request.
                return;
            }

            IAsyncResult asyncContext = writeAResultAccessor(request);

            if (asyncContext != null)
            {
                // Flow here is for [Begin]GetRequestStream[Async].

                AsyncCallbackWrapper callback = new AsyncCallbackWrapper(request, activity, asyncCallbackAccessor(asyncContext));
                asyncCallbackModifier(asyncContext, callback.AsyncCallback);
            }
            else
            {
                // Flow here is for [Begin]GetResponse[Async] without a prior call to [Begin]GetRequestStream[Async].

                asyncContext = readAResultAccessor(request);
                AsyncCallbackWrapper callback = new AsyncCallbackWrapper(request, activity, asyncCallbackAccessor(asyncContext));
                asyncCallbackModifier(asyncContext, callback.AsyncCallback);
            }

            AddRequestTagsAndInstrumentRequest(request, activity);
        }