This commit is contained in:
Victor 2021-06-10 15:57:08 -03:00
Родитель 5509384a9b
Коммит a1655dbe43
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: D5244A093A932369
13 изменённых файлов: 211 добавлений и 12 удалений

Просмотреть файл

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@ -16,8 +17,11 @@ using Microsoft.Bot.Solutions;
using Microsoft.Bot.Solutions.Responses;
using Microsoft.Bot.Solutions.Skills.Dialogs;
using Microsoft.Bot.Solutions.Testing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using $ext_safeprojectname$.Bots;
using $ext_safeprojectname$.Dialogs;
using $ext_safeprojectname$.Models;
@ -53,7 +57,7 @@ namespace $safeprojectname$
[TestInitialize]
public virtual void Initialize()
{
Services = new ServiceCollection();
Services = new ServiceCollection().AddLogging(config => config.AddConsole());
Services.AddSingleton(new BotSettings());
Services.AddSingleton(new BotServices()
{
@ -131,6 +135,14 @@ namespace $safeprojectname$
Services.AddSingleton<TestAdapter, DefaultTestAdapter>();
Services.AddTransient<IBot, DefaultActivityHandler<MockMainDialog>>();
// Add MicrosoftAPPId to configuration
var configuration = new Mock<IConfiguration>();
var configurationSection = new Mock<IConfigurationSection>();
configurationSection.Setup(a => a.Value).Returns("testvalue");
configuration.Setup(a => a.GetSection("MicrosoftAppId")).Returns(configurationSection.Object);
// Register configuration
Services.AddSingleton(configuration.Object);
TestUserProfileState = new UserProfileState();
TestUserProfileState.Name = "Bot";
}

Просмотреть файл

@ -29,6 +29,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="Moq" Version="4.14.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
<PackageReference Include="MSTest.TestFramework" Version="2.0.0" />
<PackageReference Include="RichardSzalay.MockHttp" Version="6.0.0" />

Просмотреть файл

@ -3,17 +3,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Choices;
using Microsoft.Bot.Builder.Integration.AspNet.Core.Skills;
using Microsoft.Bot.Builder.Teams;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Schema;
using Microsoft.Bot.Schema.Teams;
using Microsoft.Bot.Solutions;
using Microsoft.Bot.Solutions.Responses;
using Microsoft.Bot.Solutions.Skills;
using Microsoft.Bot.Solutions.Skills.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using $safeprojectname$.Extensions;
using $safeprojectname$.Models;
namespace $safeprojectname$.Bots
@ -27,8 +36,13 @@ namespace $safeprojectname$.Bots
private readonly IStatePropertyAccessor<DialogState> _dialogStateAccessor;
private readonly IStatePropertyAccessor<UserProfileState> _userProfileState;
private readonly LocaleTemplateManager _templateManager;
private readonly SkillHttpClient _skillHttpClient;
private readonly SkillsConfiguration _skillsConfig;
private readonly IConfiguration _configuration;
private readonly string _virtualAssistantBotId;
private readonly ILogger _logger;
public DefaultActivityHandler(IServiceProvider serviceProvider, T dialog)
public DefaultActivityHandler(IServiceProvider serviceProvider, ILogger<DefaultActivityHandler<T>> logger, T dialog)
{
_dialog = dialog;
_dialog.TelemetryClient = serviceProvider.GetService<IBotTelemetryClient>();
@ -37,6 +51,11 @@ namespace $safeprojectname$.Bots
_dialogStateAccessor = _conversationState.CreateProperty<DialogState>(nameof(DialogState));
_userProfileState = _userState.CreateProperty<UserProfileState>(nameof(UserProfileState));
_templateManager = serviceProvider.GetService<LocaleTemplateManager>();
_skillHttpClient = serviceProvider.GetService<SkillHttpClient>();
_skillsConfig = serviceProvider.GetService<SkillsConfiguration>();
_configuration = serviceProvider.GetService<IConfiguration>();
_virtualAssistantBotId = _configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;
_logger = logger;
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
@ -104,9 +123,49 @@ namespace $safeprojectname$.Bots
}
}
// Invoked when a "task/fetch" event is received to invoke task module.
protected override async Task<TaskModuleResponse> OnTeamsTaskModuleFetchAsync(ITurnContext<IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
{
return await this.ProcessTaskModuleInvokeAsync(turnContext, cancellationToken);
}
// Invoked when a 'task/submit' invoke activity is received for task module submit actions.
protected override async Task<TaskModuleResponse> OnTeamsTaskModuleSubmitAsync(ITurnContext<IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
{
return await this.ProcessTaskModuleInvokeAsync(turnContext, cancellationToken);
}
protected override async Task OnEndOfConversationActivityAsync(ITurnContext<IEndOfConversationActivity> turnContext, CancellationToken cancellationToken)
{
await _dialog.RunAsync(turnContext, _dialogStateAccessor, cancellationToken);
}
private async Task<TaskModuleResponse> ProcessTaskModuleInvokeAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken)
{
try
{
// Get Skill From TaskInvoke
var skillId = (turnContext.Activity as Activity).AsInvokeActivity().GetSkillId(_logger);
var skill = _skillsConfig.Skills.Where(s => s.Value.AppId == skillId).FirstOrDefault().Value;
// Forward request to correct skill
var invokeResponse = await _skillHttpClient.PostActivityAsync(_virtualAssistantBotId, skill, _skillsConfig.SkillHostEndpoint, turnContext.Activity as Activity, cancellationToken).ConfigureAwait(false);
// Temporary workaround to get correct invokeresponse
// issue: https://github.com/microsoft/botframework-sdk/issues/5929
var response = new InvokeResponse()
{
Status = invokeResponse.Status,
Body = ((Microsoft.Bot.Builder.InvokeResponse<object>)invokeResponse).Body
};
return response.GetTaskModuleResponse();
}
catch
{
await turnContext.SendActivityAsync(_templateManager.GenerateActivityForLocale("ErrorMessage"));
throw;
}
}
}
}

