Skip to content
This repository was archived by the owner on Jun 30, 2022. It is now read-only.

Commit a1655db

Browse files
committed
Update VA template
1 parent 5509384 commit a1655db

13 files changed

Lines changed: 211 additions & 12 deletions

templates/csharp/VA/VA.Tests/BotTestBase.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Globalization;
67
using System.IO;
@@ -16,8 +17,11 @@
1617
using Microsoft.Bot.Solutions.Responses;
1718
using Microsoft.Bot.Solutions.Skills.Dialogs;
1819
using Microsoft.Bot.Solutions.Testing;
20+
using Microsoft.Extensions.Configuration;
1921
using Microsoft.Extensions.DependencyInjection;
22+
using Microsoft.Extensions.Logging;
2023
using Microsoft.VisualStudio.TestTools.UnitTesting;
24+
using Moq;
2125
using $ext_safeprojectname$.Bots;
2226
using $ext_safeprojectname$.Dialogs;
2327
using $ext_safeprojectname$.Models;
@@ -53,7 +57,7 @@ protected Templates AllResponsesTemplates
5357
[TestInitialize]
5458
public virtual void Initialize()
5559
{
56-
Services = new ServiceCollection();
60+
Services = new ServiceCollection().AddLogging(config => config.AddConsole());
5761
Services.AddSingleton(new BotSettings());
5862
Services.AddSingleton(new BotServices()
5963
{
@@ -131,6 +135,14 @@ public virtual void Initialize()
131135
Services.AddSingleton<TestAdapter, DefaultTestAdapter>();
132136
Services.AddTransient<IBot, DefaultActivityHandler<MockMainDialog>>();
133137

138+
// Add MicrosoftAPPId to configuration
139+
var configuration = new Mock<IConfiguration>();
140+
var configurationSection = new Mock<IConfigurationSection>();
141+
configurationSection.Setup(a => a.Value).Returns("testvalue");
142+
configuration.Setup(a => a.GetSection("MicrosoftAppId")).Returns(configurationSection.Object);
143+
// Register configuration
144+
Services.AddSingleton(configuration.Object);
145+
134146
TestUserProfileState = new UserProfileState();
135147
TestUserProfileState.Name = "Bot";
136148
}

templates/csharp/VA/VA.Tests/VA.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.1" />
3030
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.1" />
3131
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
32+
<PackageReference Include="Moq" Version="4.14.1" />
3233
<PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
3334
<PackageReference Include="MSTest.TestFramework" Version="2.0.0" />
3435
<PackageReference Include="RichardSzalay.MockHttp" Version="6.0.0" />

templates/csharp/VA/VA/Bots/DefaultActivityHandler.cs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,26 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Linq;
67
using System.Threading;
78
using System.Threading.Tasks;
89
using Microsoft.Bot.Builder;
910
using Microsoft.Bot.Builder.Dialogs;
1011
using Microsoft.Bot.Builder.Dialogs.Choices;
12+
using Microsoft.Bot.Builder.Integration.AspNet.Core.Skills;
1113
using Microsoft.Bot.Builder.Teams;
1214
using Microsoft.Bot.Connector;
15+
using Microsoft.Bot.Connector.Authentication;
1316
using Microsoft.Bot.Schema;
17+
using Microsoft.Bot.Schema.Teams;
1418
using Microsoft.Bot.Solutions;
1519
using Microsoft.Bot.Solutions.Responses;
20+
using Microsoft.Bot.Solutions.Skills;
21+
using Microsoft.Bot.Solutions.Skills.Models;
22+
using Microsoft.Extensions.Configuration;
1623
using Microsoft.Extensions.DependencyInjection;
24+
using Microsoft.Extensions.Logging;
25+
using $safeprojectname$.Extensions;
1726
using $safeprojectname$.Models;
1827

1928
namespace $safeprojectname$.Bots
@@ -27,8 +36,13 @@ public class DefaultActivityHandler<T> : TeamsActivityHandler
2736
private readonly IStatePropertyAccessor<DialogState> _dialogStateAccessor;
2837
private readonly IStatePropertyAccessor<UserProfileState> _userProfileState;
2938
private readonly LocaleTemplateManager _templateManager;
39+
private readonly SkillHttpClient _skillHttpClient;
40+
private readonly SkillsConfiguration _skillsConfig;
41+
private readonly IConfiguration _configuration;
42+
private readonly string _virtualAssistantBotId;
43+
private readonly ILogger _logger;
3044

31-
public DefaultActivityHandler(IServiceProvider serviceProvider, T dialog)
45+
public DefaultActivityHandler(IServiceProvider serviceProvider, ILogger<DefaultActivityHandler<T>> logger, T dialog)
3246
{
3347
_dialog = dialog;
3448
_dialog.TelemetryClient = serviceProvider.GetService<IBotTelemetryClient>();
@@ -37,6 +51,11 @@ public DefaultActivityHandler(IServiceProvider serviceProvider, T dialog)
3751
_dialogStateAccessor = _conversationState.CreateProperty<DialogState>(nameof(DialogState));
3852
_userProfileState = _userState.CreateProperty<UserProfileState>(nameof(UserProfileState));
3953
_templateManager = serviceProvider.GetService<LocaleTemplateManager>();
54+
_skillHttpClient = serviceProvider.GetService<SkillHttpClient>();
55+
_skillsConfig = serviceProvider.GetService<SkillsConfiguration>();
56+
_configuration = serviceProvider.GetService<IConfiguration>();
57+
_virtualAssistantBotId = _configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;
58+
_logger = logger;
4059
}
4160

4261
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
@@ -104,9 +123,49 @@ protected override async Task OnEventActivityAsync(ITurnContext<IEventActivity>
104123
}
105124
}
106125

126+
// Invoked when a "task/fetch" event is received to invoke task module.
127+
protected override async Task<TaskModuleResponse> OnTeamsTaskModuleFetchAsync(ITurnContext<IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
128+
{
129+
return await this.ProcessTaskModuleInvokeAsync(turnContext, cancellationToken);
130+
}
131+
132+
// Invoked when a 'task/submit' invoke activity is received for task module submit actions.
133+
protected override async Task<TaskModuleResponse> OnTeamsTaskModuleSubmitAsync(ITurnContext<IInvokeActivity> turnContext, TaskModuleRequest taskModuleRequest, CancellationToken cancellationToken)
134+
{
135+
return await this.ProcessTaskModuleInvokeAsync(turnContext, cancellationToken);
136+
}
137+
107138
protected override async Task OnEndOfConversationActivityAsync(ITurnContext<IEndOfConversationActivity> turnContext, CancellationToken cancellationToken)
108139
{
109140
await _dialog.RunAsync(turnContext, _dialogStateAccessor, cancellationToken);
110141
}
142+
143+
private async Task<TaskModuleResponse> ProcessTaskModuleInvokeAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken)
144+
{
145+
try
146+
{
147+
// Get Skill From TaskInvoke
148+
var skillId = (turnContext.Activity as Activity).AsInvokeActivity().GetSkillId(_logger);
149+
var skill = _skillsConfig.Skills.Where(s => s.Value.AppId == skillId).FirstOrDefault().Value;
150+
151+
// Forward request to correct skill
152+
var invokeResponse = await _skillHttpClient.PostActivityAsync(_virtualAssistantBotId, skill, _skillsConfig.SkillHostEndpoint, turnContext.Activity as Activity, cancellationToken).ConfigureAwait(false);
153+
154+
// Temporary workaround to get correct invokeresponse
155+
// issue: https://github.com/microsoft/botframework-sdk/issues/5929
156+
var response = new InvokeResponse()
157+
{
158+
Status = invokeResponse.Status,
159+
Body = ((Microsoft.Bot.Builder.InvokeResponse<object>)invokeResponse).Body
160+
};
161+
162+
return response.GetTaskModuleResponse();
163+
}
164+
catch
165+
{
166+
await turnContext.SendActivityAsync(_templateManager.GenerateActivityForLocale("ErrorMessage"));
167+
throw;
168+
}
169+
}
111170
}
112171
}

