From 293894ed7749757986592b3d8ff64ead869453b8 Mon Sep 17 00:00:00 2001 From: Gabo Gilabert Date: Wed, 15 Jul 2020 15:36:43 -0400 Subject: [PATCH] Added FxCop and Async analyzers to the QnAMaker project. --- .../Dialogs/QnAMakerDialog.cs | 58 +++++++++---------- .../Microsoft.Bot.Builder.AI.QnA.csproj | 23 +++++--- .../Models/FeedbackRecords.cs | 2 + .../Models/Metadata.cs | 2 + .../Models/QnAMakerTraceInfo.cs | 10 +++- .../Models/QnAResponseContext.cs | 2 + .../Models/QueryResult.cs | 4 ++ .../Models/QueryResults.cs | 2 + .../Models/RankerTypes.cs | 2 + .../Microsoft.Bot.Builder.AI.QnA/QnAMaker.cs | 15 ++++- .../QnAMakerOptions.cs | 6 +- .../QnAMakerRecognizer.cs | 9 +-- .../Utils/GenerateAnswerUtils.cs | 8 +-- .../Utils/HttpRequestUtils.cs | 17 +++--- .../QnAMakerTests.cs | 2 +- 15 files changed, 102 insertions(+), 60 deletions(-) diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Dialogs/QnAMakerDialog.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Dialogs/QnAMakerDialog.cs index bc21ae98b0..c296c0b650 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Dialogs/QnAMakerDialog.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Dialogs/QnAMakerDialog.cs @@ -365,7 +365,7 @@ protected override async Task OnPreBubbleEventAsync(DialogContext dc, Dial } var suggestedQuestions = dc.State.GetValue>($"this.suggestedQuestions"); - if (suggestedQuestions != null && suggestedQuestions.Any(question => string.Compare(question, reply.Trim(), ignoreCase: true) == 0)) + if (suggestedQuestions != null && suggestedQuestions.Any(question => string.Compare(question, reply.Trim(), StringComparison.OrdinalIgnoreCase) == 0)) { // it matches one of the suggested actions, we like that. return true; @@ -439,7 +439,7 @@ protected virtual Task GetQnAMakerOptionsAsync(DialogContext dc /// The for the current turn of conversation. /// A representing the asynchronous operation. /// If the task is successful, the result contains the response options to use. - protected async virtual Task GetQnAResponseOptionsAsync(DialogContext dc) + protected virtual async Task GetQnAResponseOptionsAsync(DialogContext dc) { return new QnADialogResponseOptions { @@ -449,6 +449,31 @@ protected async virtual Task GetQnAResponseOptionsAsyn CardNoMatchResponse = await this.CardNoMatchResponse.BindAsync(dc).ConfigureAwait(false) }; } + + private static void ResetOptions(DialogContext dc, QnAMakerDialogOptions dialogOptions) + { + // Resetting context and QnAId + dialogOptions.QnAMakerOptions.QnAId = 0; + dialogOptions.QnAMakerOptions.Context = new QnARequestContext(); + + // -Check if previous context is present, if yes then put it with the query + // -Check for id if query is present in reverse index. + var previousContextData = ObjectPath.GetPathValue>(dc.ActiveDialog.State, QnAContextData, new Dictionary()); + var previousQnAId = ObjectPath.GetPathValue(dc.ActiveDialog.State, PreviousQnAId, 0); + + if (previousQnAId > 0) + { + dialogOptions.QnAMakerOptions.Context = new QnARequestContext + { + PreviousQnAId = previousQnAId + }; + + if (previousContextData.TryGetValue(dc.Context.Activity.Text, out var currentQnAId)) + { + dialogOptions.QnAMakerOptions.QnAId = currentQnAId; + } + } + } private async Task CallGenerateAnswerAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { @@ -485,7 +510,7 @@ private async Task CallGenerateAnswerAsync(WaterfallStepContex // Get filtered list of the response that support low score variation criteria. response.Answers = qnaClient.GetLowScoreVariation(response.Answers); - if (response.Answers.Count() > 1 && isActiveLearningEnabled) + if (response.Answers.Length > 1 && isActiveLearningEnabled) { var suggestedQuestions = new List(); foreach (var qna in response.Answers) @@ -516,31 +541,6 @@ private async Task CallGenerateAnswerAsync(WaterfallStepContex return await stepContext.NextAsync(result, cancellationToken).ConfigureAwait(false); } - private void ResetOptions(DialogContext dc, QnAMakerDialogOptions dialogOptions) - { - // Resetting context and QnAId - dialogOptions.QnAMakerOptions.QnAId = 0; - dialogOptions.QnAMakerOptions.Context = new QnARequestContext(); - - // -Check if previous context is present, if yes then put it with the query - // -Check for id if query is present in reverse index. - var previousContextData = ObjectPath.GetPathValue>(dc.ActiveDialog.State, QnAContextData, new Dictionary()); - var previousQnAId = ObjectPath.GetPathValue(dc.ActiveDialog.State, PreviousQnAId, 0); - - if (previousQnAId > 0) - { - dialogOptions.QnAMakerOptions.Context = new QnARequestContext - { - PreviousQnAId = previousQnAId - }; - - if (previousContextData.TryGetValue(dc.Context.Activity.Text, out var currentQnAId)) - { - dialogOptions.QnAMakerOptions.QnAId = currentQnAId; - } - } - } - private async Task CallTrainAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var dialogOptions = ObjectPath.GetPathValue(stepContext.ActiveDialog.State, Options); @@ -613,7 +613,7 @@ private async Task CheckForMultiTurnPromptAsync(WaterfallStepC var answer = response.First(); - if (answer.Context != null && answer.Context.Prompts.Count() > 0) + if (answer.Context != null && answer.Context.Prompts.Length > 0) { var previousContextData = ObjectPath.GetPathValue(stepContext.ActiveDialog.State, QnAContextData, new Dictionary()); var previousQnAId = ObjectPath.GetPathValue(stepContext.ActiveDialog.State, PreviousQnAId, 0); diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Microsoft.Bot.Builder.AI.QnA.csproj b/libraries/Microsoft.Bot.Builder.AI.QnA/Microsoft.Bot.Builder.AI.QnA.csproj index 9114ab030a..dc1999d015 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Microsoft.Bot.Builder.AI.QnA.csproj +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Microsoft.Bot.Builder.AI.QnA.csproj @@ -21,7 +21,7 @@ Full true - + @@ -31,20 +31,27 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - - - - - - + + + + + + \ No newline at end of file diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/FeedbackRecords.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/FeedbackRecords.cs index 5d832eee46..1b2a560971 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/FeedbackRecords.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/FeedbackRecords.cs @@ -17,6 +17,8 @@ public class FeedbackRecords /// List of feedback records. /// [JsonProperty("feedbackRecords")] +#pragma warning disable CA1819 // Properties should not return arrays (we can't change this without breaking binary compat) public FeedbackRecord[] Records { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays } } diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/Metadata.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/Metadata.cs index 3a2c4df49b..f13362a679 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/Metadata.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/Metadata.cs @@ -10,7 +10,9 @@ namespace Microsoft.Bot.Builder.AI.QnA /// Represents the Metadata object sent as part of QnA Maker requests. /// [Serializable] +#pragma warning disable CA1724 // Type names should not match namespaces (we can't change this without breaking binary compat) public class Metadata +#pragma warning restore CA1724 // Type names should not match namespaces { /// /// Gets or sets the name for the Metadata property. diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QnAMakerTraceInfo.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QnAMakerTraceInfo.cs index 19f2900daf..115450ebb0 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QnAMakerTraceInfo.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QnAMakerTraceInfo.cs @@ -28,7 +28,9 @@ public class QnAMakerTraceInfo /// Results that QnAMaker returned. /// [JsonProperty("queryResults")] +#pragma warning disable CA1819 // Properties should not return arrays (we can't change this without breaking binary compat) public QueryResult[] QueryResults { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays /// /// Gets or sets iD of the Knowledgebase that is being used. @@ -66,8 +68,10 @@ public class QnAMakerTraceInfo /// The filters used to return answers that have the specified metadata. /// [JsonProperty("strictFilters")] - public Metadata[] StrictFilters { get; set; } - +#pragma warning disable CA1819 // Properties should not return arrays (we can't change this without breaking binary compat) + public Metadata[] StrictFilters { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays + /// /// Gets or sets context for multi-turn responses. /// @@ -112,6 +116,8 @@ public class QnAMakerTraceInfo /// [Obsolete("This property is no longer used and will be ignored")] [JsonIgnore] +#pragma warning disable CA1819 // Properties should not return arrays (this property is obsolete and we won't change it) public Metadata[] MetadataBoost { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays } } diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QnAResponseContext.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QnAResponseContext.cs index 88737ad334..7289982bf7 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QnAResponseContext.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QnAResponseContext.cs @@ -18,6 +18,8 @@ public class QnAResponseContext /// The QnA prompts array. /// [JsonProperty(PropertyName = "prompts")] +#pragma warning disable CA1819 // Properties should not return arrays (we can't change this without breaking binary compat) public QnaMakerPrompt[] Prompts { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays } } diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QueryResult.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QueryResult.cs index 99ec649dd3..4cfd180bab 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QueryResult.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QueryResult.cs @@ -17,7 +17,9 @@ public class QueryResult /// The list of questions indexed in the QnA Service for the given answer. /// [JsonProperty("questions")] +#pragma warning disable CA1819 // Properties should not return arrays (we can't change this without breaking binary compat) public string[] Questions { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays /// /// Gets or sets the answer text. @@ -46,7 +48,9 @@ public class QueryResult /// Metadata that is associated with the answer. /// [JsonProperty(PropertyName = "metadata")] +#pragma warning disable CA1819 // Properties should not return arrays (we can't change this without breaking binary compat) public Metadata[] Metadata { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays /// /// Gets or sets the source from which the QnA was extracted. diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QueryResults.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QueryResults.cs index c47322cb21..aa651c2fc1 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QueryResults.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/QueryResults.cs @@ -19,7 +19,9 @@ public class QueryResults /// sorted in decreasing order of ranking score. /// [JsonProperty("answers")] +#pragma warning disable CA1819 // Properties should not return arrays (we can't change this without breaking binary compat) public QueryResult[] Answers { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays /// /// Gets or sets a value indicating whether gets or set for the active learning enable flag. diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/RankerTypes.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/RankerTypes.cs index ca165d7334..1c85b5343d 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Models/RankerTypes.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Models/RankerTypes.cs @@ -6,7 +6,9 @@ namespace Microsoft.Bot.Builder.AI.QnA /// /// Enumeration of types of ranking. /// +#pragma warning disable CA1052 // Static holder types should be Static or NotInheritable (we can't change this without breaking binary compat) public class RankerTypes +#pragma warning restore CA1052 // Static holder types should be Static or NotInheritable { /// /// Default Ranker Behaviour. i.e. Ranking based on Questions and Answer. diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMaker.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMaker.cs index eff3e93b47..873fd3d55b 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMaker.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMaker.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net.Http; using System.Threading; @@ -67,7 +68,7 @@ public QnAMaker(QnAMakerEndpoint endpoint, QnAMakerOptions options, HttpClient h throw new ArgumentException(nameof(endpoint.EndpointKey)); } - if (_endpoint.Host.EndsWith("v2.0") || _endpoint.Host.EndsWith("v3.0")) + if (_endpoint.Host.EndsWith("v2.0", StringComparison.Ordinal) || _endpoint.Host.EndsWith("v3.0", StringComparison.Ordinal)) { throw new NotSupportedException("v2.0 and v3.0 of QnA Maker service is no longer supported in the QnA Maker."); } @@ -109,10 +110,13 @@ public QnAMaker(QnAMakerEndpoint endpoint, QnAMakerOptions options = null, HttpC /// If null, a default client is used for this instance. /// The IBotTelemetryClient used for logging telemetry events. /// Set to true to include personally identifiable information in telemetry events. + [Obsolete("Constructor is deprecated, please use QnAMaker(QnAMakerEndpoint endpoint, QnAMakerOptions options, HttpClient httpClient).")] +#pragma warning disable CS0618 // Type or member is obsolete, this is here only for backward compat and should be removed when QnAMakerService is removed. public QnAMaker(QnAMakerService service, QnAMakerOptions options, HttpClient httpClient, IBotTelemetryClient telemetryClient, bool logPersonalInformation = false) : this(new QnAMakerEndpoint(service), options, httpClient, telemetryClient, logPersonalInformation) { } +#pragma warning restore CS0618 // Type or member is obsolete /// /// Initializes a new instance of the class. @@ -121,10 +125,13 @@ public QnAMaker(QnAMakerService service, QnAMakerOptions options, HttpClient htt /// The options for the QnA Maker knowledge base. /// An alternate client with which to talk to QnAMaker. /// If null, a default client is used for this instance. + [Obsolete("Constructor is deprecated, please use QnAMaker(QnAMakerEndpoint endpoint, QnAMakerOptions options, HttpClient httpClient).")] +#pragma warning disable CS0618 // Type or member is obsolete, this is here only for backward compat and should be removed when QnAMakerService is removed. public QnAMaker(QnAMakerService service, QnAMakerOptions options = null, HttpClient httpClient = null) : this(new QnAMakerEndpoint(service), options, httpClient, null) { } +#pragma warning restore CS0618 // Type or member is obsolete /// /// Gets the to be used when calling the QnA Maker API. @@ -198,7 +205,7 @@ public async Task GetAnswersRawAsync( if (turnContext.Activity == null) { - throw new ArgumentNullException(nameof(turnContext.Activity)); + throw new ArgumentException($"The {nameof(turnContext.Activity)} property for {nameof(turnContext)} can't be null.", nameof(turnContext)); } var messageActivity = turnContext.Activity.AsMessageActivity(); @@ -272,7 +279,9 @@ protected virtual async Task OnQnaResultsAsync( /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// additionalProperties /// A tuple of Properties and Metrics that will be sent to the IBotTelemetryClient.TrackEvent method for the QnAMessage event. The properties and metrics returned the standard properties logged with any properties passed from the GetAnswersAsync method. +#pragma warning disable CA1801 // Review unused parameters (we can't remove cancellationToken without breaking binary compat) protected Task<(Dictionary Properties, Dictionary Metrics)> FillQnAEventAsync(QueryResult[] queryResults, ITurnContext turnContext, Dictionary telemetryProperties = null, Dictionary telemetryMetrics = null, CancellationToken cancellationToken = default(CancellationToken)) +#pragma warning restore CA1801 // Review unused parameters { var properties = new Dictionary(); var metrics = new Dictionary(); @@ -301,7 +310,7 @@ protected virtual async Task OnQnaResultsAsync( { var queryResult = queryResults[0]; properties.Add(QnATelemetryConstants.MatchedQuestionProperty, JsonConvert.SerializeObject(queryResult.Questions)); - properties.Add(QnATelemetryConstants.QuestionIdProperty, queryResult.Id.ToString()); + properties.Add(QnATelemetryConstants.QuestionIdProperty, queryResult.Id.ToString(CultureInfo.InvariantCulture)); properties.Add(QnATelemetryConstants.AnswerProperty, queryResult.Answer); metrics.Add(QnATelemetryConstants.ScoreProperty, queryResult.Score); properties.Add(QnATelemetryConstants.ArticleFoundProperty, "true"); diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMakerOptions.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMakerOptions.cs index 3a3beb358a..62ca1325e8 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMakerOptions.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMakerOptions.cs @@ -62,7 +62,7 @@ public QnAMakerOptions() public QnARequestContext Context { get; set; } /// - /// Gets or sets QnA Id of the current question asked (if avaliable). + /// Gets or sets QnA Id of the current question asked (if availble). /// /// /// Id of the current question asked. @@ -77,7 +77,9 @@ public QnAMakerOptions() /// An array of . /// [JsonProperty("strictFilters")] +#pragma warning disable CA1819 // Properties should not return arrays (we can't change this without breaking binary compat) public Metadata[] StrictFilters { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays /// /// Gets or sets the collection to be sent when calling QnA Maker to boost results. @@ -87,7 +89,9 @@ public QnAMakerOptions() /// [Obsolete("This property is no longer used and will be ignored")] [JsonIgnore] +#pragma warning disable CA1819 // Properties should not return arrays (property is obsolete, we won't change it) public Metadata[] MetadataBoost { get; set; } +#pragma warning restore CA1819 // Properties should not return arrays /// /// Gets or sets a value indicating whether to call test or prod environment of knowledge base to be called. diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMakerRecognizer.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMakerRecognizer.cs index 1334e76693..01c8633348 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMakerRecognizer.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/QnAMakerRecognizer.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Net.Http; using System.Threading; @@ -223,7 +224,7 @@ public override async Task RecognizeAsync(DialogContext dialog } } - if (topAnswer.Answer.Trim().ToLower().StartsWith(IntentPrefix)) + if (topAnswer.Answer.Trim().ToUpperInvariant().StartsWith(IntentPrefix.ToUpperInvariant(), StringComparison.Ordinal)) { recognizerResult.Intents.Add(topAnswer.Answer.Trim().Substring(IntentPrefix.Length).Trim(), new IntentScore { Score = topAnswer.Score }); } @@ -273,9 +274,9 @@ protected virtual Task GetQnAMakerClientAsync(DialogContext dc) var endpoint = new QnAMakerEndpoint { - EndpointKey = epKey ?? throw new ArgumentNullException(nameof(EndpointKey), error), - Host = hn ?? throw new ArgumentNullException(nameof(HostName), error2), - KnowledgeBaseId = kbId ?? throw new ArgumentNullException(nameof(KnowledgeBaseId), error3) + EndpointKey = epKey ?? throw new InvalidOperationException($"Unable to get a value for {nameof(EndpointKey)} from state. {error}"), + Host = hn ?? throw new InvalidOperationException($"Unable to a get value for {nameof(HostName)} from state. {error2}"), + KnowledgeBaseId = kbId ?? throw new InvalidOperationException($"Unable to get a value for {nameof(KnowledgeBaseId)} from state. {error3}") }; return Task.FromResult(new QnAMaker(endpoint, new QnAMakerOptions(), HttpClient, TelemetryClient, logPersonalInfo)); diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Utils/GenerateAnswerUtils.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Utils/GenerateAnswerUtils.cs index 1cc93be2d0..9168cf98aa 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Utils/GenerateAnswerUtils.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Utils/GenerateAnswerUtils.cs @@ -73,7 +73,7 @@ public async Task GetAnswersRawAsync(ITurnContext turnContext, IMe if (turnContext.Activity == null) { - throw new ArgumentNullException(nameof(turnContext.Activity)); + throw new ArgumentException($"The {nameof(turnContext.Activity)} property for {nameof(turnContext)} can't be null.", nameof(turnContext)); } if (messageActivity == null) @@ -121,7 +121,7 @@ private static void ValidateOptions(QnAMakerOptions options) if (options.ScoreThreshold < 0 || options.ScoreThreshold > 1) { - throw new ArgumentOutOfRangeException(nameof(options.ScoreThreshold), "Score threshold should be a value between 0 and 1"); + throw new ArgumentOutOfRangeException(nameof(options), $"The {nameof(options.ScoreThreshold)} property should be a value between 0 and 1"); } if (options.Timeout == 0.0D) @@ -131,12 +131,12 @@ private static void ValidateOptions(QnAMakerOptions options) if (options.Top < 1) { - throw new ArgumentOutOfRangeException(nameof(options.Top), "Top should be an integer greater than 0"); + throw new ArgumentOutOfRangeException(nameof(options), $"The {nameof(options.Top)} property should be an integer greater than 0"); } if (options.StrictFilters == null) { - options.StrictFilters = new Metadata[] { }; + options.StrictFilters = Array.Empty(); } if (options.RankerType == null) diff --git a/libraries/Microsoft.Bot.Builder.AI.QnA/Utils/HttpRequestUtils.cs b/libraries/Microsoft.Bot.Builder.AI.QnA/Utils/HttpRequestUtils.cs index a60f0143a8..09ba4504e0 100644 --- a/libraries/Microsoft.Bot.Builder.AI.QnA/Utils/HttpRequestUtils.cs +++ b/libraries/Microsoft.Bot.Builder.AI.QnA/Utils/HttpRequestUtils.cs @@ -55,19 +55,20 @@ public async Task ExecuteHttpRequestAsync(string requestUrl throw new ArgumentNullException(nameof(endpoint)); } - var request = new HttpRequestMessage(HttpMethod.Post, requestUrl); - - request.Content = new StringContent(payloadBody, Encoding.UTF8, "application/json"); + using (var request = new HttpRequestMessage(HttpMethod.Post, requestUrl)) + { + request.Content = new StringContent(payloadBody, Encoding.UTF8, "application/json"); - SetHeaders(request, endpoint); + SetHeaders(request, endpoint); - var response = await this._httpClient.SendAsync(request).ConfigureAwait(false); - response.EnsureSuccessStatusCode(); + var response = await _httpClient.SendAsync(request).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); - return response; + return response; + } } - private void SetHeaders(HttpRequestMessage request, QnAMakerEndpoint endpoint) + private static void SetHeaders(HttpRequestMessage request, QnAMakerEndpoint endpoint) { request.Headers.Add("Authorization", $"EndpointKey {endpoint.EndpointKey}"); request.Headers.Add("Ocp-Apim-Subscription-Key", endpoint.EndpointKey); diff --git a/tests/Microsoft.Bot.Builder.AI.QnA.Tests/QnAMakerTests.cs b/tests/Microsoft.Bot.Builder.AI.QnA.Tests/QnAMakerTests.cs index 3b45de8dab..8833a0c04a 100644 --- a/tests/Microsoft.Bot.Builder.AI.QnA.Tests/QnAMakerTests.cs +++ b/tests/Microsoft.Bot.Builder.AI.QnA.Tests/QnAMakerTests.cs @@ -311,7 +311,7 @@ public async Task QnaMaker_TraceActivity_BadMessage() [TestMethod] [TestCategory("AI")] [TestCategory("QnAMaker")] - [ExpectedException(typeof(ArgumentNullException))] + [ExpectedException(typeof(ArgumentException))] public async Task QnaMaker_TraceActivity_NullActivity() { // Get basic Qna