diff --git a/BotBuilder-DotNet.ruleset b/BotBuilder-DotNet.ruleset
index e88cf5c5d8..d69b00d231 100644
--- a/BotBuilder-DotNet.ruleset
+++ b/BotBuilder-DotNet.ruleset
@@ -6,11 +6,16 @@
-
-
-
+
+
+
+
+
+
+
+
+
-
@@ -186,15 +191,6 @@
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index 425c123d9f..120e4f50e2 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -59,7 +59,7 @@
Suppress a warning about upcoming deprecation of PackageLicenseUrl. When embedding licenses are supported,
replace PackageLicenseUrl with PackageLicenseExpression.
-->
- NU5125
+ $(NoWarn);NU5125
true
true
snupkg
diff --git a/FunctionalTests/Directory.Build.props b/FunctionalTests/Directory.Build.props
index 421e45f896..2e102e2643 100644
--- a/FunctionalTests/Directory.Build.props
+++ b/FunctionalTests/Directory.Build.props
@@ -1,8 +1,9 @@
-
- $(NoWarn);SA0001;CS1573,CS1591,CS1712
+
+
+ $(NoWarn);SA0001;CS1573;CS1591;CS1712;SX1309
diff --git a/libraries/Adapters/Directory.Build.props b/libraries/Adapters/Directory.Build.props
index c8c7901060..2f68009aa3 100644
--- a/libraries/Adapters/Directory.Build.props
+++ b/libraries/Adapters/Directory.Build.props
@@ -1,7 +1,11 @@
-
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/libraries/Adapters/Microsoft.Bot.Builder.Adapters.Twilio/TwilioAdapter.cs b/libraries/Adapters/Microsoft.Bot.Builder.Adapters.Twilio/TwilioAdapter.cs
index 32aa1fda1a..a3b1a0d4fd 100644
--- a/libraries/Adapters/Microsoft.Bot.Builder.Adapters.Twilio/TwilioAdapter.cs
+++ b/libraries/Adapters/Microsoft.Bot.Builder.Adapters.Twilio/TwilioAdapter.cs
@@ -81,7 +81,7 @@ public override async Task SendActivitiesAsync(ITurnContext
{
var messageOptions = TwilioHelper.ActivityToTwilio(activity, _twilioClient.Options.TwilioNumber);
- var res = await _twilioClient.SendMessage(messageOptions, cancellationToken).ConfigureAwait(false);
+ var res = await _twilioClient.SendMessageAsync(messageOptions, cancellationToken).ConfigureAwait(false);
var response = new ResourceResponse() { Id = res, };
diff --git a/libraries/Adapters/Microsoft.Bot.Builder.Adapters.Twilio/TwilioClientWrapper.cs b/libraries/Adapters/Microsoft.Bot.Builder.Adapters.Twilio/TwilioClientWrapper.cs
index 231374d669..8e95f46278 100644
--- a/libraries/Adapters/Microsoft.Bot.Builder.Adapters.Twilio/TwilioClientWrapper.cs
+++ b/libraries/Adapters/Microsoft.Bot.Builder.Adapters.Twilio/TwilioClientWrapper.cs
@@ -60,7 +60,7 @@ public TwilioClientWrapper(TwilioAdapterOptions options)
/// An object containing the parameters for the message to send.
/// A cancellation token for the task.
/// The SID of the Twilio message sent.
- public virtual async Task SendMessage(CreateMessageOptions messageOptions, CancellationToken cancellationToken)
+ public virtual async Task SendMessageAsync(CreateMessageOptions messageOptions, CancellationToken cancellationToken)
{
var messageResource = await MessageResource.CreateAsync(messageOptions).ConfigureAwait(false);
return messageResource.Sid;
diff --git a/libraries/AdaptiveExpressions/AdaptiveExpressions.csproj b/libraries/AdaptiveExpressions/AdaptiveExpressions.csproj
index 397e67e8de..f73da99a23 100644
--- a/libraries/AdaptiveExpressions/AdaptiveExpressions.csproj
+++ b/libraries/AdaptiveExpressions/AdaptiveExpressions.csproj
@@ -18,7 +18,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder.AI.LUIS/Microsoft.Bot.Builder.AI.Luis.csproj b/libraries/Microsoft.Bot.Builder.AI.LUIS/Microsoft.Bot.Builder.AI.Luis.csproj
index cfaf785696..7998866d9e 100644
--- a/libraries/Microsoft.Bot.Builder.AI.LUIS/Microsoft.Bot.Builder.AI.Luis.csproj
+++ b/libraries/Microsoft.Bot.Builder.AI.LUIS/Microsoft.Bot.Builder.AI.Luis.csproj
@@ -25,7 +25,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
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 1406c9056b..3ba2cef6d7 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
@@ -24,7 +24,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder.Azure/Microsoft.Bot.Builder.Azure.csproj b/libraries/Microsoft.Bot.Builder.Azure/Microsoft.Bot.Builder.Azure.csproj
index 84e4a6c68f..aade4c08f1 100644
--- a/libraries/Microsoft.Bot.Builder.Azure/Microsoft.Bot.Builder.Azure.csproj
+++ b/libraries/Microsoft.Bot.Builder.Azure/Microsoft.Bot.Builder.Azure.csproj
@@ -23,7 +23,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder.Dialogs.Adaptive.Testing/Microsoft.Bot.Builder.Dialogs.Adaptive.Testing.csproj b/libraries/Microsoft.Bot.Builder.Dialogs.Adaptive.Testing/Microsoft.Bot.Builder.Dialogs.Adaptive.Testing.csproj
index 70b7cc1f27..314e2cf89f 100644
--- a/libraries/Microsoft.Bot.Builder.Dialogs.Adaptive.Testing/Microsoft.Bot.Builder.Dialogs.Adaptive.Testing.csproj
+++ b/libraries/Microsoft.Bot.Builder.Dialogs.Adaptive.Testing/Microsoft.Bot.Builder.Dialogs.Adaptive.Testing.csproj
@@ -29,7 +29,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder.Dialogs.Adaptive/Microsoft.Bot.Builder.Dialogs.Adaptive.csproj b/libraries/Microsoft.Bot.Builder.Dialogs.Adaptive/Microsoft.Bot.Builder.Dialogs.Adaptive.csproj
index a097403401..04ddad9ce5 100644
--- a/libraries/Microsoft.Bot.Builder.Dialogs.Adaptive/Microsoft.Bot.Builder.Dialogs.Adaptive.csproj
+++ b/libraries/Microsoft.Bot.Builder.Dialogs.Adaptive/Microsoft.Bot.Builder.Dialogs.Adaptive.csproj
@@ -26,7 +26,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder.Dialogs.Debugging/Microsoft.Bot.Builder.Dialogs.Debugging.csproj b/libraries/Microsoft.Bot.Builder.Dialogs.Debugging/Microsoft.Bot.Builder.Dialogs.Debugging.csproj
index fb80edfa82..24bdb72af4 100644
--- a/libraries/Microsoft.Bot.Builder.Dialogs.Debugging/Microsoft.Bot.Builder.Dialogs.Debugging.csproj
+++ b/libraries/Microsoft.Bot.Builder.Dialogs.Debugging/Microsoft.Bot.Builder.Dialogs.Debugging.csproj
@@ -26,7 +26,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder.Dialogs.Declarative/Microsoft.Bot.Builder.Dialogs.Declarative.csproj b/libraries/Microsoft.Bot.Builder.Dialogs.Declarative/Microsoft.Bot.Builder.Dialogs.Declarative.csproj
index b847442f29..bad5152e82 100644
--- a/libraries/Microsoft.Bot.Builder.Dialogs.Declarative/Microsoft.Bot.Builder.Dialogs.Declarative.csproj
+++ b/libraries/Microsoft.Bot.Builder.Dialogs.Declarative/Microsoft.Bot.Builder.Dialogs.Declarative.csproj
@@ -25,7 +25,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder.Dialogs/Microsoft.Bot.Builder.Dialogs.csproj b/libraries/Microsoft.Bot.Builder.Dialogs/Microsoft.Bot.Builder.Dialogs.csproj
index 5c8e57f416..38124191f8 100644
--- a/libraries/Microsoft.Bot.Builder.Dialogs/Microsoft.Bot.Builder.Dialogs.csproj
+++ b/libraries/Microsoft.Bot.Builder.Dialogs/Microsoft.Bot.Builder.Dialogs.csproj
@@ -27,7 +27,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder.LanguageGeneration/Microsoft.Bot.Builder.LanguageGeneration.csproj b/libraries/Microsoft.Bot.Builder.LanguageGeneration/Microsoft.Bot.Builder.LanguageGeneration.csproj
index 82be0776a6..18472dc8bd 100644
--- a/libraries/Microsoft.Bot.Builder.LanguageGeneration/Microsoft.Bot.Builder.LanguageGeneration.csproj
+++ b/libraries/Microsoft.Bot.Builder.LanguageGeneration/Microsoft.Bot.Builder.LanguageGeneration.csproj
@@ -25,7 +25,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder.TemplateManager/Microsoft.Bot.Builder.TemplateManager.csproj b/libraries/Microsoft.Bot.Builder.TemplateManager/Microsoft.Bot.Builder.TemplateManager.csproj
index 749733e774..617898d7cc 100644
--- a/libraries/Microsoft.Bot.Builder.TemplateManager/Microsoft.Bot.Builder.TemplateManager.csproj
+++ b/libraries/Microsoft.Bot.Builder.TemplateManager/Microsoft.Bot.Builder.TemplateManager.csproj
@@ -23,7 +23,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Builder/ActivityFactory.cs b/libraries/Microsoft.Bot.Builder/ActivityFactory.cs
index bcc829ce3d..7e0cbf65e5 100644
--- a/libraries/Microsoft.Bot.Builder/ActivityFactory.cs
+++ b/libraries/Microsoft.Bot.Builder/ActivityFactory.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.Bot.Schema;
@@ -14,11 +15,15 @@ namespace Microsoft.Bot.Builder
/// The ActivityFactory
/// to generate text and then uses simple markdown semantics like chatdown to create Activity.
///
+#pragma warning disable CA1052 // Static holder types should be Static or NotInheritable (we can't change this without breaking binary compat)
public class ActivityFactory
+#pragma warning restore CA1052 // Static holder types should be Static or NotInheritable
{
+#pragma warning disable CA1308 // Normalize strings to uppercase (LG is heavily invested in lowercase, ignoring this rule in this class)
private const string LGType = "lgType";
- private static readonly string ErrorPrefix = "[ERROR]";
- private static readonly string WarningPrefix = "[WARNING]";
+ private const string ErrorPrefix = "[ERROR]";
+ private const string WarningPrefix = "[WARNING]";
+ private const string AdaptiveCardType = "application/vnd.microsoft.card.adaptive";
private static readonly IList AllActivityTypes = GetAllPublicConstantValues(typeof(ActivityTypes));
private static readonly IList AllActivityProperties = GetAllProperties(typeof(Activity));
@@ -36,8 +41,6 @@ public class ActivityFactory
{ nameof(ReceiptCard).ToLowerInvariant(), ReceiptCard.ContentType },
};
- private static readonly string AdaptiveCardType = "application/vnd.microsoft.card.adaptive";
-
///
/// Generate the activity.
/// Support Both string LG result and structured LG result.
@@ -47,7 +50,7 @@ public class ActivityFactory
public static Activity FromObject(object lgResult)
{
var diagnostics = CheckLGResult(lgResult);
- var errors = diagnostics.Where(u => u.StartsWith(ErrorPrefix));
+ var errors = diagnostics.Where(u => u.StartsWith(ErrorPrefix, StringComparison.Ordinal));
if (errors.Any())
{
@@ -64,7 +67,9 @@ public static Activity FromObject(object lgResult)
var lgJsonResult = JObject.FromObject(lgResult);
return BuildActivityFromLGStructuredResult(lgJsonResult);
}
+#pragma warning disable CA1031 // Do not catch general exception types (we should narrow down the exception being caught but for now we just attempt to build the activity from the text property)
catch
+#pragma warning restore CA1031 // Do not catch general exception types
{
return BuildActivityFromText(lgResult?.ToString()?.Trim());
}
@@ -84,7 +89,7 @@ public static IList CheckLGResult(object lgResult)
return new List { BuildDiagnostic("LG output is empty", false) };
}
- if (!lgStringResult.StartsWith("{") || !lgStringResult.EndsWith("}"))
+ if (!lgStringResult.StartsWith("{", StringComparison.Ordinal) || !lgStringResult.EndsWith("}", StringComparison.Ordinal))
{
return new List { BuildDiagnostic("LG output is not a json object, and will fallback to string format.", false) };
}
@@ -94,7 +99,9 @@ public static IList CheckLGResult(object lgResult)
{
lgStructuredResult = JObject.Parse(lgStringResult);
}
+#pragma warning disable CA1031 // Do not catch general exception types (we should narrow down the exception being caught but for now we just show an error message)
catch
+#pragma warning restore CA1031 // Do not catch general exception types
{
return new List { BuildDiagnostic("LG output is not a json object, and will fallback to string format.", false) };
}
@@ -108,7 +115,9 @@ public static IList CheckLGResult(object lgResult)
{
lgStructuredResult = JObject.FromObject(lgResult);
}
+#pragma warning disable CA1031 // Do not catch general exception types (we should narrow down the exception being caught but for now we just show an error message)
catch
+#pragma warning restore CA1031 // Do not catch general exception types
{
return new List { BuildDiagnostic("LG output is not a json object, and will fallback to string format.", false) };
}
@@ -414,7 +423,8 @@ private static bool IsValidBooleanValue(string boolValue, out bool boolResult)
boolResult = true;
return true;
}
- else if (boolValue.ToLowerInvariant() == "false")
+
+ if (boolValue.ToLowerInvariant() == "false")
{
boolResult = false;
return true;
@@ -757,5 +767,6 @@ private static IList GetAllProperties(Type type)
{
return type.GetProperties().Select(u => u.Name.ToLowerInvariant()).ToList();
}
+#pragma warning restore CA1308 // Normalize strings to uppercase
}
}
diff --git a/libraries/Microsoft.Bot.Builder/ActivityHandler.cs b/libraries/Microsoft.Bot.Builder/ActivityHandler.cs
index baa2d129d0..1ac6e18be3 100644
--- a/libraries/Microsoft.Bot.Builder/ActivityHandler.cs
+++ b/libraries/Microsoft.Bot.Builder/ActivityHandler.cs
@@ -563,10 +563,12 @@ protected virtual Task OnUnrecognizedActivityTypeAsync(ITurnContext turnContext,
return Task.CompletedTask;
}
+#pragma warning disable CA1064 // Exceptions should be public (we can't change this without breaking binary compat, we may consider making this type public in the future)
protected class InvokeResponseException : Exception
+#pragma warning restore CA1064 // Exceptions should be public
{
- private HttpStatusCode _statusCode;
- private object _body;
+ private readonly HttpStatusCode _statusCode;
+ private readonly object _body;
public InvokeResponseException(HttpStatusCode statusCode, object body = null)
{
@@ -574,9 +576,27 @@ public InvokeResponseException(HttpStatusCode statusCode, object body = null)
_body = body;
}
+ public InvokeResponseException()
+ {
+ }
+
+ public InvokeResponseException(string message)
+ : base(message)
+ {
+ }
+
+ public InvokeResponseException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
public InvokeResponse CreateInvokeResponse()
{
- return new InvokeResponse { Status = (int)_statusCode, Body = _body };
+ return new InvokeResponse
+ {
+ Status = (int)_statusCode,
+ Body = _body
+ };
}
}
}
diff --git a/libraries/Microsoft.Bot.Builder/Adapters/TestAdapter.cs b/libraries/Microsoft.Bot.Builder/Adapters/TestAdapter.cs
index efd2465c9b..af82197286 100644
--- a/libraries/Microsoft.Bot.Builder/Adapters/TestAdapter.cs
+++ b/libraries/Microsoft.Bot.Builder/Adapters/TestAdapter.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Security.Claims;
using System.Threading;
@@ -125,8 +126,10 @@ public static ConversationReference CreateConversation(string name, string user
ChannelId = "test",
ServiceUrl = "https://test.com",
Conversation = new ConversationAccount(false, name, name),
- User = new ChannelAccount(id: user.ToLower(), name: user),
- Bot = new ChannelAccount(id: bot.ToLower(), name: bot),
+#pragma warning disable CA1308 // Normalize strings to uppercase (it is safe to use lowercase here, this is just for display purposes)
+ User = new ChannelAccount(id: user.ToLowerInvariant(), name: user),
+ Bot = new ChannelAccount(id: bot.ToLowerInvariant(), name: bot),
+#pragma warning restore CA1308 // Normalize strings to uppercase
Locale = "en-us"
};
}
@@ -174,7 +177,7 @@ public async Task ProcessActivityAsync(Activity activity, BotCallbackHandler cal
activity.Conversation = Conversation.Conversation;
activity.ServiceUrl = Conversation.ServiceUrl;
- var id = activity.Id = (_nextId++).ToString();
+ var id = activity.Id = (_nextId++).ToString(CultureInfo.InvariantCulture);
}
if (activity.Timestamp == null || activity.Timestamp == default(DateTimeOffset))
@@ -370,9 +373,12 @@ public Task CreateConversationAsync(string channelId, BotCallbackHandler callbac
{
ActiveQueue.Clear();
var update = Activity.CreateConversationUpdateActivity();
- update.Conversation = new ConversationAccount() { Id = Guid.NewGuid().ToString("n") };
- var context = new TurnContext(this, (Activity)update);
- return callback(context, cancellationToken);
+ update.ChannelId = channelId;
+ update.Conversation = new ConversationAccount { Id = Guid.NewGuid().ToString("n") };
+ using (var context = new TurnContext(this, (Activity)update))
+ {
+ return callback(context, cancellationToken);
+ }
}
///
@@ -435,7 +441,7 @@ public Activity MakeActivity(string text = null)
Recipient = Conversation.Bot,
Conversation = Conversation.Conversation,
ServiceUrl = Conversation.ServiceUrl,
- Id = (_nextId++).ToString(),
+ Id = (_nextId++).ToString(CultureInfo.InvariantCulture),
Text = text,
};
@@ -892,9 +898,9 @@ public override bool Equals(object obj)
var rhs = obj as UserTokenKey;
if (rhs != null)
{
- return string.Equals(this.ConnectionName, rhs.ConnectionName) &&
- string.Equals(this.UserId, rhs.UserId) &&
- string.Equals(this.ChannelId, rhs.ChannelId);
+ return string.Equals(this.ConnectionName, rhs.ConnectionName, StringComparison.Ordinal) &&
+ string.Equals(this.UserId, rhs.UserId, StringComparison.Ordinal) &&
+ string.Equals(this.ChannelId, rhs.ChannelId, StringComparison.Ordinal);
}
return base.Equals(obj);
@@ -917,7 +923,7 @@ public override bool Equals(object obj)
var rhs = obj as ExchangableTokenKey;
if (rhs != null)
{
- return string.Equals(this.ExchangableItem, rhs.ExchangableItem) &&
+ return string.Equals(this.ExchangableItem, rhs.ExchangableItem, StringComparison.Ordinal) &&
base.Equals(obj);
}
diff --git a/libraries/Microsoft.Bot.Builder/Adapters/TestFlow.cs b/libraries/Microsoft.Bot.Builder/Adapters/TestFlow.cs
index 603198b5df..cebbadedd0 100644
--- a/libraries/Microsoft.Bot.Builder/Adapters/TestFlow.cs
+++ b/libraries/Microsoft.Bot.Builder/Adapters/TestFlow.cs
@@ -97,7 +97,7 @@ public TestFlow Send(string userSays)
{
if (userSays == null)
{
- throw new ArgumentNullException("You have to pass a userSays parameter");
+ throw new ArgumentNullException(nameof(userSays), "You have to pass a userSays parameter");
}
return new TestFlow(
@@ -145,7 +145,7 @@ public TestFlow Send(IActivity userActivity)
{
if (userActivity == null)
{
- throw new ArgumentNullException("You have to pass an Activity");
+ throw new ArgumentNullException(nameof(userActivity), "You have to pass an Activity");
}
return new TestFlow(
@@ -314,7 +314,9 @@ public TestFlow AssertReply(IActivity expected, IEqualityComparer equ
/// The amount of time in milliseconds within which a response is expected.
/// A new object that appends this assertion to the modeled exchange.
/// This method does not modify the original object.
+#pragma warning disable CA1801 // Review unused parameters (we can't remove this withouth breaking binary compat)
public TestFlow AssertReply(Action validateActivity, [CallerMemberName] string description = null, uint timeout = 3000)
+#pragma warning restore CA1801 // Review unused parameters
{
return new TestFlow(
async () =>
@@ -530,9 +532,9 @@ public TestFlow AssertReplyOneOf(string[] candidates, string description = null,
timeout);
}
- private bool IsReply(IActivity activity)
+ private static bool IsReply(IActivity activity)
{
- return string.Equals("bot", activity.From?.Role, StringComparison.InvariantCultureIgnoreCase);
+ return string.Equals("bot", activity.From?.Role, StringComparison.OrdinalIgnoreCase);
}
}
}
diff --git a/libraries/Microsoft.Bot.Builder/BotAssert.cs b/libraries/Microsoft.Bot.Builder/BotAssert.cs
index 4814a1a3f8..cf2b422f13 100644
--- a/libraries/Microsoft.Bot.Builder/BotAssert.cs
+++ b/libraries/Microsoft.Bot.Builder/BotAssert.cs
@@ -10,7 +10,9 @@ namespace Microsoft.Bot.Builder
///
/// Provides methods for debugging Bot Builder code.
///
+#pragma warning disable CA1052 // Static holder types should be Static or NotInheritable (we can't change this without breaking binary compat)
public class BotAssert
+#pragma warning restore CA1052 // Static holder types should be Static or NotInheritable
{
///
/// Checks that an activity object is not null.
diff --git a/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs b/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs
index 7119751e05..4e944aff09 100644
--- a/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs
+++ b/libraries/Microsoft.Bot.Builder/BotFrameworkAdapter.cs
@@ -363,7 +363,7 @@ public override async Task ContinueConversationAsync(ClaimsIdentity claimsIdenti
}
}
- var connectorClient = await CreateConnectorClientAsync(reference.ServiceUrl, claimsIdentity, audience, cancellationToken).ConfigureAwait(false);
+ var connectorClient = await CreateConnectorClientAsync(reference.ServiceUrl, claimsIdentity, audience).ConfigureAwait(false);
context.TurnState.Add(connectorClient);
await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false);
@@ -441,7 +441,7 @@ public override async Task ProcessActivityAsync(ClaimsIdentity c
// The OAuthScope is also stored on the TurnState to get the correct AppCredentials if fetching a token is required.
var scope = SkillValidation.IsSkillClaim(claimsIdentity.Claims) ? JwtTokenValidation.GetAppIdFromClaims(claimsIdentity.Claims) : GetBotFrameworkOAuthScope();
context.TurnState.Add(OAuthScopeKey, scope);
- var connectorClient = await CreateConnectorClientAsync(activity.ServiceUrl, claimsIdentity, scope, cancellationToken).ConfigureAwait(false);
+ var connectorClient = await CreateConnectorClientAsync(activity.ServiceUrl, claimsIdentity, scope).ConfigureAwait(false);
context.TurnState.Add(connectorClient);
context.TurnState.Add(callback);
@@ -552,7 +552,9 @@ public override async Task SendActivitiesAsync(ITurnContext
var oAuthScope = turnContext.TurnState.Get(OAuthScopeKey);
_ = (await GetAppCredentialsAsync(appId, oAuthScope).ConfigureAwait(false)).GetTokenAsync();
}
+#pragma warning disable CA1031 // Do not catch general exception types (we just catch and log the exception here)
catch (Exception ex)
+#pragma warning restore CA1031 // Do not catch general exception types
{
Logger.LogError("Failed to fetch token before processing outgoing activity. " + ex.Message);
}
@@ -1153,28 +1155,28 @@ public virtual async Task> GetAadTokensAsync(I
/// A cancellation token that can be used by other objects
/// or threads to receive notice of cancellation.
/// If the task completes, the exchanged token is returned.
- public virtual async Task ExchangeTokenAsync(ITurnContext turnContext, AppCredentials oAuthAppCredentials, string connectionName, string userId, TokenExchangeRequest exchangeRequest, CancellationToken cancellationToken = default(CancellationToken))
+ public virtual async Task ExchangeTokenAsync(ITurnContext turnContext, AppCredentials oAuthAppCredentials, string connectionName, string userId, TokenExchangeRequest exchangeRequest, CancellationToken cancellationToken = default)
{
BotAssert.ContextNotNull(turnContext);
if (string.IsNullOrWhiteSpace(connectionName))
{
- LogAndThrowException(new ArgumentException(nameof(connectionName)));
+ LogAndThrowException(new ArgumentException($"{nameof(connectionName)} is null or empty", nameof(connectionName)));
}
if (string.IsNullOrWhiteSpace(userId))
{
- LogAndThrowException(new ArgumentException(nameof(userId)));
+ LogAndThrowException(new ArgumentException($"{nameof(userId)} is null or empty", nameof(userId)));
}
if (exchangeRequest == null)
{
- LogAndThrowException(new ArgumentException(nameof(exchangeRequest)));
+ LogAndThrowException(new ArgumentException($"{nameof(exchangeRequest)} is null or empty", nameof(exchangeRequest)));
}
if (string.IsNullOrWhiteSpace(exchangeRequest.Token) && string.IsNullOrWhiteSpace(exchangeRequest.Uri))
{
- LogAndThrowException(new ArgumentException(nameof(exchangeRequest), "Either a Token or Uri property is required on the TokenExchangeRequest"));
+ LogAndThrowException(new ArgumentException("Either a Token or Uri property is required on the TokenExchangeRequest", nameof(exchangeRequest)));
}
var activity = turnContext.Activity;
@@ -1191,13 +1193,11 @@ public virtual async Task> GetAadTokensAsync(I
{
return tokenResponse;
}
- else
- {
- LogAndThrowException(new InvalidOperationException($"ExchangeAsyncAsync returned improper result: {result.GetType()}"));
- // even though LogAndThrowException always throws, compiler gives an error about not all code paths returning a value.
- return null;
- }
+ LogAndThrowException(new InvalidOperationException($"ExchangeAsyncAsync returned improper result: {result.GetType()}"));
+
+ // even though LogAndThrowException always throws, compiler gives an error about not all code paths returning a value.
+ return null;
}
///
@@ -1309,7 +1309,7 @@ public virtual async Task CreateConversationAsync(string channelId, string servi
Task IConnectorClientBuilder.CreateConnectorClientAsync(string serviceUrl, ClaimsIdentity claimsIdentity, string audience, CancellationToken cancellationToken)
{
- return CreateConnectorClientAsync(serviceUrl, claimsIdentity, audience, cancellationToken);
+ return CreateConnectorClientAsync(serviceUrl, claimsIdentity, audience);
}
///
@@ -1321,7 +1321,7 @@ Task IConnectorClientBuilder.CreateConnectorClientAsync(string
protected virtual async Task CreateOAuthApiClientAsync(ITurnContext turnContext, AppCredentials oAuthAppCredentials)
{
if (!OAuthClientConfig.EmulateOAuthCards &&
- string.Equals(turnContext.Activity.ChannelId, Channels.Emulator, StringComparison.InvariantCultureIgnoreCase) &&
+ string.Equals(turnContext.Activity.ChannelId, Channels.Emulator, StringComparison.OrdinalIgnoreCase) &&
(await CredentialProvider.IsAuthenticationDisabledAsync().ConfigureAwait(false)))
{
OAuthClientConfig.EmulateOAuthCards = true;
@@ -1335,7 +1335,7 @@ protected virtual async Task CreateOAuthApiClientAsync(ITurnContext
var appCredentials = oAuthAppCredentials ?? await GetAppCredentialsAsync(appId, oAuthScope).ConfigureAwait(false);
if (!OAuthClientConfig.EmulateOAuthCards &&
- string.Equals(turnContext.Activity.ChannelId, Channels.Emulator, StringComparison.InvariantCultureIgnoreCase) &&
+ string.Equals(turnContext.Activity.ChannelId, Channels.Emulator, StringComparison.OrdinalIgnoreCase) &&
(await CredentialProvider.IsAuthenticationDisabledAsync().ConfigureAwait(false)))
{
OAuthClientConfig.EmulateOAuthCards = true;
@@ -1421,6 +1421,28 @@ protected virtual async Task BuildCredentialsAsync(string appId,
return ChannelProvider != null && ChannelProvider.IsGovernment() ? new MicrosoftGovernmentAppCredentials(appId, appPassword, HttpClient, Logger, oAuthScope) : new MicrosoftAppCredentials(appId, appPassword, HttpClient, Logger, oAuthScope);
}
+ ///
+ /// Gets the AppId of the Bot out of the TurnState.
+ ///
+ /// The context object for the turn.
+ /// Bot's AppId.
+ private static string GetBotAppId(ITurnContext turnContext)
+ {
+ var botIdentity = (ClaimsIdentity)turnContext.TurnState.Get(BotIdentityKey);
+ if (botIdentity == null)
+ {
+ throw new InvalidOperationException("An IIdentity is required in TurnState for this operation.");
+ }
+
+ var appId = botIdentity.Claims.FirstOrDefault(claim => claim.Type == AuthenticationConstants.AudienceClaim)?.Value;
+ if (string.IsNullOrWhiteSpace(appId))
+ {
+ throw new InvalidOperationException("Unable to get the bot AppId from the audience claim.");
+ }
+
+ return appId;
+ }
+
///
/// Generates the CallerId property for the activity based on
/// https://github.com/microsoft/botframework-obi/blob/master/protocols/botframework-activity/botframework-activity.md#appendix-v---caller-id-values.
@@ -1463,10 +1485,9 @@ private async Task GenerateCallerIdAsync(ClaimsIdentity claimsIdentity)
/// The service URL.
/// The claims claimsIdentity.
/// The target audience for the connector.
- /// Cancellation token.
/// ConnectorClient instance.
/// ClaimsIdentity cannot be null. Pass Anonymous ClaimsIdentity if authentication is turned off.
- private async Task CreateConnectorClientAsync(string serviceUrl, ClaimsIdentity claimsIdentity, string audience, CancellationToken cancellationToken = default)
+ private async Task CreateConnectorClientAsync(string serviceUrl, ClaimsIdentity claimsIdentity, string audience)
{
if (claimsIdentity == null)
{
@@ -1497,7 +1518,7 @@ private async Task CreateConnectorClientAsync(string serviceUr
GetBotFrameworkOAuthScope();
}
- appCredentials = await GetAppCredentialsAsync(botId, scope, cancellationToken).ConfigureAwait(false);
+ appCredentials = await GetAppCredentialsAsync(botId, scope).ConfigureAwait(false);
}
return CreateConnectorClient(serviceUrl, appCredentials);
@@ -1544,9 +1565,8 @@ private IConnectorClient CreateConnectorClient(string serviceUrl, AppCredentials
///
/// The application identifier (AAD ID for the bot).
/// The scope for the token. Skills use the skill's app ID.
- /// Cancellation token.
/// App credentials.
- private async Task GetAppCredentialsAsync(string appId, string oAuthScope, CancellationToken cancellationToken = default)
+ private async Task GetAppCredentialsAsync(string appId, string oAuthScope)
{
if (string.IsNullOrWhiteSpace(appId))
{
@@ -1575,28 +1595,6 @@ private async Task GetAppCredentialsAsync(string appId, string o
return appCredentials;
}
- ///
- /// Gets the AppId of the Bot out of the TurnState.
- ///
- /// The context object for the turn.
- /// Bot's AppId.
- private string GetBotAppId(ITurnContext turnContext)
- {
- var botIdentity = (ClaimsIdentity)turnContext.TurnState.Get(BotIdentityKey);
- if (botIdentity == null)
- {
- throw new InvalidOperationException("An IIdentity is required in TurnState for this operation.");
- }
-
- var appId = botIdentity.Claims.FirstOrDefault(claim => claim.Type == AuthenticationConstants.AudienceClaim)?.Value;
- if (string.IsNullOrWhiteSpace(appId))
- {
- throw new InvalidOperationException("Unable to get the bot AppId from the audience claim.");
- }
-
- return appId;
- }
-
///
/// This method returns the correct Bot Framework OAuthScope for AppCredentials.
///
@@ -1608,7 +1606,7 @@ private string GetBotFrameworkOAuthScope()
}
///
- /// Logs and throws an expcetion.
+ /// Logs and throws an exception.
///
/// Exception instance to throw.
/// Source method for the exception.
@@ -1630,7 +1628,7 @@ internal class TenantIdWorkaroundForTeamsMiddleware : IMiddleware
{
public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default)
{
- if (Channels.Msteams.Equals(turnContext.Activity.ChannelId, StringComparison.InvariantCultureIgnoreCase) && turnContext.Activity.Conversation != null && string.IsNullOrEmpty(turnContext.Activity.Conversation.TenantId) && turnContext.Activity.ChannelData != null)
+ if (Channels.Msteams.Equals(turnContext.Activity.ChannelId, StringComparison.OrdinalIgnoreCase) && turnContext.Activity.Conversation != null && string.IsNullOrEmpty(turnContext.Activity.Conversation.TenantId) && turnContext.Activity.ChannelData != null)
{
var teamsChannelData = JObject.FromObject(turnContext.Activity.ChannelData);
if (teamsChannelData["tenant"]?["id"] != null)
diff --git a/libraries/Microsoft.Bot.Builder/BotState.cs b/libraries/Microsoft.Bot.Builder/BotState.cs
index 918c49345f..078db02b9b 100644
--- a/libraries/Microsoft.Bot.Builder/BotState.cs
+++ b/libraries/Microsoft.Bot.Builder/BotState.cs
@@ -134,7 +134,7 @@ public IStatePropertyAccessor CreateProperty(string name)
{ key, cachedState.State },
};
await _storage.WriteAsync(changes).ConfigureAwait(false);
- cachedState.Hash = cachedState.ComputeHash(cachedState.State);
+ cachedState.Hash = CachedBotState.ComputeHash(cachedState.State);
return;
}
}
@@ -230,7 +230,9 @@ public CachedBotState GetCachedState(ITurnContext turnContext)
/// If the task is successful, the result contains the property value, otherwise it will be default(T).
/// or
/// is null.
+#pragma warning disable CA1801 // Review unused parameters (we can't change this without breaking binary compat)
protected Task GetPropertyValueAsync(ITurnContext turnContext, string propertyName, CancellationToken cancellationToken = default(CancellationToken))
+#pragma warning restore CA1801 // Review unused parameters
{
BotAssert.ContextNotNull(turnContext);
@@ -287,7 +289,9 @@ public CachedBotState GetCachedState(ITurnContext turnContext)
/// A task that represents the work queued to execute.
/// or
/// is null.
+#pragma warning disable CA1801 // Review unused parameters (we can't change this without breaking binary compat)
protected Task DeletePropertyValueAsync(ITurnContext turnContext, string propertyName, CancellationToken cancellationToken = default(CancellationToken))
+#pragma warning restore CA1801 // Review unused parameters
{
BotAssert.ContextNotNull(turnContext);
@@ -312,7 +316,9 @@ public CachedBotState GetCachedState(ITurnContext turnContext)
/// A task that represents the work queued to execute.
/// or
/// is null.
+#pragma warning disable CA1801 // Review unused parameters (we can't change this without breaking binary compat)
protected Task SetPropertyValueAsync(ITurnContext turnContext, string propertyName, object value, CancellationToken cancellationToken = default(CancellationToken))
+#pragma warning restore CA1801 // Review unused parameters
{
BotAssert.ContextNotNull(turnContext);
@@ -329,7 +335,9 @@ public CachedBotState GetCachedState(ITurnContext turnContext)
///
/// Internal cached bot state.
///
+#pragma warning disable CA1034 // Nested types should not be visible (we can't change this without breaking binary compat)
public class CachedBotState
+#pragma warning restore CA1034 // Nested types should not be visible
{
internal CachedBotState(IDictionary state = null)
{
@@ -337,18 +345,20 @@ internal CachedBotState(IDictionary state = null)
Hash = ComputeHash(State);
}
+#pragma warning disable CA2227 // Collection properties should be read only (we can't change this without breaking binary compat)
public IDictionary State { get; set; }
+#pragma warning restore CA2227 // Collection properties should be read only
internal string Hash { get; set; }
- internal bool IsChanged()
+ internal static string ComputeHash(object obj)
{
- return Hash != ComputeHash(State);
+ return JsonConvert.SerializeObject(obj);
}
- internal string ComputeHash(object obj)
+ internal bool IsChanged()
{
- return JsonConvert.SerializeObject(obj);
+ return Hash != ComputeHash(State);
}
}
diff --git a/libraries/Microsoft.Bot.Builder/BotStateSet.cs b/libraries/Microsoft.Bot.Builder/BotStateSet.cs
index eb3167904f..d571c80ddf 100644
--- a/libraries/Microsoft.Bot.Builder/BotStateSet.cs
+++ b/libraries/Microsoft.Bot.Builder/BotStateSet.cs
@@ -27,7 +27,9 @@ public BotStateSet(params BotState[] botStates)
/// Gets or sets the BotStates list for the BotStateSet.
///
/// The BotState objects managed by this class.
+#pragma warning disable CA2227 // Collection properties should be read only (we can't change this without breaking binary compat)
public List BotStates { get; set; } = new List();
+#pragma warning restore CA2227 // Collection properties should be read only
///
/// Adds a bot state object to the set.
diff --git a/libraries/Microsoft.Bot.Builder/ComponentRegistration.cs b/libraries/Microsoft.Bot.Builder/ComponentRegistration.cs
index be8271f6a1..ed6f13593e 100644
--- a/libraries/Microsoft.Bot.Builder/ComponentRegistration.cs
+++ b/libraries/Microsoft.Bot.Builder/ComponentRegistration.cs
@@ -4,10 +4,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.ComponentModel;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
namespace Microsoft.Bot.Builder
{
@@ -33,9 +29,11 @@ namespace Microsoft.Bot.Builder
/// ComponentRegistration.Add(new MyComponentRegistration());
///
///
+#pragma warning disable CA1052 // Static holder types should be Static or NotInheritable (we can't change this without breaking binary compat)
public class ComponentRegistration
+#pragma warning restore CA1052 // Static holder types should be Static or NotInheritable
{
- private static ConcurrentDictionary components = new ConcurrentDictionary();
+ private static readonly ConcurrentDictionary _components = new ConcurrentDictionary();
///
/// Gets list of all ComponentRegistration objects registered.
@@ -43,7 +41,7 @@ public class ComponentRegistration
///
/// A numeration of ComponentRegistration objects.
///
- public static IEnumerable
diff --git a/libraries/Microsoft.Bot.Builder/PagedResult.cs b/libraries/Microsoft.Bot.Builder/PagedResult.cs
index 5b1651c880..786864bc6f 100644
--- a/libraries/Microsoft.Bot.Builder/PagedResult.cs
+++ b/libraries/Microsoft.Bot.Builder/PagedResult.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
+using System;
+
namespace Microsoft.Bot.Builder
{
///
@@ -15,7 +17,9 @@ public class PagedResult
///
/// The array of items.
///
- public T[] Items { get; set; } = new T[0];
+#pragma warning disable CA1819 // Properties should not return arrays (can't change this without breaking binary compat)
+ public T[] Items { get; set; } = Array.Empty();
+#pragma warning restore CA1819 // Properties should not return arrays
///
/// Gets or sets a token for retrieving the next page of results.
diff --git a/libraries/Microsoft.Bot.Builder/PrivateConversationState.cs b/libraries/Microsoft.Bot.Builder/PrivateConversationState.cs
index 12731128c8..03fc959e93 100644
--- a/libraries/Microsoft.Bot.Builder/PrivateConversationState.cs
+++ b/libraries/Microsoft.Bot.Builder/PrivateConversationState.cs
@@ -39,9 +39,9 @@ public PrivateConversationState(IStorage storage)
///
protected override string GetStorageKey(ITurnContext turnContext)
{
- var channelId = turnContext.Activity.ChannelId ?? throw new ArgumentNullException("invalid activity-missing channelId");
- var conversationId = turnContext.Activity.Conversation?.Id ?? throw new ArgumentNullException("invalid activity-missing Conversation.Id");
- var userId = turnContext.Activity.From?.Id ?? throw new ArgumentNullException("invalid activity-missing From.Id");
+ var channelId = turnContext.Activity.ChannelId ?? throw new InvalidOperationException("invalid activity-missing channelId");
+ var conversationId = turnContext.Activity.Conversation?.Id ?? throw new InvalidOperationException("invalid activity-missing Conversation.Id");
+ var userId = turnContext.Activity.From?.Id ?? throw new InvalidOperationException("invalid activity-missing From.Id");
return $"{channelId}/conversations/{conversationId}/users/{userId}";
}
}
diff --git a/libraries/Microsoft.Bot.Builder/RecognizerResult.cs b/libraries/Microsoft.Bot.Builder/RecognizerResult.cs
index d482c7e5ca..75785836cc 100644
--- a/libraries/Microsoft.Bot.Builder/RecognizerResult.cs
+++ b/libraries/Microsoft.Bot.Builder/RecognizerResult.cs
@@ -38,7 +38,9 @@ public class RecognizerResult : IRecognizerConvert
/// Mapping from intent to information about the intent.
///
[JsonProperty("intents")]
+#pragma warning disable CA2227 // Collection properties should be read only (we can't change this without breaking binary compat)
public IDictionary Intents { get; set; } = new Dictionary();
+#pragma warning restore CA2227 // Collection properties should be read only
///
/// Gets or sets the recognized top-level entities.
@@ -47,7 +49,9 @@ public class RecognizerResult : IRecognizerConvert
/// Object with each top-level recognized entity as a key.
///
[JsonProperty("entities")]
+#pragma warning disable CA2227 // Collection properties should be read only (we can't change this without breaking binary compat)
public JObject Entities { get; set; } = new JObject();
+#pragma warning restore CA2227 // Collection properties should be read only
///
/// Gets or sets properties that are not otherwise defined by the type but that
@@ -58,7 +62,9 @@ public class RecognizerResult : IRecognizerConvert
/// the JSON object is deserialized, but are instead stored in this property. Such properties
/// will be written to a JSON object when the instance is serialized.
[JsonExtensionData(ReadData = true, WriteData = true)]
+#pragma warning disable CA2227 // Collection properties should be read only (we can't change this without breaking binary compat)
public IDictionary Properties { get; set; } = new Dictionary();
+#pragma warning restore CA2227 // Collection properties should be read only
///
public void Convert(dynamic result)
diff --git a/libraries/Microsoft.Bot.Builder/RecognizerResultExtensions.cs b/libraries/Microsoft.Bot.Builder/RecognizerResultExtensions.cs
index 0a0978930e..597f2d4a44 100644
--- a/libraries/Microsoft.Bot.Builder/RecognizerResultExtensions.cs
+++ b/libraries/Microsoft.Bot.Builder/RecognizerResultExtensions.cs
@@ -24,7 +24,7 @@ public static (string intent, double score) GetTopScoringIntent(this RecognizerR
if (result.Intents == null)
{
- throw new ArgumentNullException(nameof(result.Intents));
+ throw new InvalidOperationException(nameof(result.Intents));
}
var topIntent = (string.Empty, 0.0d);
diff --git a/libraries/Microsoft.Bot.Builder/RegisterClassMiddleware.cs b/libraries/Microsoft.Bot.Builder/RegisterClassMiddleware.cs
index 5fec5c935a..b049c787b3 100644
--- a/libraries/Microsoft.Bot.Builder/RegisterClassMiddleware.cs
+++ b/libraries/Microsoft.Bot.Builder/RegisterClassMiddleware.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Bot.Builder
public class RegisterClassMiddleware : IMiddleware
where T : class
{
- private string key;
+ private readonly string _key;
///
/// Initializes a new instance of the class.
@@ -29,7 +29,7 @@ public RegisterClassMiddleware(T service)
public RegisterClassMiddleware(T service, string key)
{
this.Service = service;
- this.key = key;
+ this._key = key;
}
///
@@ -53,9 +53,9 @@ public RegisterClassMiddleware(T service, string key)
public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate nextTurn, CancellationToken cancellationToken)
{
// Register service
- if (this.key != null)
+ if (this._key != null)
{
- turnContext.TurnState.Add(this.key, this.Service);
+ turnContext.TurnState.Add(this._key, this.Service);
}
else
{
diff --git a/libraries/Microsoft.Bot.Builder/ShowTypingMiddleware.cs b/libraries/Microsoft.Bot.Builder/ShowTypingMiddleware.cs
index 94b7903e10..09a80deddb 100644
--- a/libraries/Microsoft.Bot.Builder/ShowTypingMiddleware.cs
+++ b/libraries/Microsoft.Bot.Builder/ShowTypingMiddleware.cs
@@ -55,26 +55,27 @@ public ShowTypingMiddleware(int delay = 500, int period = 2000)
///
public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken)
{
- CancellationTokenSource cts = null;
- try
+ using (var cts = new CancellationTokenSource())
{
- // If the incoming activity is a MessageActivity, start a timer to periodically send the typing activity
- if (turnContext.Activity.Type == ActivityTypes.Message)
+ Task typingTask = null;
+ try
{
- cts = new CancellationTokenSource();
- cancellationToken.Register(() => cts.Cancel());
+ // If the incoming activity is a MessageActivity, start a timer to periodically send the typing activity.
+ if (turnContext.Activity.Type == ActivityTypes.Message)
+ {
+ // do not await task - we want this to run in the background and we will cancel it when its done
+ typingTask = SendTypingAsync(turnContext, _delay, _period, cts.Token);
+ }
- // do not await task - we want this to run in the background and we will cancel it when its done
- var task = Task.Run(() => SendTypingAsync(turnContext, _delay, _period, cts.Token), cancellationToken);
+ await next(cancellationToken).ConfigureAwait(false);
}
-
- await next(cancellationToken).ConfigureAwait(false);
- }
- finally
- {
- if (cts != null)
+ finally
{
- cts.Cancel();
+ if (typingTask != null && !typingTask.IsCanceled)
+ {
+ // Cancel the typing loop.
+ cts.Cancel();
+ }
}
}
}
@@ -96,7 +97,7 @@ private static async Task SendTypingAsync(ITurnContext turnContext, TimeSpan del
await Task.Delay(period, cancellationToken).ConfigureAwait(false);
}
}
- catch (TaskCanceledException)
+ catch (OperationCanceledException)
{
// do nothing
}
diff --git a/libraries/Microsoft.Bot.Builder/Streaming/BotFrameworkHttpAdapterBase.cs b/libraries/Microsoft.Bot.Builder/Streaming/BotFrameworkHttpAdapterBase.cs
index d872909f8e..d72d699be6 100644
--- a/libraries/Microsoft.Bot.Builder/Streaming/BotFrameworkHttpAdapterBase.cs
+++ b/libraries/Microsoft.Bot.Builder/Streaming/BotFrameworkHttpAdapterBase.cs
@@ -62,7 +62,9 @@ public BotFrameworkHttpAdapterBase(ICredentialProvider credentialProvider, IChan
///
/// The request handlers for this adapter.
///
+#pragma warning disable CA2227 // Collection properties should be read only (we can't change this without breaking binary compat)
protected IList RequestHandlers { get; set; } = new List();
+#pragma warning restore CA2227 // Collection properties should be read only
///
/// Primary adapter method for processing activities sent from streaming channel.
@@ -128,7 +130,7 @@ public async Task SendStreamingActivityAsync(Activity activity
// Check to see if any of this adapter's StreamingRequestHandlers is associated with this conversation.
var possibleHandlers = RequestHandlers.Where(x => x.ServiceUrl == activity.ServiceUrl).Where(y => y.HasConversation(activity.Conversation.Id));
- if (possibleHandlers.Count() > 0)
+ if (possibleHandlers.Any())
{
if (possibleHandlers.Count() > 1)
{
@@ -147,32 +149,32 @@ public async Task SendStreamingActivityAsync(Activity activity
return await possibleHandlers.First().SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
}
- else
+
+ if (ConnectedBot != null)
{
- if (ConnectedBot != null)
+ // This is a proactive message that will need a new streaming connection opened.
+ // The ServiceUrl of a streaming connection follows the pattern "urn:[ChannelName]:[Protocol]:[Host]".
+#pragma warning disable CA2000 // Dispose objects before losing scope (we can't fix this without closing the socket connection, this should be addressed after we make StreamingRequestHandler disposable and we dispose the connector )
+ var connection = new ClientWebSocket();
+#pragma warning restore CA2000 // Dispose objects before losing scope
+ var uri = activity.ServiceUrl.Split(':');
+ var protocol = uri[uri.Length - 2];
+ var host = uri[uri.Length - 1];
+ await connection.ConnectAsync(new Uri(protocol + host + "/api/messages"), cancellationToken).ConfigureAwait(false);
+
+ var handler = new StreamingRequestHandler(ConnectedBot, this, connection, Logger);
+
+ if (RequestHandlers == null)
{
- // This is a proactive message that will need a new streaming connection opened.
- // The ServiceUrl of a streaming connection follows the pattern "urn:[ChannelName]:[Protocol]:[Host]".
- var connection = new ClientWebSocket();
- var uri = activity.ServiceUrl.Split(':');
- var protocol = uri[uri.Length - 2];
- var host = uri[uri.Length - 1];
- await connection.ConnectAsync(new Uri(protocol + host + "/api/messages"), cancellationToken).ConfigureAwait(false);
-
- var handler = new StreamingRequestHandler(ConnectedBot, this, connection, Logger);
-
- if (RequestHandlers == null)
- {
- RequestHandlers = new List();
- }
-
- RequestHandlers.Add(handler);
-
- return await handler.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
+ RequestHandlers = new List();
}
- return null;
+ RequestHandlers.Add(handler);
+
+ return await handler.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
}
+
+ return null;
}
///
@@ -228,7 +230,7 @@ protected override async Task ProcessOutgoingActivityAsync(ITu
// information unique to streaming connections. Now that we know that this is a streaming
// activity, process it in the streaming pipeline.
// Process streaming activity.
- return await SendStreamingActivityAsync(activity).ConfigureAwait(false);
+ return await SendStreamingActivityAsync(activity, cancellationToken).ConfigureAwait(false);
}
///
@@ -239,7 +241,9 @@ private IConnectorClient CreateStreamingConnectorClient(Activity activity, Strea
var emptyCredentials = (ChannelProvider != null && ChannelProvider.IsGovernment()) ?
MicrosoftGovernmentAppCredentials.Empty :
MicrosoftAppCredentials.Empty;
+#pragma warning disable CA2000 // Dispose objects before losing scope (We need to make ConnectorClient disposable to fix this, ignoring it for now)
var streamingClient = new StreamingHttpClient(requestHandler, Logger);
+#pragma warning restore CA2000 // Dispose objects before losing scope
var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl), emptyCredentials, customHttpClient: streamingClient);
return connectorClient;
}
diff --git a/libraries/Microsoft.Bot.Builder/Streaming/StreamingHttpClient.cs b/libraries/Microsoft.Bot.Builder/Streaming/StreamingHttpClient.cs
index cfb151fda1..0bd42dcbb1 100644
--- a/libraries/Microsoft.Bot.Builder/Streaming/StreamingHttpClient.cs
+++ b/libraries/Microsoft.Bot.Builder/Streaming/StreamingHttpClient.cs
@@ -14,7 +14,7 @@ namespace Microsoft.Bot.Builder.Streaming
{
internal class StreamingHttpClient : HttpClient
{
- private StreamingRequestHandler _requestHandler;
+ private readonly StreamingRequestHandler _requestHandler;
private readonly ILogger _logger;
///
@@ -29,19 +29,19 @@ public StreamingHttpClient(StreamingRequestHandler requestHandler, ILogger logge
_logger = logger ?? NullLogger.Instance;
}
- public override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken = default)
+ public override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var streamingRequest = new StreamingRequest
{
- Path = request.RequestUri.OriginalString.Substring(request.RequestUri.OriginalString.IndexOf("/v3")),
+ Path = request.RequestUri.OriginalString.Substring(request.RequestUri.OriginalString.IndexOf("/v3", StringComparison.Ordinal)),
Verb = request.Method.ToString(),
};
streamingRequest.SetBody(request.Content);
- return await this.SendRequestAsync(streamingRequest, cancellationToken).ConfigureAwait(false);
+ return await SendRequestAsync(streamingRequest, cancellationToken).ConfigureAwait(false);
}
- public async Task SendAsync(StreamingRequest streamingRequest, CancellationToken cancellationToken = default) => await this._requestHandler.SendStreamingRequestAsync(streamingRequest, cancellationToken).ConfigureAwait(false);
+ public async Task SendAsync(StreamingRequest streamingRequest, CancellationToken cancellationToken = default) => await _requestHandler.SendStreamingRequestAsync(streamingRequest, cancellationToken).ConfigureAwait(false);
private async Task SendRequestAsync(StreamingRequest request, CancellationToken cancellation = default)
{
@@ -59,9 +59,11 @@ private async Task SendRequestAsync(StreamingRequest request, Cancellation
return serverResponse.ReadBodyAsJson();
}
}
+#pragma warning disable CA1031 // Do not catch general exception types (we just log the exception and continue)
catch (Exception ex)
+#pragma warning restore CA1031 // Do not catch general exception types
{
- this._logger.LogError(ex.ToString());
+ _logger.LogError(ex.ToString());
}
return default;
diff --git a/libraries/Microsoft.Bot.Builder/Streaming/StreamingRequestHandler.cs b/libraries/Microsoft.Bot.Builder/Streaming/StreamingRequestHandler.cs
index eebf4e8d29..82086ac6d6 100644
--- a/libraries/Microsoft.Bot.Builder/Streaming/StreamingRequestHandler.cs
+++ b/libraries/Microsoft.Bot.Builder/Streaming/StreamingRequestHandler.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
@@ -30,8 +31,8 @@ public class StreamingRequestHandler : RequestHandler
private readonly IStreamingActivityProcessor _activityProcessor;
private readonly string _userAgent;
private readonly IDictionary _conversations;
+ private readonly IStreamingTransportServer _server;
- private IStreamingTransportServer _server;
private bool _serverIsConnected;
///
@@ -92,7 +93,9 @@ public StreamingRequestHandler(IBot bot, IStreamingActivityProcessor activityPro
///
/// The URL of the channel endpoint this StreamingRequestHandler receives requests from.
///
+#pragma warning disable CA1056 // Uri properties should not be strings (we can't change this without breaking binary compat)
public string ServiceUrl { get; private set; }
+#pragma warning restore CA1056 // Uri properties should not be strings
///
/// Begins listening for incoming requests over this StreamingRequestHandler's server.
@@ -123,7 +126,7 @@ public bool HasConversation(string conversationId)
/// the conversation was added to this .
public DateTime ConversationAddedTime(string conversationId)
{
- if (!_conversations.TryGetValue(conversationId, out DateTime addedTime))
+ if (!_conversations.TryGetValue(conversationId, out var addedTime))
{
addedTime = DateTime.MinValue;
}
@@ -146,7 +149,7 @@ public override async Task ProcessRequestAsync(ReceiveRequest
var response = new StreamingResponse();
// We accept all POSTs regardless of path, but anything else requires special treatment.
- if (!string.Equals(request?.Verb, StreamingRequest.POST, StringComparison.InvariantCultureIgnoreCase))
+ if (!string.Equals(request?.Verb, StreamingRequest.POST, StringComparison.OrdinalIgnoreCase))
{
return HandleCustomPaths(request, response);
}
@@ -157,7 +160,9 @@ public override async Task ProcessRequestAsync(ReceiveRequest
{
body = request.ReadBodyAsString();
}
+#pragma warning disable CA1031 // Do not catch general exception types (we log the exception and continue execution)
catch (Exception ex)
+#pragma warning restore CA1031 // Do not catch general exception types
{
response.StatusCode = (int)HttpStatusCode.BadRequest;
_logger.LogError("Request body missing or malformed: " + ex.Message);
@@ -225,7 +230,9 @@ public override async Task ProcessRequestAsync(ReceiveRequest
}
}
}
+#pragma warning disable CA1031 // Do not catch general exception types (we logging the error and we send it back in the body of the response)
catch (Exception ex)
+#pragma warning restore CA1031 // Do not catch general exception types
{
response.StatusCode = (int)HttpStatusCode.InternalServerError;
response.SetBody(ex.ToString());
@@ -279,7 +286,9 @@ public async Task SendActivityAsync(Activity activity, Cancell
return serverResponse.ReadBodyAsJson();
}
}
+#pragma warning disable CA1031 // Do not catch general exception types (this should probably be addressed later, but for now we just log the error and continue the execution)
catch (Exception ex)
+#pragma warning restore CA1031 // Do not catch general exception types
{
_logger.LogError(ex.Message);
}
@@ -309,7 +318,9 @@ public async Task SendStreamingRequestAsync(StreamingRequest re
return serverResponse.ReadBodyAsJson();
}
}
+#pragma warning disable CA1031 // Do not catch general exception types (this should probably be addressed later, but for now we just log the error and continue the execution)
catch (Exception ex)
+#pragma warning restore CA1031 // Do not catch general exception types
{
_logger.LogError(ex.Message);
}
@@ -327,15 +338,21 @@ public async Task SendStreamingRequestAsync(StreamingRequest re
/// https://github.com/Microsoft/botbuilder-dotnet/blob/d342cd66d159a023ac435aec0fdf791f93118f5f/doc/UserAgents.md.
///
/// A string containing versioning information.
- private static string GetUserAgent() =>
- string.Format(
- "Microsoft-BotFramework/3.1 Streaming-Extensions/1.0 BotBuilder/{0} ({1}; {2}; {3})",
- ConnectorClient.GetClientVersion(new ConnectorClient(new Uri("http://localhost"))),
- ConnectorClient.GetASPNetVersion(),
- ConnectorClient.GetOsVersion(),
- ConnectorClient.GetArchitecture());
-
- private IEnumerable UpdateAttachmentStreams(Activity activity)
+ private static string GetUserAgent()
+ {
+ using (var connectorClient = new ConnectorClient(new Uri("http://localhost")))
+ {
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ "Microsoft-BotFramework/3.1 Streaming-Extensions/1.0 BotBuilder/{0} ({1}; {2}; {3})",
+ ConnectorClient.GetClientVersion(connectorClient),
+ ConnectorClient.GetASPNetVersion(),
+ ConnectorClient.GetOsVersion(),
+ ConnectorClient.GetArchitecture());
+ }
+ }
+
+ private static IEnumerable UpdateAttachmentStreams(Activity activity)
{
if (activity == null || activity.Attachments == null)
{
@@ -379,8 +396,8 @@ private StreamingResponse HandleCustomPaths(ReceiveRequest request, StreamingRes
return response;
}
- if (string.Equals(request.Verb, StreamingRequest.GET, StringComparison.InvariantCultureIgnoreCase) &&
- string.Equals(request.Path, "/api/version", StringComparison.InvariantCultureIgnoreCase))
+ if (string.Equals(request.Verb, StreamingRequest.GET, StringComparison.OrdinalIgnoreCase) &&
+ string.Equals(request.Path, "/api/version", StringComparison.OrdinalIgnoreCase))
{
response.StatusCode = (int)HttpStatusCode.OK;
response.SetBody(new VersionInfo() { UserAgent = _userAgent });
diff --git a/libraries/Microsoft.Bot.Builder/Teams/TeamsInfo.cs b/libraries/Microsoft.Bot.Builder/Teams/TeamsInfo.cs
index b362f3b93b..72836e47b7 100644
--- a/libraries/Microsoft.Bot.Builder/Teams/TeamsInfo.cs
+++ b/libraries/Microsoft.Bot.Builder/Teams/TeamsInfo.cs
@@ -20,13 +20,17 @@ public static class TeamsInfo
public static async Task GetTeamDetailsAsync(ITurnContext turnContext, string teamId = null, CancellationToken cancellationToken = default)
{
var t = teamId ?? turnContext.Activity.TeamsGetTeamInfo()?.Id ?? throw new InvalidOperationException("This method is only valid within the scope of MS Teams Team.");
+#pragma warning disable CA2000 // Dispose objects before losing scope (we need to review this, disposing the connectorClient may have unintended consequences)
return await GetTeamsConnectorClient(turnContext).Teams.FetchTeamDetailsAsync(t, cancellationToken).ConfigureAwait(false);
+#pragma warning restore CA2000 // Dispose objects before losing scope
}
public static async Task> GetTeamChannelsAsync(ITurnContext turnContext, string teamId = null, CancellationToken cancellationToken = default)
{
var t = teamId ?? turnContext.Activity.TeamsGetTeamInfo()?.Id ?? throw new InvalidOperationException("This method is only valid within the scope of MS Teams Team.");
+#pragma warning disable CA2000 // Dispose objects before losing scope (we need to review this, disposing the connectorClient may have unintended consequences)
var channelList = await GetTeamsConnectorClient(turnContext).Teams.FetchChannelListAsync(t, cancellationToken).ConfigureAwait(false);
+#pragma warning restore CA2000 // Dispose objects before losing scope
return channelList.Conversations;
}
@@ -102,7 +106,7 @@ public static async Task> SendMessageToTeam
if (turnContext.Activity == null)
{
- throw new ArgumentNullException(nameof(turnContext.Activity));
+ throw new InvalidOperationException(nameof(turnContext.Activity));
}
if (string.IsNullOrEmpty(teamsChannelId))
diff --git a/libraries/Microsoft.Bot.Builder/TelemetryLoggerMiddleware.cs b/libraries/Microsoft.Bot.Builder/TelemetryLoggerMiddleware.cs
index e10020c334..584b879f4a 100644
--- a/libraries/Microsoft.Bot.Builder/TelemetryLoggerMiddleware.cs
+++ b/libraries/Microsoft.Bot.Builder/TelemetryLoggerMiddleware.cs
@@ -324,7 +324,9 @@ protected Task> FillUpdateEventPropertiesAsync(Activi
/// The Activity object deleted by bot.
/// Additional properties to add to the event.
/// The properties and their values to log when the bot deletes a message it sent previously.
+#pragma warning disable CA1822 // Mark members as static (can't change this without breaking binary compat)
protected Task> FillDeleteEventPropertiesAsync(IMessageDeleteActivity activity, Dictionary additionalProperties = null)
+#pragma warning restore CA1822 // Mark members as static
{
var properties = new Dictionary()
{
diff --git a/libraries/Microsoft.Bot.Builder/TokenResolver.cs b/libraries/Microsoft.Bot.Builder/TokenResolver.cs
index 23ea3a2809..9f62c9fbfb 100644
--- a/libraries/Microsoft.Bot.Builder/TokenResolver.cs
+++ b/libraries/Microsoft.Bot.Builder/TokenResolver.cs
@@ -13,7 +13,6 @@
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
-using Newtonsoft.Json.Linq;
namespace Microsoft.Bot.Builder
{
@@ -23,69 +22,63 @@ internal static class TokenResolver
public static void CheckForOAuthCards(BotFrameworkAdapter adapter, ILogger logger, ITurnContext turnContext, Activity activity, CancellationToken cancellationToken)
{
- if (activity == null || activity.Attachments == null)
+ if (activity?.Attachments == null)
{
return;
}
+ var pollTokenTasks = new List();
foreach (var attachment in activity.Attachments.Where(a => a.ContentType == OAuthCard.ContentType))
{
- OAuthCard oauthCard = attachment.Content as OAuthCard;
- if (oauthCard != null)
+ if (attachment.Content is OAuthCard oauthCard)
{
if (string.IsNullOrWhiteSpace(oauthCard.ConnectionName))
{
throw new InvalidOperationException("The OAuthPrompt's ConnectionName property is missing a value.");
}
- // Poll as a background task
- Task.Run(() => PollForTokenAsync(adapter, logger, turnContext, activity, oauthCard.ConnectionName, cancellationToken))
- .ContinueWith(t =>
- {
- if (t.Exception != null)
- {
- logger.LogError(t.Exception.InnerException ?? t.Exception, "PollForTokenAsync threw an exception", oauthCard.ConnectionName);
- }
- });
+ // Poll as a background task and add to the list (we don't call await here, we await all the calls together later).
+ pollTokenTasks.Add(PollForTokenAsync(adapter, logger, turnContext, oauthCard.ConnectionName, cancellationToken));
}
}
+
+ if (pollTokenTasks.Any())
+ {
+ // Wait for all the poll operations to complete.
+ Task.WaitAll(pollTokenTasks.ToArray());
+ }
}
- private static async Task PollForTokenAsync(BotFrameworkAdapter adapter, ILogger logger, ITurnContext turnContext, Activity activity, string connectionName, CancellationToken cancellationToken)
+ private static async Task PollForTokenAsync(BotFrameworkAdapter adapter, ILogger logger, ITurnContext turnContext, string connectionName, CancellationToken cancellationToken)
{
- TokenResponse tokenResponse = null;
- bool shouldEndPolling = false;
- var pollingTimeout = TurnStateConstants.OAuthLoginTimeoutValue;
- var pollingRequestsInterval = PollingInterval;
- var loginTimeout = turnContext.TurnState.Get(TurnStateConstants.OAuthLoginTimeoutKey);
- bool sentToken = false;
-
- // Override login timeout with value set from the OAuthPrompt or by the developer
- if (turnContext.TurnState.ContainsKey(TurnStateConstants.OAuthLoginTimeoutKey))
+ try
{
- pollingTimeout = (TimeSpan)turnContext.TurnState.Get(TurnStateConstants.OAuthLoginTimeoutKey);
- }
+ var shouldEndPolling = false;
+ var pollingTimeout = TurnStateConstants.OAuthLoginTimeoutValue;
+ var pollingRequestsInterval = PollingInterval;
+ var sentToken = false;
- var stopwatch = Stopwatch.StartNew();
- var oauthClient = turnContext.TurnState.Get();
+ // Override login timeout with value set from the OAuthPrompt or by the developer
+ if (turnContext.TurnState.ContainsKey(TurnStateConstants.OAuthLoginTimeoutKey))
+ {
+ pollingTimeout = (TimeSpan)turnContext.TurnState.Get(TurnStateConstants.OAuthLoginTimeoutKey);
+ }
- while (stopwatch.Elapsed < pollingTimeout && !shouldEndPolling)
- {
- tokenResponse = await adapter.GetUserTokenAsync(turnContext, oauthClient?.Credentials as AppCredentials, connectionName, null, cancellationToken).ConfigureAwait(false);
+ var stopwatch = Stopwatch.StartNew();
+ var oauthClient = turnContext.TurnState.Get();
- if (tokenResponse != null)
+ while (stopwatch.Elapsed < pollingTimeout && !shouldEndPolling)
{
- // This can be used to short-circuit the polling loop.
- if (tokenResponse.Properties != null)
- {
- JToken tokenPollingSettingsToken = null;
- TokenPollingSettings tokenPollingSettings = null;
- tokenResponse.Properties.TryGetValue(TurnStateConstants.TokenPollingSettingsKey, out tokenPollingSettingsToken);
+ var tokenResponse = await adapter.GetUserTokenAsync(turnContext, oauthClient?.Credentials as AppCredentials, connectionName, null, cancellationToken).ConfigureAwait(false);
- if (tokenPollingSettingsToken != null)
+ if (tokenResponse != null)
+ {
+ // This can be used to short-circuit the polling loop.
+ if (tokenResponse.Properties != null)
{
- tokenPollingSettings = tokenPollingSettingsToken.ToObject();
+ tokenResponse.Properties.TryGetValue(TurnStateConstants.TokenPollingSettingsKey, out var tokenPollingSettingsToken);
+ var tokenPollingSettings = tokenPollingSettingsToken?.ToObject();
if (tokenPollingSettings != null)
{
logger.LogInformation($"PollForTokenAsync received new polling settings: timeout={tokenPollingSettings.Timeout}, interval={tokenPollingSettings.Interval}", tokenPollingSettings);
@@ -93,34 +86,40 @@ private static async Task PollForTokenAsync(BotFrameworkAdapter adapter, ILogger
pollingRequestsInterval = tokenPollingSettings.Interval > 0 ? TimeSpan.FromMilliseconds(tokenPollingSettings.Interval) : pollingRequestsInterval; // Only overrides if it is set.
}
}
+
+ // once there is a token, send it to the bot and stop polling
+ if (tokenResponse.Token != null)
+ {
+ var tokenResponseActivityEvent = CreateTokenResponse(turnContext.Activity.GetConversationReference(), tokenResponse.Token, connectionName);
+ var identity = turnContext.TurnState.Get(BotAdapter.BotIdentityKey) as ClaimsIdentity;
+ var callback = turnContext.TurnState.Get();
+ await adapter.ProcessActivityAsync(identity, tokenResponseActivityEvent, callback, cancellationToken).ConfigureAwait(false);
+ shouldEndPolling = true;
+ sentToken = true;
+
+ logger.LogInformation("PollForTokenAsync completed with a token", turnContext.Activity);
+ }
}
- // once there is a token, send it to the bot and stop polling
- if (tokenResponse.Token != null)
+ if (!shouldEndPolling)
{
- var tokenResponseActivityEvent = CreateTokenResponse(turnContext.Activity.GetConversationReference(), tokenResponse.Token, connectionName);
- var identity = turnContext.TurnState.Get(BotFrameworkAdapter.BotIdentityKey) as ClaimsIdentity;
- var callback = turnContext.TurnState.Get();
- await adapter.ProcessActivityAsync(identity, tokenResponseActivityEvent, callback, cancellationToken).ConfigureAwait(false);
- shouldEndPolling = true;
- sentToken = true;
-
- logger.LogInformation("PollForTokenAsync completed with a token", turnContext.Activity);
+ await Task.Delay(pollingRequestsInterval, cancellationToken).ConfigureAwait(false);
}
}
- if (!shouldEndPolling)
+ if (!sentToken)
{
- await Task.Delay(pollingRequestsInterval).ConfigureAwait(false);
+ logger.LogInformation("PollForTokenAsync completed without receiving a token", turnContext.Activity);
}
- }
- if (!sentToken)
+ stopwatch.Stop();
+ }
+#pragma warning disable CA1031 // Do not catch general exception types (for new we just log the exception and continue)
+ catch (Exception ex)
+#pragma warning restore CA1031 // Do not catch general exception types
{
- logger.LogInformation("PollForTokenAsync completed without receiving a token", turnContext.Activity);
+ logger.LogError(ex, "PollForTokenAsync threw an exception", connectionName);
}
-
- stopwatch.Stop();
}
private static Activity CreateTokenResponse(ConversationReference relatesTo, string token, string connectionName)
diff --git a/libraries/Microsoft.Bot.Builder/TraceTranscriptLogger.cs b/libraries/Microsoft.Bot.Builder/TraceTranscriptLogger.cs
index 7a2d6188d6..ea857ee828 100644
--- a/libraries/Microsoft.Bot.Builder/TraceTranscriptLogger.cs
+++ b/libraries/Microsoft.Bot.Builder/TraceTranscriptLogger.cs
@@ -13,9 +13,9 @@ namespace Microsoft.Bot.Builder
///
public class TraceTranscriptLogger : ITranscriptLogger
{
- private static JsonSerializerSettings serializationSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.Indented };
+ private static readonly JsonSerializerSettings _serializationSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.Indented };
- private bool traceActivity;
+ private readonly bool _traceActivity;
public TraceTranscriptLogger()
: this(true)
@@ -24,7 +24,7 @@ public TraceTranscriptLogger()
public TraceTranscriptLogger(bool traceActivity)
{
- this.traceActivity = traceActivity;
+ this._traceActivity = traceActivity;
}
///
@@ -35,9 +35,9 @@ public TraceTranscriptLogger(bool traceActivity)
public Task LogActivityAsync(IActivity activity)
{
BotAssert.ActivityNotNull(activity);
- if (traceActivity)
+ if (_traceActivity)
{
- Trace.TraceInformation(JsonConvert.SerializeObject(activity, serializationSettings));
+ Trace.TraceInformation(JsonConvert.SerializeObject(activity, _serializationSettings));
}
else
{
diff --git a/libraries/Microsoft.Bot.Builder/TranscriptLoggerMiddleware.cs b/libraries/Microsoft.Bot.Builder/TranscriptLoggerMiddleware.cs
index b853d64851..dc9184d421 100644
--- a/libraries/Microsoft.Bot.Builder/TranscriptLoggerMiddleware.cs
+++ b/libraries/Microsoft.Bot.Builder/TranscriptLoggerMiddleware.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Schema;
@@ -16,8 +17,8 @@ namespace Microsoft.Bot.Builder
///
public class TranscriptLoggerMiddleware : IMiddleware
{
- private static JsonSerializerSettings _jsonSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore };
- private ITranscriptLogger logger;
+ private static readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore };
+ private readonly ITranscriptLogger _logger;
///
/// Initializes a new instance of the class.
@@ -25,7 +26,7 @@ public class TranscriptLoggerMiddleware : IMiddleware
/// The conversation store to use.
public TranscriptLoggerMiddleware(ITranscriptLogger transcriptLogger)
{
- logger = transcriptLogger ?? throw new ArgumentNullException("TranscriptLoggerMiddleware requires a ITranscriptLogger implementation. ");
+ _logger = transcriptLogger ?? throw new ArgumentNullException(nameof(transcriptLogger), "TranscriptLoggerMiddleware requires a ITranscriptLogger implementation. ");
}
///
@@ -108,26 +109,34 @@ public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate nextTurn, C
await nextTurn(cancellationToken).ConfigureAwait(false);
// flush transcript at end of turn
+ var logTasks = new List();
while (transcript.Count > 0)
{
+ // Process the queue and log all the activities in parallel.
var activity = transcript.Dequeue();
- // As we are deliberately not using await, disable the associated warning.
-#pragma warning disable 4014
- logger.LogActivityAsync(activity).ContinueWith(
- task =>
- {
- try
- {
- task.Wait();
- }
- catch (Exception err)
- {
- Trace.TraceError($"Transcript logActivity failed with {err}");
- }
- },
- cancellationToken);
-#pragma warning restore 4014
+ // Add the logging task to the list (we don't call await here, we await all the calls together later).
+ logTasks.Add(TryLogActivityAsync(_logger, activity));
+ }
+
+ if (logTasks.Any())
+ {
+ // Wait for all the activities to be logged before continuing.
+ await Task.WhenAll(logTasks).ConfigureAwait(false);
+ }
+ }
+
+ private static async Task TryLogActivityAsync(ITranscriptLogger logger, IActivity activity)
+ {
+ try
+ {
+ await logger.LogActivityAsync(activity).ConfigureAwait(false);
+ }
+#pragma warning disable CA1031 // Do not catch general exception types (this should probably be addressed later, but for now we just log the error and continue the execution)
+ catch (Exception ex)
+#pragma warning restore CA2008 // Do not create tasks without passing a TaskScheduler
+ {
+ Trace.TraceError($"Transcript logActivity failed with {ex}");
}
}
@@ -145,7 +154,7 @@ private static IActivity EnsureActivityHasId(IActivity activity)
if (activity == null)
{
- throw new ArgumentNullException("Cannot check or add Id on a null Activity.");
+ throw new ArgumentNullException(nameof(activity), "Cannot check or add Id on a null Activity.");
}
if (activity.Id == null)
@@ -157,7 +166,7 @@ private static IActivity EnsureActivityHasId(IActivity activity)
return activityWithId;
}
- private void LogActivity(Queue transcript, IActivity activity)
+ private static void LogActivity(Queue transcript, IActivity activity)
{
if (activity.Timestamp == null)
{
diff --git a/libraries/Microsoft.Bot.Builder/TurnContext.cs b/libraries/Microsoft.Bot.Builder/TurnContext.cs
index f4709d5674..b353e8596a 100644
--- a/libraries/Microsoft.Bot.Builder/TurnContext.cs
+++ b/libraries/Microsoft.Bot.Builder/TurnContext.cs
@@ -401,6 +401,16 @@ async Task ActuallyDeleteStuff()
///
public void Dispose()
{
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ // Dispose any disposable objects owned by the class here.
+ }
}
private async Task UpdateActivityInternalAsync(
@@ -412,11 +422,11 @@ private async Task UpdateActivityInternalAsync(
BotAssert.ActivityNotNull(activity);
if (updateHandlers == null)
{
- throw new ArgumentException(nameof(updateHandlers));
+ throw new ArgumentException($"{nameof(updateHandlers)} is null.", nameof(updateHandlers));
}
// No middleware to run.
- if (updateHandlers.Count() == 0)
+ if (!updateHandlers.Any())
{
if (callAtBottom != null)
{
@@ -452,11 +462,11 @@ private async Task DeleteActivityInternalAsync(
if (deleteHandlers == null)
{
- throw new ArgumentException(nameof(deleteHandlers));
+ throw new ArgumentException($"{nameof(deleteHandlers)} is null", nameof(deleteHandlers));
}
// No middleware to run.
- if (deleteHandlers.Count() == 0)
+ if (!deleteHandlers.Any())
{
if (callAtBottom != null)
{
diff --git a/libraries/Microsoft.Bot.Builder/TurnContextStateCollection.cs b/libraries/Microsoft.Bot.Builder/TurnContextStateCollection.cs
index e977803b45..e69b3d1bce 100644
--- a/libraries/Microsoft.Bot.Builder/TurnContextStateCollection.cs
+++ b/libraries/Microsoft.Bot.Builder/TurnContextStateCollection.cs
@@ -133,6 +133,16 @@ public void Set(T value)
public void Dispose()
{
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ // Dispose any disposable objects owned by the class here.
+ }
}
}
}
diff --git a/libraries/Microsoft.Bot.Builder/UserState.cs b/libraries/Microsoft.Bot.Builder/UserState.cs
index 156c698fc2..6733a89e25 100644
--- a/libraries/Microsoft.Bot.Builder/UserState.cs
+++ b/libraries/Microsoft.Bot.Builder/UserState.cs
@@ -37,8 +37,8 @@ public UserState(IStorage storage)
/// is missing.
protected override string GetStorageKey(ITurnContext turnContext)
{
- var channelId = turnContext.Activity.ChannelId ?? throw new ArgumentNullException("invalid activity-missing channelId");
- var userId = turnContext.Activity.From?.Id ?? throw new ArgumentNullException("invalid activity-missing From.Id");
+ var channelId = turnContext.Activity.ChannelId ?? throw new InvalidOperationException("invalid activity-missing channelId");
+ var userId = turnContext.Activity.From?.Id ?? throw new InvalidOperationException("invalid activity-missing From.Id");
return $"{channelId}/users/{userId}";
}
}
diff --git a/libraries/Microsoft.Bot.Configuration/Microsoft.Bot.Configuration.csproj b/libraries/Microsoft.Bot.Configuration/Microsoft.Bot.Configuration.csproj
index 08f2f8c32a..32fe7a885f 100644
--- a/libraries/Microsoft.Bot.Configuration/Microsoft.Bot.Configuration.csproj
+++ b/libraries/Microsoft.Bot.Configuration/Microsoft.Bot.Configuration.csproj
@@ -23,7 +23,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Connector/Authentication/ChannelValidation.cs b/libraries/Microsoft.Bot.Connector/Authentication/ChannelValidation.cs
index 138ed4c9cc..d8f3b4079e 100644
--- a/libraries/Microsoft.Bot.Connector/Authentication/ChannelValidation.cs
+++ b/libraries/Microsoft.Bot.Connector/Authentication/ChannelValidation.cs
@@ -54,7 +54,9 @@ public static class ChannelValidation
///
/// A valid ClaimsIdentity.
///
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateChannelToken(string authHeader, ICredentialProvider credentials, HttpClient httpClient, string channelId)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
return await AuthenticateChannelToken(authHeader, credentials, httpClient, channelId, new AuthenticationConfiguration()).ConfigureAwait(false);
}
@@ -75,7 +77,9 @@ public static async Task AuthenticateChannelToken(string authHea
///
/// A valid ClaimsIdentity.
///
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateChannelToken(string authHeader, ICredentialProvider credentials, HttpClient httpClient, string channelId, AuthenticationConfiguration authConfig)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (authConfig == null)
{
@@ -145,7 +149,9 @@ public static async Task AuthenticateChannelToken(string authHea
/// setup and teardown, so a shared HttpClient is recommended.
/// The ID of the channel to validate.
/// ClaimsIdentity.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateChannelToken(string authHeader, ICredentialProvider credentials, string serviceUrl, HttpClient httpClient, string channelId)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
return await AuthenticateChannelToken(authHeader, credentials, serviceUrl, httpClient, channelId, new AuthenticationConfiguration()).ConfigureAwait(false);
}
@@ -162,7 +168,9 @@ public static async Task AuthenticateChannelToken(string authHea
/// The ID of the channel to validate.
/// The authentication configuration.
/// ClaimsIdentity.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateChannelToken(string authHeader, ICredentialProvider credentials, string serviceUrl, HttpClient httpClient, string channelId, AuthenticationConfiguration authConfig)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (authConfig == null)
{
diff --git a/libraries/Microsoft.Bot.Connector/Authentication/EmulatorValidation.cs b/libraries/Microsoft.Bot.Connector/Authentication/EmulatorValidation.cs
index 32adad58b3..56063886d4 100644
--- a/libraries/Microsoft.Bot.Connector/Authentication/EmulatorValidation.cs
+++ b/libraries/Microsoft.Bot.Connector/Authentication/EmulatorValidation.cs
@@ -92,7 +92,9 @@ public static bool IsTokenFromEmulator(string authHeader)
///
/// A token issued by the Bot Framework will FAIL this check. Only Emulator tokens will pass.
///
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateEmulatorToken(string authHeader, ICredentialProvider credentials, IChannelProvider channelProvider, HttpClient httpClient, string channelId)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
return await AuthenticateEmulatorToken(authHeader, credentials, channelProvider, httpClient, channelId, new AuthenticationConfiguration()).ConfigureAwait(false);
}
@@ -114,7 +116,9 @@ public static async Task AuthenticateEmulatorToken(string authHe
///
/// A token issued by the Bot Framework will FAIL this check. Only Emulator tokens will pass.
///
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateEmulatorToken(string authHeader, ICredentialProvider credentials, IChannelProvider channelProvider, HttpClient httpClient, string channelId, AuthenticationConfiguration authConfig)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (authConfig == null)
{
diff --git a/libraries/Microsoft.Bot.Connector/Authentication/EnterpriseChannelValidation.cs b/libraries/Microsoft.Bot.Connector/Authentication/EnterpriseChannelValidation.cs
index b6492a0c46..1beb9bd5d3 100644
--- a/libraries/Microsoft.Bot.Connector/Authentication/EnterpriseChannelValidation.cs
+++ b/libraries/Microsoft.Bot.Connector/Authentication/EnterpriseChannelValidation.cs
@@ -42,7 +42,9 @@ public sealed class EnterpriseChannelValidation
/// setup and teardown, so a shared HttpClient is recommended.
/// The ID of the channel to validate.
/// ClaimsIdentity.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateChannelToken(string authHeader, ICredentialProvider credentials, IChannelProvider channelProvider, string serviceUrl, HttpClient httpClient, string channelId)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
return await AuthenticateChannelToken(authHeader, credentials, channelProvider, serviceUrl, httpClient, channelId, new AuthenticationConfiguration()).ConfigureAwait(false);
}
@@ -60,7 +62,9 @@ public static async Task AuthenticateChannelToken(string authHea
/// The ID of the channel to validate.
/// The authentication configuration.
/// ClaimsIdentity.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateChannelToken(string authHeader, ICredentialProvider credentials, IChannelProvider channelProvider, string serviceUrl, HttpClient httpClient, string channelId, AuthenticationConfiguration authConfig)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (authConfig == null)
{
@@ -82,7 +86,9 @@ public static async Task AuthenticateChannelToken(string authHea
return identity;
}
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task ValidateIdentity(ClaimsIdentity identity, ICredentialProvider credentials, string serviceUrl)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (identity == null)
{
diff --git a/libraries/Microsoft.Bot.Connector/Authentication/GovernmentChannelValidation.cs b/libraries/Microsoft.Bot.Connector/Authentication/GovernmentChannelValidation.cs
index a7e0da3777..0fc9fe9215 100644
--- a/libraries/Microsoft.Bot.Connector/Authentication/GovernmentChannelValidation.cs
+++ b/libraries/Microsoft.Bot.Connector/Authentication/GovernmentChannelValidation.cs
@@ -44,7 +44,9 @@ public sealed class GovernmentChannelValidation
/// setup and teardown, so a shared HttpClient is recommended.
/// The ID of the channel to validate.
/// ClaimsIdentity.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateChannelToken(string authHeader, ICredentialProvider credentials, string serviceUrl, HttpClient httpClient, string channelId)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
return await AuthenticateChannelToken(authHeader, credentials, serviceUrl, httpClient, channelId, new AuthenticationConfiguration()).ConfigureAwait(false);
}
@@ -61,7 +63,9 @@ public static async Task AuthenticateChannelToken(string authHea
/// The ID of the channel to validate.
/// The authentication configuration.
/// ClaimsIdentity.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateChannelToken(string authHeader, ICredentialProvider credentials, string serviceUrl, HttpClient httpClient, string channelId, AuthenticationConfiguration authConfig)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (authConfig == null)
{
@@ -88,7 +92,9 @@ public static async Task AuthenticateChannelToken(string authHea
/// The user defined set of valid credentials, such as the AppId.
/// The service url from the request.
/// A representing the asynchronous operation.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task ValidateIdentity(ClaimsIdentity identity, ICredentialProvider credentials, string serviceUrl)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (identity == null)
{
diff --git a/libraries/Microsoft.Bot.Connector/Authentication/JwtTokenValidation.cs b/libraries/Microsoft.Bot.Connector/Authentication/JwtTokenValidation.cs
index fa22135d94..4793db2a25 100644
--- a/libraries/Microsoft.Bot.Connector/Authentication/JwtTokenValidation.cs
+++ b/libraries/Microsoft.Bot.Connector/Authentication/JwtTokenValidation.cs
@@ -30,7 +30,9 @@ public static class JwtTokenValidation
/// A task that represents the work queued to execute.
/// If the task completes successfully, the result contains the claims-based
/// identity for the request.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateRequest(IActivity activity, string authHeader, ICredentialProvider credentials, IChannelProvider provider, HttpClient httpClient = null)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
return await AuthenticateRequest(activity, authHeader, credentials, provider, new AuthenticationConfiguration(), httpClient).ConfigureAwait(false);
}
@@ -48,7 +50,9 @@ public static async Task AuthenticateRequest(IActivity activity,
/// A task that represents the work queued to execute.
/// If the task completes successfully, the result contains the claims-based
/// identity for the request.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateRequest(IActivity activity, string authHeader, ICredentialProvider credentials, IChannelProvider provider, AuthenticationConfiguration authConfig, HttpClient httpClient = null)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (authConfig == null)
{
@@ -89,7 +93,9 @@ public static async Task AuthenticateRequest(IActivity activity,
/// A task that represents the work queued to execute.
/// If the task completes successfully, the result contains the claims-based
/// identity for the request.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task ValidateAuthHeader(string authHeader, ICredentialProvider credentials, IChannelProvider channelProvider, string channelId, string serviceUrl = null, HttpClient httpClient = null)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
return await ValidateAuthHeader(authHeader, credentials, channelProvider, channelId, new AuthenticationConfiguration(), serviceUrl, httpClient).ConfigureAwait(false);
}
@@ -107,7 +113,9 @@ public static async Task ValidateAuthHeader(string authHeader, I
/// A task that represents the work queued to execute.
/// If the task completes successfully, the result contains the claims-based
/// identity for the request.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task ValidateAuthHeader(string authHeader, ICredentialProvider credentials, IChannelProvider channelProvider, string channelId, AuthenticationConfiguration authConfig, string serviceUrl = null, HttpClient httpClient = null)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (string.IsNullOrEmpty(authHeader))
{
@@ -121,7 +129,7 @@ public static async Task ValidateAuthHeader(string authHeader, I
httpClient = httpClient ?? _httpClient;
- var identity = await AuthenticateToken(authHeader, credentials, channelProvider, channelId, authConfig, serviceUrl, httpClient).ConfigureAwait(false);
+ var identity = await AuthenticateTokenAsync(authHeader, credentials, channelProvider, channelId, authConfig, serviceUrl, httpClient).ConfigureAwait(false);
await ValidateClaimsAsync(authConfig, identity.Claims).ConfigureAwait(false);
@@ -210,7 +218,7 @@ internal static bool IsValidTokenFormat(string authHeader)
// [0] = "Bearer"
// [1] = "[Big Long String]"
var authScheme = parts[0];
- if (!authScheme.Equals("Bearer", StringComparison.InvariantCultureIgnoreCase))
+ if (!authScheme.Equals("Bearer", StringComparison.OrdinalIgnoreCase))
{
// The scheme MUST be "Bearer"
return false;
@@ -222,7 +230,7 @@ internal static bool IsValidTokenFormat(string authHeader)
///
/// Authenticates the auth header token from the request.
///
- private static async Task AuthenticateToken(string authHeader, ICredentialProvider credentials, IChannelProvider channelProvider, string channelId, AuthenticationConfiguration authConfig, string serviceUrl, HttpClient httpClient)
+ private static async Task AuthenticateTokenAsync(string authHeader, ICredentialProvider credentials, IChannelProvider channelProvider, string channelId, AuthenticationConfiguration authConfig, string serviceUrl, HttpClient httpClient)
{
if (SkillValidation.IsSkillToken(authHeader))
{
diff --git a/libraries/Microsoft.Bot.Connector/Authentication/Retry.cs b/libraries/Microsoft.Bot.Connector/Authentication/Retry.cs
index 30d0a29315..c008e2783a 100644
--- a/libraries/Microsoft.Bot.Connector/Authentication/Retry.cs
+++ b/libraries/Microsoft.Bot.Connector/Authentication/Retry.cs
@@ -9,7 +9,9 @@ namespace Microsoft.Bot.Connector.Authentication
{
public static class Retry
{
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task Run(Func> task, Func retryExceptionHandler)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
RetryParams retry;
var exceptions = new List();
diff --git a/libraries/Microsoft.Bot.Connector/Authentication/SimpleChannelProvider.cs b/libraries/Microsoft.Bot.Connector/Authentication/SimpleChannelProvider.cs
index 146972f311..dfd93956f1 100644
--- a/libraries/Microsoft.Bot.Connector/Authentication/SimpleChannelProvider.cs
+++ b/libraries/Microsoft.Bot.Connector/Authentication/SimpleChannelProvider.cs
@@ -42,7 +42,7 @@ public Task GetChannelServiceAsync()
/// True if this channel provider represents a channel on US Government Azure.
public bool IsGovernment()
{
- return string.Equals(GovernmentAuthenticationConstants.ChannelService, ChannelService, StringComparison.InvariantCultureIgnoreCase);
+ return string.Equals(GovernmentAuthenticationConstants.ChannelService, ChannelService, StringComparison.OrdinalIgnoreCase);
}
///
diff --git a/libraries/Microsoft.Bot.Connector/Authentication/SkillValidation.cs b/libraries/Microsoft.Bot.Connector/Authentication/SkillValidation.cs
index 01b5e1c95f..0554bc4a04 100644
--- a/libraries/Microsoft.Bot.Connector/Authentication/SkillValidation.cs
+++ b/libraries/Microsoft.Bot.Connector/Authentication/SkillValidation.cs
@@ -94,7 +94,7 @@ public static bool IsSkillClaim(IEnumerable claims)
}
var audience = claimsList.FirstOrDefault(claim => claim.Type == AuthenticationConstants.AudienceClaim)?.Value;
- if (string.IsNullOrWhiteSpace(audience) || AuthenticationConstants.ToBotFromChannelTokenIssuer.Equals(audience, StringComparison.InvariantCulture))
+ if (string.IsNullOrWhiteSpace(audience) || AuthenticationConstants.ToBotFromChannelTokenIssuer.Equals(audience, StringComparison.OrdinalIgnoreCase))
{
// The audience is https://api.botframework.com and not an appId.
return false;
@@ -124,7 +124,9 @@ public static bool IsSkillClaim(IEnumerable claims)
/// The ID of the channel to validate.
/// The authentication configuration.
/// A instance if the validation is successful.
+#pragma warning disable UseAsyncSuffix // Use Async suffix (can't change this without breaking binary compat)
public static async Task AuthenticateChannelToken(string authHeader, ICredentialProvider credentials, IChannelProvider channelProvider, HttpClient httpClient, string channelId, AuthenticationConfiguration authConfig)
+#pragma warning restore UseAsyncSuffix // Use Async suffix
{
if (authConfig == null)
{
diff --git a/libraries/Microsoft.Bot.Connector/Microsoft.Bot.Connector.csproj b/libraries/Microsoft.Bot.Connector/Microsoft.Bot.Connector.csproj
index 80c84348cd..99d47a20b3 100644
--- a/libraries/Microsoft.Bot.Connector/Microsoft.Bot.Connector.csproj
+++ b/libraries/Microsoft.Bot.Connector/Microsoft.Bot.Connector.csproj
@@ -24,7 +24,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
@@ -38,6 +39,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/libraries/Microsoft.Bot.Schema/Microsoft.Bot.Schema.csproj b/libraries/Microsoft.Bot.Schema/Microsoft.Bot.Schema.csproj
index 524545ffc6..9766586e12 100644
--- a/libraries/Microsoft.Bot.Schema/Microsoft.Bot.Schema.csproj
+++ b/libraries/Microsoft.Bot.Schema/Microsoft.Bot.Schema.csproj
@@ -23,10 +23,15 @@
- $(NoWarn);CS1573;CS1591
+
+ $(NoWarn);CS1573;CS1591;SX1309
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/libraries/Microsoft.Bot.Streaming/Microsoft.Bot.Streaming.csproj b/libraries/Microsoft.Bot.Streaming/Microsoft.Bot.Streaming.csproj
index d3396b097a..041ca2d0c0 100644
--- a/libraries/Microsoft.Bot.Streaming/Microsoft.Bot.Streaming.csproj
+++ b/libraries/Microsoft.Bot.Streaming/Microsoft.Bot.Streaming.csproj
@@ -25,8 +25,9 @@
-
- $(NoWarn);CS1591
+
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/Microsoft.Bot.Streaming/RequestHandler.cs b/libraries/Microsoft.Bot.Streaming/RequestHandler.cs
index 05cfdd40ff..cd7ab7023a 100644
--- a/libraries/Microsoft.Bot.Streaming/RequestHandler.cs
+++ b/libraries/Microsoft.Bot.Streaming/RequestHandler.cs
@@ -12,7 +12,6 @@ namespace Microsoft.Bot.Streaming
///
public abstract class RequestHandler
{
- #pragma warning disable IDE0034
///
/// The method that must be implemented in order to handle incoming requests.
///
@@ -22,6 +21,5 @@ public abstract class RequestHandler
/// Cancellation token.
/// A that will produce a on successful completion.
public abstract Task ProcessRequestAsync(ReceiveRequest request, ILogger logger, object context = null, CancellationToken cancellationToken = default(CancellationToken));
- #pragma warning restore IDE0034
}
}
diff --git a/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core.csproj b/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core.csproj
index 3c99ce50b5..1e741543f3 100644
--- a/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core.csproj
+++ b/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core/Microsoft.Bot.Builder.Integration.ApplicationInsights.Core.csproj
@@ -24,7 +24,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi/Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi.csproj b/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi/Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi.csproj
index e8db339f98..e023234f27 100644
--- a/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi/Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi.csproj
+++ b/libraries/integration/Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi/Microsoft.Bot.Builder.Integration.ApplicationInsights.WebApi.csproj
@@ -25,7 +25,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/integration/Microsoft.Bot.Builder.Integration.AspNet.Core/Microsoft.Bot.Builder.Integration.AspNet.Core.csproj b/libraries/integration/Microsoft.Bot.Builder.Integration.AspNet.Core/Microsoft.Bot.Builder.Integration.AspNet.Core.csproj
index ee8b690fb7..62e821b668 100644
--- a/libraries/integration/Microsoft.Bot.Builder.Integration.AspNet.Core/Microsoft.Bot.Builder.Integration.AspNet.Core.csproj
+++ b/libraries/integration/Microsoft.Bot.Builder.Integration.AspNet.Core/Microsoft.Bot.Builder.Integration.AspNet.Core.csproj
@@ -23,7 +23,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/libraries/integration/Microsoft.Bot.Builder.Integration.AspNet.WebApi/Microsoft.Bot.Builder.Integration.AspNet.WebApi.csproj b/libraries/integration/Microsoft.Bot.Builder.Integration.AspNet.WebApi/Microsoft.Bot.Builder.Integration.AspNet.WebApi.csproj
index c44948c1c7..ca240aba65 100644
--- a/libraries/integration/Microsoft.Bot.Builder.Integration.AspNet.WebApi/Microsoft.Bot.Builder.Integration.AspNet.WebApi.csproj
+++ b/libraries/integration/Microsoft.Bot.Builder.Integration.AspNet.WebApi/Microsoft.Bot.Builder.Integration.AspNet.WebApi.csproj
@@ -20,7 +20,8 @@
- $(NoWarn);CS1591
+
+ $(NoWarn);CS1591;SX1309
diff --git a/tests/Adapters/Microsoft.Bot.Builder.Adapters.Twilio.Tests/TwilioAdapterTests.cs b/tests/Adapters/Microsoft.Bot.Builder.Adapters.Twilio.Tests/TwilioAdapterTests.cs
index ea19b73cdd..a8b0a05c34 100644
--- a/tests/Adapters/Microsoft.Bot.Builder.Adapters.Twilio.Tests/TwilioAdapterTests.cs
+++ b/tests/Adapters/Microsoft.Bot.Builder.Adapters.Twilio.Tests/TwilioAdapterTests.cs
@@ -42,7 +42,7 @@ public async void SendActivitiesAsyncShouldSucceed()
const string resourceIdentifier = "Mocked Resource Identifier";
var twilioApi = new Mock(_testOptions);
- twilioApi.Setup(x => x.SendMessage(It.IsAny(), default)).Returns(Task.FromResult(resourceIdentifier));
+ twilioApi.Setup(x => x.SendMessageAsync(It.IsAny(), default)).Returns(Task.FromResult(resourceIdentifier));
var twilioAdapter = new TwilioAdapter(twilioApi.Object);
var resourceResponses = await twilioAdapter.SendActivitiesAsync(null, new Activity[] { activity.Object }, default).ConfigureAwait(false);
@@ -61,7 +61,7 @@ public async void SendActivitiesAsyncShouldSucceedAndNoActivityReturnedWithActiv
const string resourceIdentifier = "Mocked Resource Identifier";
var twilioApi = new Mock(_testOptions);
- twilioApi.Setup(x => x.SendMessage(It.IsAny(), default)).Returns(Task.FromResult(resourceIdentifier));
+ twilioApi.Setup(x => x.SendMessageAsync(It.IsAny(), default)).Returns(Task.FromResult(resourceIdentifier));
var twilioAdapter = new TwilioAdapter(twilioApi.Object);
var resourceResponses = await twilioAdapter.SendActivitiesAsync(null, new Activity[] { activity.Object }, default).ConfigureAwait(false);
diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props
index c431bb4128..305212613e 100644
--- a/tests/Directory.Build.props
+++ b/tests/Directory.Build.props
@@ -1,8 +1,9 @@
-
- $(NoWarn);SA0001;CS1573,CS1591,CS1712
+
+
+ $(NoWarn);SA0001;CS1573;CS1591;CS1712;SX1309
diff --git a/tests/Microsoft.Bot.Builder.Tests/Adapters/TestAdapterTests.cs b/tests/Microsoft.Bot.Builder.Tests/Adapters/TestAdapterTests.cs
index 04691f013e..f7beb14476 100644
--- a/tests/Microsoft.Bot.Builder.Tests/Adapters/TestAdapterTests.cs
+++ b/tests/Microsoft.Bot.Builder.Tests/Adapters/TestAdapterTests.cs
@@ -16,24 +16,6 @@ namespace Microsoft.Bot.Builder.Tests.Adapters
{
public class TestAdapterTests
{
- public async Task MyBotLogic(ITurnContext turnContext, CancellationToken cancellationToken)
- {
- switch (turnContext.Activity.AsMessageActivity().Text)
- {
- case "count":
- await turnContext.SendActivityAsync(turnContext.Activity.CreateReply("one"));
- await turnContext.SendActivityAsync(turnContext.Activity.CreateReply("two"));
- await turnContext.SendActivityAsync(turnContext.Activity.CreateReply("three"));
- break;
- case "ignore":
- break;
- default:
- await turnContext.SendActivityAsync(
- turnContext.Activity.CreateReply($"echo:{turnContext.Activity.AsMessageActivity().Text}"));
- break;
- }
- }
-
[Fact]
public async Task TestAdapter_ExceptionTypesOnTest()
{
@@ -579,5 +561,23 @@ async Task TestCallback(ITurnContext context, CancellationToken token)
Assert.Equal(targetChannel, receivedChannelId);
Assert.Equal(targetChannel, reply.ChannelId);
}
+
+ private async Task MyBotLogic(ITurnContext turnContext, CancellationToken cancellationToken)
+ {
+ switch (turnContext.Activity.AsMessageActivity().Text)
+ {
+ case "count":
+ await turnContext.SendActivityAsync(turnContext.Activity.CreateReply("one"));
+ await turnContext.SendActivityAsync(turnContext.Activity.CreateReply("two"));
+ await turnContext.SendActivityAsync(turnContext.Activity.CreateReply("three"));
+ break;
+ case "ignore":
+ break;
+ default:
+ await turnContext.SendActivityAsync(
+ turnContext.Activity.CreateReply($"echo:{turnContext.Activity.AsMessageActivity().Text}"));
+ break;
+ }
+ }
}
}
diff --git a/tests/Microsoft.Bot.Builder.Tests/BotStateTests.cs b/tests/Microsoft.Bot.Builder.Tests/BotStateTests.cs
index 67f9c9fbb1..7609cc4c9e 100644
--- a/tests/Microsoft.Bot.Builder.Tests/BotStateTests.cs
+++ b/tests/Microsoft.Bot.Builder.Tests/BotStateTests.cs
@@ -610,7 +610,7 @@ public async Task UserState_BadFromThrows()
var context = TestUtilities.CreateEmptyContext();
context.Activity.From = null;
var testProperty = userState.CreateProperty("test");
- await Assert.ThrowsAsync(() => testProperty.GetAsync(context));
+ await Assert.ThrowsAsync(() => testProperty.GetAsync(context));
}
[Fact]
@@ -621,7 +621,7 @@ public async Task ConversationState_BadConverationThrows()
var context = TestUtilities.CreateEmptyContext();
context.Activity.Conversation = null;
var testProperty = userState.CreateProperty("test");
- await Assert.ThrowsAsync(() => testProperty.GetAsync(context));
+ await Assert.ThrowsAsync(() => testProperty.GetAsync(context));
}
[Fact]
@@ -633,7 +633,7 @@ public async Task PrivateConversationState_BadActivityFromThrows()
context.Activity.Conversation = null;
context.Activity.From = null;
var testProperty = userState.CreateProperty("test");
- await Assert.ThrowsAsync(() => testProperty.GetAsync(context));
+ await Assert.ThrowsAsync(() => testProperty.GetAsync(context));
}
[Fact]
@@ -644,7 +644,7 @@ public async Task PrivateConversationState_BadActivityConversationThrows()
var context = TestUtilities.CreateEmptyContext();
context.Activity.Conversation = null;
var testProperty = userState.CreateProperty("test");
- await Assert.ThrowsAsync(() => testProperty.GetAsync(context));
+ await Assert.ThrowsAsync(() => testProperty.GetAsync(context));
}
[Fact]