templates/csharp/VA/VA/Dialogs/MainDialog.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class MainDialog : ComponentDialog
3333

3434
private readonly LocaleTemplateManager _templateManager;
3535
private readonly BotServices _services;
36+
private readonly BotSettings _settings;
3637
private readonly OnboardingDialog _onboardingDialog;
3738
private readonly SwitchSkillDialog _switchSkillDialog;
3839
private readonly SkillsConfiguration _skillsConfig;
@@ -44,6 +45,7 @@ public MainDialog(
4445
IServiceProvider serviceProvider)
4546
: base(nameof(MainDialog))
4647
{
48+
_settings = serviceProvider.GetService<BotSettings>();
4749
_services = serviceProvider.GetService<BotServices>();
4850
_templateManager = serviceProvider.GetService<LocaleTemplateManager>();
4951
_skillsConfig = serviceProvider.GetService<SkillsConfiguration>();
@@ -189,7 +191,8 @@ protected virtual QnAMakerDialog TryCreateQnADialog(string knowledgebaseId, Cogn
189191
activeLearningCardTitle: _templateManager.GenerateActivityForLocale("QnaMakerAdaptiveLearningCardTitle").Text,
190192
cardNoMatchText: _templateManager.GenerateActivityForLocale("QnaMakerNoMatchText").Text)
191193
{
192-
Id = knowledgebaseId
194+
Id = knowledgebaseId,
195+
LogPersonalInformation = _settings.LogPersonalData
193196
};
194197
}
195198
else
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using AdaptiveExpressions;
6+
using Microsoft.Bot.Schema;
7+
using Microsoft.Extensions.Logging;
8+
using Newtonsoft.Json;
9+
using Newtonsoft.Json.Linq;
10+
using $safeprojectname$.Models;
11+
12+
namespace $safeprojectname$.Extensions
13+
{
14+
/// <summary>
15+
/// Extension class for getting SkillId from Activity.
16+
/// </summary>
17+
public static class InvokeActivityExtensions
18+
{
19+
// Fetches skillId from CardAction data if present
20+
public static string GetSkillId(this IInvokeActivity activity, ILogger logger)
21+
{
22+
if (activity == null)
23+
{
24+
logger.Log(LogLevel.Error, "activity is null from TaskModule");
25+
throw new ArgumentNullException(nameof(activity));
26+
}
27+
28+
if (activity.Value == null)
29+
{
30+
logger.Log(LogLevel.Error, "activity.Value is null from TaskModule");
31+
throw new ArgumentException("activity.Value is null.", nameof(activity));
32+
}
33+
34+
// GetSkillId from Activity Value
35+
var data = JObject.Parse(activity.Value.ToString()).SelectToken("data.data")?.ToObject<SkillCardActionData>();
36+
return data.SkillId ?? throw new ArgumentException("SkillId in TaskModule is null", nameof(SkillCardActionData));
37+
}
38+
}
39+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using Microsoft.Bot.Builder;
6+
using Microsoft.Bot.Schema.Teams;
7+
using Newtonsoft.Json.Linq;
8+
9+
namespace $safeprojectname$.Extensions
10+
{
11+
/// <summary>
12+
/// InvokeResposneHandler class for returning TaskModuleResponse from InvokeResponse
13+
/// </summary>
14+
public static class InvokeResponseExtensions
15+
{
16+
// Converts "InvokeResponse" sent by SkillHttpClient to "TaskModuleResponse"
17+
public static TaskModuleResponse GetTaskModuleResponse(this InvokeResponse invokeResponse)
18+
{
19+
if (invokeResponse == null)
20+
{
21+
throw new ArgumentNullException(nameof(invokeResponse));
22+
}
23+
24+
if (invokeResponse.Body != null)
25+
{
26+
return new TaskModuleResponse()
27+
{
28+
Task = GetTask(invokeResponse.Body),
29+
};
30+
}
31+
32+
return null;
33+
}
34+
35+
private static TaskModuleResponseBase GetTask(object invokeResponseBody)
36+
{
37+
var responseBody = JObject.FromObject(invokeResponseBody);
38+
var task = responseBody.GetValue("task");
39+
string taskType = task.SelectToken("type")?.Value<string>();
40+
41+
return taskType switch
42+
{
43+
"continue" => new TaskModuleContinueResponse()
44+
{
45+
Type = taskType,
46+
Value = task.SelectToken("value").ToObject<TaskModuleTaskInfo>(),
47+
},
48+
"message" => new TaskModuleMessageResponse()
49+
{
50+
Type = taskType,
51+
Value = task.SelectToken("value").ToString(),
52+
},
53+
_ => null,
54+
};
55+
}
56+
}
57+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Newtonsoft.Json;
5+
6+
namespace $safeprojectname$.Models
7+
{
8+
/// <summary>
9+
/// Skill Card action data should contain skillName parameter
10+
/// This class is used to deserialize it and get skillName.
11+
/// </summary>
12+
/// <value>
13+
/// SkillName.
14+
/// </value>
15+
public class SkillCardActionData
16+
{
17+
[JsonProperty("SkillId")]
18+
public string SkillId { get; set; }
19+
}
20+
}

templates/csharp/VA/VA/Services/BotServices.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public BotServices(BotSettings settings, IBotTelemetryClient client)
3636
luisOptions = new LuisRecognizerOptionsV3(dispatchApp)
3737
{
3838
TelemetryClient = telemetryClient,
39-
LogPersonalInformation = true,
39+
LogPersonalInformation = settings.LogPersonalData,
4040
};
4141
set.DispatchService = new LuisRecognizer(luisOptions);
4242
}
@@ -49,7 +49,7 @@ public BotServices(BotSettings settings, IBotTelemetryClient client)
4949
luisOptions = new LuisRecognizerOptionsV3(luisApp)
5050
{
5151
TelemetryClient = telemetryClient,
52-
LogPersonalInformation = true,
52+
LogPersonalInformation = settings.LogPersonalData,
5353
};
5454
set.LuisServices.Add(model.Id, new LuisRecognizer(luisOptions));
5555
}