Просмотреть файл

@ -33,6 +33,7 @@ namespace $safeprojectname$.Dialogs
private readonly LocaleTemplateManager _templateManager;
private readonly BotServices _services;
private readonly BotSettings _settings;
private readonly OnboardingDialog _onboardingDialog;
private readonly SwitchSkillDialog _switchSkillDialog;
private readonly SkillsConfiguration _skillsConfig;
@ -44,6 +45,7 @@ namespace $safeprojectname$.Dialogs
IServiceProvider serviceProvider)
: base(nameof(MainDialog))
{
_settings = serviceProvider.GetService<BotSettings>();
_services = serviceProvider.GetService<BotServices>();
_templateManager = serviceProvider.GetService<LocaleTemplateManager>();
_skillsConfig = serviceProvider.GetService<SkillsConfiguration>();
@ -189,7 +191,8 @@ namespace $safeprojectname$.Dialogs
activeLearningCardTitle: _templateManager.GenerateActivityForLocale("QnaMakerAdaptiveLearningCardTitle").Text,
cardNoMatchText: _templateManager.GenerateActivityForLocale("QnaMakerNoMatchText").Text)
{
Id = knowledgebaseId
Id = knowledgebaseId,
LogPersonalInformation = _settings.LogPersonalData
};
}
else

