Ejemplo n.º 1
0
        /// <summary>
        /// Called when the dialog is started and pushed onto the dialog stack.
        /// </summary>
        /// <param name="dc">The <see cref="DialogContext"/> for the current turn of conversation.</param>
        /// <param name="options">Optional, initial information to pass to the dialog.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
            }

            if (Disabled != null && Disabled.GetValue(dc.State))
            {
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }

            // This is injected for testing, and should not be used for anything else.
            var client = dc.Context.TurnState.Get <HttpClient>();

            var disposeHttpClient = false;

            if (client == null)
            {
                disposeHttpClient = true;

                //Note: this should also be analyzed once we start using HttpClientFactory.
#pragma warning disable CA2000 // Dispose objects before losing scope
                client = new HttpClient();
#pragma warning restore CA2000 // Dispose objects before losing scope
            }

            try
            {
                JToken instanceBody = null;
                if (Body != null)
                {
                    var(body, err) = Body.TryGetValue(dc.State);
                    if (err != null)
                    {
                        throw new ArgumentException(err);
                    }

                    instanceBody = (JToken)JToken.FromObject(body).DeepClone();
                }

                var instanceHeaders = Headers == null ? null : Headers.ToDictionary(kv => kv.Key, kv => kv.Value.GetValue(dc.State));

                var(instanceUrl, instanceUrlError) = Url.TryGetValue(dc.State);
                if (instanceUrlError != null)
                {
                    throw new ArgumentException(instanceUrlError);
                }

                // Bind each string token to the data in state
                instanceBody = instanceBody?.ReplaceJTokenRecursively(dc.State);

                using HttpRequestMessage request = new HttpRequestMessage(new System.Net.Http.HttpMethod(Method.ToString()), instanceUrl);

                // Set headers
                if (instanceHeaders != null)
                {
                    foreach (var unit in instanceHeaders)
                    {
                        request.Headers.TryAddWithoutValidation(unit.Key, unit.Value);
                    }
                }

                request.Headers.TryAddWithoutValidation("user-agent", "Mozilla/5.0");

                dynamic traceInfo = new JObject();

                traceInfo.request        = new JObject();
                traceInfo.request.method = Method.ToString();
                traceInfo.request.url    = instanceUrl;

                HttpResponseMessage response = null;
                string contentType           = ContentType?.GetValue(dc.State) ?? "application/json";

                switch (Method)
                {
                case HttpMethod.POST:
                    if (instanceBody == null)
                    {
                        response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        using var postContent     = new StringContent(instanceBody.ToString(), Encoding.UTF8, contentType);
                        traceInfo.request.content = instanceBody.ToString();
                        request.Content           = postContent;
                        traceInfo.request.headers = JObject.FromObject(request.Content.Headers.ToDictionary(t => t.Key, t => (object)t.Value?.FirstOrDefault()));
                        response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
                    }

                    break;

                case HttpMethod.PATCH:
                    if (instanceBody == null)
                    {
                        response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        using var patchContent    = new StringContent(instanceBody.ToString(), Encoding.UTF8, contentType);
                        request.Content           = patchContent;
                        traceInfo.request.content = instanceBody.ToString();
                        traceInfo.request.headers = JObject.FromObject(request.Content.Headers.ToDictionary(t => t.Key, t => (object)t.Value?.FirstOrDefault()));
                        response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
                    }

                    break;

                case HttpMethod.PUT:
                    if (instanceBody == null)
                    {
                        response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        using var putContent      = new StringContent(instanceBody.ToString(), Encoding.UTF8, contentType);
                        traceInfo.request.content = instanceBody.ToString();
                        traceInfo.request.headers = JObject.FromObject(request.Content.Headers.ToDictionary(t => t.Key, t => (object)t.Value?.FirstOrDefault()));
                        request.Content           = putContent;
                        response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
                    }

                    break;

                case HttpMethod.DELETE:
                    response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);

                    break;

                case HttpMethod.GET:
                    response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);

                    break;
                }

                var requestResult = new Result(response.Headers)
                {
                    StatusCode   = (int)response.StatusCode,
                    ReasonPhrase = response.ReasonPhrase,
                };

                object content = (object)await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                switch (ResponseType.GetValue(dc.State))
                {
                case ResponseTypes.Activity:
                    var activity = JsonConvert.DeserializeObject <Activity>((string)content);
                    requestResult.Content = JObject.FromObject(activity);
                    await dc.Context.SendActivityAsync(activity, cancellationToken : cancellationToken).ConfigureAwait(false);

                    break;

                case ResponseTypes.Activities:
                    var activities = JsonConvert.DeserializeObject <Activity[]>((string)content);
                    requestResult.Content = JArray.FromObject(activities);
                    await dc.Context.SendActivitiesAsync(activities, cancellationToken : cancellationToken).ConfigureAwait(false);

                    break;

                case ResponseTypes.Json:
                    // Try set with JOjbect for further retrieving
                    try
                    {
                        content = JToken.Parse((string)content);
                    }
#pragma warning disable CA1031 // Do not catch general exception types (just stringify the content if we can't parse the content).
                    catch
#pragma warning restore CA1031 // Do not catch general exception types
                    {
                        content = content.ToString();
                    }

                    requestResult.Content = content;
                    break;

                case ResponseTypes.Binary:
                    // Try to resolve binary data
                    var bytes = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);

                    requestResult.Content = bytes;
                    break;

                case ResponseTypes.None:
                default:
                    break;
                }

                traceInfo.response = JObject.FromObject(requestResult);

                // Write Trace Activity for the http request and response values
                await dc.Context.TraceActivityAsync("HttpRequest", (object)traceInfo, valueType : "Microsoft.HttpRequest", label : Id).ConfigureAwait(false);

                if (ResultProperty != null)
                {
                    dc.State.SetValue(ResultProperty.GetValue(dc.State), requestResult);
                }

                // return the actionResult as the result of this operation
                return(await dc.EndDialogAsync(result : requestResult, cancellationToken : cancellationToken).ConfigureAwait(false));
            }
            finally
            {
                if (disposeHttpClient)
                {
                    client.Dispose();
                }
            }
        }