public override async Task <ResourceResponse> UpdateActivityAsync(ITurnContext turnContext, Activity activity, CancellationToken cancellationToken)
        {
            var requestPath = $"/activities/{activity.Id}";
            var request     = StreamingRequest.CreatePut(requestPath);

            // set callerId to empty so it's not sent over the wire
            activity.CallerId = null;

            request.SetBody(activity);

            var response = default(ResourceResponse);

            _botTelemetryClient.TrackTrace($"Updating activity. activity id: {activity.Id}", Severity.Information, null);

            var stopWatch = new Diagnostics.Stopwatch();

            try
            {
                stopWatch.Start();
                response = await SendRequestAsync <ResourceResponse>(request, cancellationToken).ConfigureAwait(false);

                stopWatch.Stop();
            }
            catch (Exception ex)
            {
                throw new SkillWebSocketCallbackException($"Callback failed. Verb: PUT, Path: {requestPath}", ex);
            }

            _botTelemetryClient.TrackEvent("SkillWebSocketUpdateActivityLatency", null, new Dictionary <string, double>
            {
                { "Latency", stopWatch.ElapsedMilliseconds },
            });

            return(response);
        }
        public void Request_Create_Put_Success()
        {
            var r = StreamingRequest.CreatePut();

            Assert.AreEqual(StreamingRequest.PUT, r.Verb);
            Assert.IsNull(r.Path);
            Assert.IsNull(r.Streams);
        }
        /// <summary>
        /// Replaces an existing activity in the conversation.
        /// Throws <see cref="ArgumentNullException"/> on null arguments.
        /// </summary>
        /// <param name="activity">New replacement activity.</param>
        /// <param name="cancellationToken">Optional cancellation token.</param>
        /// <returns>A task that represents the work queued to execute.</returns>
        /// <remarks>If the activity is successfully sent, the task result contains
        /// a <see cref="ResourceResponse"/> object containing the ID that the receiving
        /// channel assigned to the activity.
        /// <para>Before calling this, set the ID of the replacement activity to the ID
        /// of the activity to replace.</para></remarks>
        /// <seealso cref="ITurnContext.OnUpdateActivity(UpdateActivityHandler)"/>
        public async Task <ResourceResponse> UpdateActivityAsync(Activity activity, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (activity == null)
            {
                throw new ArgumentNullException(nameof(activity));
            }

            var route   = $"{StreamingChannelPrefix}{activity.Conversation.Id}/activities/{activity.Id}";
            var request = StreamingRequest.CreatePut(route);

            request.SetBody(activity);

            return(await SendRequestAsync <ResourceResponse>(request, cancellationToken).ConfigureAwait(false));
        }