Просмотреть файл

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using AdaptiveExpressions;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using $safeprojectname$.Models;
namespace $safeprojectname$.Extensions
{
/// <summary>
/// Extension class for getting SkillId from Activity.
/// </summary>
public static class InvokeActivityExtensions
{
// Fetches skillId from CardAction data if present
public static string GetSkillId(this IInvokeActivity activity, ILogger logger)
{
if (activity == null)
{
logger.Log(LogLevel.Error, "activity is null from TaskModule");
throw new ArgumentNullException(nameof(activity));
}
if (activity.Value == null)
{
logger.Log(LogLevel.Error, "activity.Value is null from TaskModule");
throw new ArgumentException("activity.Value is null.", nameof(activity));
}
// GetSkillId from Activity Value
var data = JObject.Parse(activity.Value.ToString()).SelectToken("data.data")?.ToObject<SkillCardActionData>();
return data.SkillId ?? throw new ArgumentException("SkillId in TaskModule is null", nameof(SkillCardActionData));
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema.Teams;
using Newtonsoft.Json.Linq;
namespace $safeprojectname$.Extensions
{
/// <summary>
/// InvokeResposneHandler class for returning TaskModuleResponse from InvokeResponse
/// </summary>
public static class InvokeResponseExtensions
{
// Converts "InvokeResponse" sent by SkillHttpClient to "TaskModuleResponse"
public static TaskModuleResponse GetTaskModuleResponse(this InvokeResponse invokeResponse)
{
if (invokeResponse == null)
{
throw new ArgumentNullException(nameof(invokeResponse));
}
if (invokeResponse.Body != null)
{
return new TaskModuleResponse()
{
Task = GetTask(invokeResponse.Body),
};
}
return null;
}
private static TaskModuleResponseBase GetTask(object invokeResponseBody)
{
var responseBody = JObject.FromObject(invokeResponseBody);
var task = responseBody.GetValue("task");
string taskType = task.SelectToken("type")?.Value<string>();
return taskType switch
{
"continue" => new TaskModuleContinueResponse()
{
Type = taskType,
Value = task.SelectToken("value").ToObject<TaskModuleTaskInfo>(),
},
"message" => new TaskModuleMessageResponse()
{
Type = taskType,
Value = task.SelectToken("value").ToString(),
},
_ => null,
};
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Newtonsoft.Json;
namespace $safeprojectname$.Models
{
/// <summary>
/// Skill Card action data should contain skillName parameter
/// This class is used to deserialize it and get skillName.
/// </summary>
/// <value>
/// SkillName.
/// </value>
public class SkillCardActionData
{
[JsonProperty("SkillId")]
public string SkillId { get; set; }
}
}

Просмотреть файл

@ -36,7 +36,7 @@ namespace $safeprojectname$.Services
luisOptions = new LuisRecognizerOptionsV3(dispatchApp)
{
TelemetryClient = telemetryClient,
LogPersonalInformation = true,
LogPersonalInformation = settings.LogPersonalData,
};
set.DispatchService = new LuisRecognizer(luisOptions);
}
@ -49,7 +49,7 @@ namespace $safeprojectname$.Services
luisOptions = new LuisRecognizerOptionsV3(luisApp)
{
TelemetryClient = telemetryClient,
LogPersonalInformation = true,
LogPersonalInformation = settings.LogPersonalData,
};
set.LuisServices.Add(model.Id, new LuisRecognizer(luisOptions));
}

Просмотреть файл

@ -9,5 +9,6 @@ namespace $safeprojectname$.Services
public class BotSettings : BotSettingsBase
{
public TokenExchangeConfig TokenExchangeConfig { get; set; }
public bool LogPersonalData { get; set; }
}
}

Просмотреть файл

@ -58,7 +58,10 @@ namespace $safeprojectname$
services.AddSingleton(Configuration);
// Load settings
var settings = new BotSettings();
var settings = new BotSettings()
{
LogPersonalData = Configuration.GetSection("logPersonalInfo")?.Value.ToLower() == "true"
};
Configuration.Bind(settings);
services.AddSingleton(settings);
@ -82,7 +85,8 @@ namespace $safeprojectname$
services.AddSingleton<ITelemetryInitializer, OperationCorrelationTelemetryInitializer>();
services.AddSingleton<ITelemetryInitializer, TelemetryBotIdInitializer>();
services.AddSingleton<TelemetryInitializerMiddleware>();
services.AddSingleton<TelemetryLoggerMiddleware>();
services.AddSingleton<TelemetryLoggerMiddleware>(s => new TelemetryLoggerMiddleware(s.GetService<IBotTelemetryClient>(), settings.LogPersonalData));
// Configure bot services
services.AddSingleton<BotServices>();

Просмотреть файл

@ -17,7 +17,7 @@
<PackageReference Include="Microsoft.Bot.Builder.AI.Luis" Version="4.13.2" />
<PackageReference Include="Microsoft.Bot.Builder.AI.QnA" Version="4.13.2" />
<PackageReference Include="Microsoft.Bot.Builder.ApplicationInsights" Version="4.13.2" />
<PackageReference Include="Microsoft.Bot.Builder.Azure" Version="4.13.2" />
<PackageReference Include="Microsoft.Bot.Builder.Azure.Blobs" Version="4.13.2" />
<PackageReference Include="Microsoft.Bot.Builder.Integration.ApplicationInsights.Core" Version="4.13.2" />
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Version="4.13.2" />
<PackageReference Include="Microsoft.Bot.Builder.LanguageGeneration" Version="4.13.2" />

Просмотреть файл

@ -27,9 +27,6 @@
<Folder Name="Adapters" TargetFolderName="Adapters">
<ProjectItem ReplaceParameters="true" TargetFileName="DefaultAdapter.cs">DefaultAdapter.cs</ProjectItem>
</Folder>
<Folder Name="Authentication" TargetFolderName="Authentication">
<ProjectItem ReplaceParameters="true" TargetFileName="AllowedCallersClaimsValidator.cs">AllowedCallersClaimsValidator.cs</ProjectItem>
</Folder>
<Folder Name="Bots" TargetFolderName="Bots">
<ProjectItem ReplaceParameters="true" TargetFileName="DefaultActivityHandler.cs">DefaultActivityHandler.cs</ProjectItem>
</Folder>
@ -101,7 +98,12 @@
<ProjectItem ReplaceParameters="true" TargetFileName="MainDialog.cs">MainDialog.cs</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="OnboardingDialog.cs">OnboardingDialog.cs</ProjectItem>
</Folder>
<Folder Name="Extensions" TargetFolderName="Extensions">
<ProjectItem ReplaceParameters="true" TargetFileName="InvokeActivityExtensions.cs">InvokeActivityExtensions.cs</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="InvokeResponseExtensions.cs">InvokeResponseExtensions.cs</ProjectItem>
</Folder>
<Folder Name="Models" TargetFolderName="Models">
<ProjectItem ReplaceParameters="true" TargetFileName="SkillCardActionData.cs">SkillCardActionData.cs</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="StateProperties.cs">StateProperties.cs</ProjectItem>
<ProjectItem ReplaceParameters="true" TargetFileName="UserProfileState.cs">UserProfileState.cs</ProjectItem>
</Folder>

Просмотреть файл

@ -21,5 +21,6 @@
},
"contentModerator": {
"key": ""
}
},
"logPersonalInfo": true
}