templates/csharp/VA/VA/Services/BotSettings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ namespace $safeprojectname$.Services
99
public class BotSettings : BotSettingsBase
1010
{
1111
public TokenExchangeConfig TokenExchangeConfig { get; set; }
12+
public bool LogPersonalData { get; set; }
1213
}
1314
}

templates/csharp/VA/VA/Startup.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ public void ConfigureServices(IServiceCollection services)
5858
services.AddSingleton(Configuration);
5959

6060
// Load settings
61-
var settings = new BotSettings();
61+
var settings = new BotSettings()
62+
{
63+
LogPersonalData = Configuration.GetSection("logPersonalInfo")?.Value.ToLower() == "true"
64+
};
6265
Configuration.Bind(settings);
6366
services.AddSingleton(settings);
6467

@@ -82,7 +85,8 @@ public void ConfigureServices(IServiceCollection services)
8285
services.AddSingleton<ITelemetryInitializer, OperationCorrelationTelemetryInitializer>();
8386
services.AddSingleton<ITelemetryInitializer, TelemetryBotIdInitializer>();
8487
services.AddSingleton<TelemetryInitializerMiddleware>();
85-
services.AddSingleton<TelemetryLoggerMiddleware>();
88+
89+
services.AddSingleton<TelemetryLoggerMiddleware>(s => new TelemetryLoggerMiddleware(s.GetService<IBotTelemetryClient>(), settings.LogPersonalData));
8690

8791
// Configure bot services
8892
services.AddSingleton<BotServices>();

0 commit comments

Comments
 (0)