Reputation: 1438
I am needing some help. I am new at developing in Azure's Bot Framework, creating my first chatbot some weeks ago using a QnA KB. In any case, I managed to create the bot in Azure's portal and it is working perfectly. But I need to do some alterations and tests in Bot Framework Emulator (using V4) and, to do so, download and run locally my bot.
I made the download of my bot's .zip file following Azure's instructions and initialized it using Visual Studio 2017 as my IDE. When I hit the button "debug", though, the program tries to connect to localhost:3984.
using Autofac;
using System.Web.Http;
using System.Configuration;
using System.Reflection;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Internals;
using Microsoft.Bot.Connector;
namespace SimpleEchoBot
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Bot Storage: This is a great spot to register the private state storage for your bot.
// We provide adapters for Azure Table, CosmosDb, SQL Azure, or you can implement your own!
// For samples and documentation, see: https://github.com/Microsoft/BotBuilder-Azure
Conversation.UpdateContainer(
builder =>
{
builder.RegisterModule(new AzureModule(Assembly.GetExecutingAssembly()));
// Using Azure Table Storage
var store = new TableBotDataStore(ConfigurationManager.AppSettings["AzureWebJobsStorage"]); // requires Microsoft.BotBuilder.Azure Nuget package
// To use CosmosDb or InMemory storage instead of the default table storage, uncomment the corresponding line below
// var store = new DocumentDbBotDataStore("cosmos db uri", "cosmos db key"); // requires Microsoft.BotBuilder.Azure Nuget package
// var store = new InMemoryDataStore(); // volatile in-memory store
builder.Register(c => store)
.Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
.AsSelf()
.SingleInstance();
});
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
In matter of seconds, though, the following line of code returns the error System.ArgumentNullException: 'Value cannot be null. Arg_ParamName_Name':
var store = new TableBotDataStore(ConfigurationManager.AppSettings["AzureWebJobsStorage"]); // requires Microsoft.BotBuilder.Azure Nuget package
As a consequence, I am unable to test my bot in the Bot Framework Emulator. Since I am really new with C#, could anyone give me a hand at solving this?
EDIT: Here is my web.config part of the code, just removing sensitive data:
<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301879
-->
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<appSettings>
<!-- update these with your Microsoft App Id and your Microsoft App Password-->
<!--<add key="BotId" value="" />-->
<add key="MicrosoftAppId" value="" />
<add key="MicrosoftAppPassword" value="" />
<add key="QnaSubscriptionKey" value="" />
<add key="QnaKnowledgebaseId" value="" />
<add key="AzureWebJobsStorage" value="" />
</appSettings>
<!--
For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.
The following attributes can be set on the <httpRuntime> tag.
<system.Web>
<httpRuntime targetFramework="4.6" />
</system.Web>
-->
<system.web>
<customErrors mode="Off" />
<compilation debug="true" targetFramework="4.6" />
<httpRuntime targetFramework="4.6" />
</system.web>
<system.webServer>
<defaultDocument>
<files>
<clear />
<add value="default.htm" />
</files>
</defaultDocument>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.1.4.0" newVersion="5.1.4.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.Protocol.Extensions" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.40306.1554" newVersion="1.0.40306.1554" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Bot.Connector" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.15.2.2" newVersion="3.15.2.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Bot.Builder" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.15.2.2" newVersion="3.15.2.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Azure.Documents.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.11.0.0" newVersion="1.11.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Bot.Builder.History" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.12.2.4" newVersion="3.12.2.4" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Bot.Builder.Autofac" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.15.2.2" newVersion="3.15.2.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.7.0.0" newVersion="5.7.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.7.0.0" newVersion="5.7.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.7.0.0" newVersion="5.7.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+" />
</compilers>
</system.codedom>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
EDIT 2: Some screenshots of the issue so far:
EDIT 3: Trying to solve "Please set QnAKnowledgebaseId, QnAAuthKey and QnAEndpointHostName (if applicable) in App Settings. Learn how to get them at https://aka.ms/qnaabssetup.". Basic QnAMakerDialog.cs so far (the first instances of qnaAuthKey, qnaKBId and endpointHostName had values attributed to them, but I erased them at here for safety):
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.CognitiveServices.QnAMaker;
using Microsoft.Bot.Connector;
using System.Configuration;
namespace Microsoft.Bot.Sample.QnABot
{
[Serializable]
public class RootDialog : IDialog<object>
{
public async Task StartAsync(IDialogContext context)
{
/* Wait until the first message is received from the conversation and call MessageReceviedAsync
* to process that message. */
context.Wait(this.MessageReceivedAsync);
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
/* When MessageReceivedAsync is called, it's passed an IAwaitable<IMessageActivity>. To get the message,
* await the result. */
var message = await result;
var qnaAuthKey = GetSetting("");
var qnaKBId = ConfigurationManager.AppSettings[""];
var endpointHostName = ConfigurationManager.AppSettings[""];
// QnA Subscription Key and KnowledgeBase Id null verification
if (!string.IsNullOrEmpty(qnaAuthKey) && !string.IsNullOrEmpty(qnaKBId))
{
// Forward to the appropriate Dialog based on whether the endpoint hostname is present
if (string.IsNullOrEmpty(endpointHostName))
await context.Forward(new BasicQnAMakerPreviewDialog(), AfterAnswerAsync, message, CancellationToken.None);
else
await context.Forward(new BasicQnAMakerDialog(), AfterAnswerAsync, message, CancellationToken.None);
}
else
{
await context.PostAsync("Please set QnAKnowledgebaseId, QnAAuthKey and QnAEndpointHostName (if applicable) in App Settings. Learn how to get them at https://aka.ms/qnaabssetup.");
}
}
private async Task AfterAnswerAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
// wait for the next user message
context.Wait(MessageReceivedAsync);
}
public static string GetSetting(string key)
{
var value = ConfigurationManager.AppSettings[key];
if (String.IsNullOrEmpty(value) && key == "QnAAuthKey")
{
value = ConfigurationManager.AppSettings["QnASubscriptionKey"]; // QnASubscriptionKey for backward compatibility with QnAMaker (Preview)
}
return value;
}
}
// Dialog for QnAMaker Preview service
[Serializable]
public class BasicQnAMakerPreviewDialog : QnAMakerDialog
{
// Go to https://qnamaker.ai and feed data, train & publish your QnA Knowledgebase.
// Parameters to QnAMakerService are:
// Required: subscriptionKey, knowledgebaseId,
// Optional: defaultMessage, scoreThreshold[Range 0.0 – 1.0]
public BasicQnAMakerPreviewDialog() : base(new QnAMakerService(new QnAMakerAttribute(RootDialog.GetSetting("QnAAuthKey"), ConfigurationManager.AppSettings["QnAKnowledgebaseId"], "No good match in FAQ.", 0.5)))
{ }
}
// Dialog for QnAMaker GA service
[Serializable]
public class BasicQnAMakerDialog : QnAMakerDialog
{
// Go to https://qnamaker.ai and feed data, train & publish your QnA Knowledgebase.
// Parameters to QnAMakerService are:
// Required: qnaAuthKey, knowledgebaseId, endpointHostName
// Optional: defaultMessage, scoreThreshold[Range 0.0 – 1.0]
public BasicQnAMakerDialog() : base(new QnAMakerService(new QnAMakerAttribute(RootDialog.GetSetting("QnAAuthKey"), ConfigurationManager.AppSettings["QnAKnowledgebaseId"], "Desculpe, não entendi muito bem sua pergunta... Poderia refazê-la de forma diferente? Caso já tenha tentado, talvez eu ainda não saiba como responder sua dúvida.", 0.3, 1, ConfigurationManager.AppSettings["QnAEndpointHostName"])))
{ }
}
}
Upvotes: 2
Views: 2465
Reputation: 1248
As the error mentions, the problem here is that, AzureWebJobsStorage
cannot be found in the web.config
file. To fix your problem, navigate to your bot in azure portal and click on app settings from the left blade. There you will find a setting with the key AzureWebJobsStorage
.
Copy the value of the setting and paste that in the web.config
file as :
<configuration>
<appSettings>
<!-- update these with your BotId, Microsoft App Id and your Microsoft App Password-->
<add key="BotId" value="YourBotId" />
<add key="MicrosoftAppId" value="" />
<add key="MicrosoftAppPassword" value="" />
<add key="QnaSubscriptionKey" value="" />
<add key="QnaKnowledgebaseId" value="" />
<add key="AzureWebJobsStorage" value="copied value from azure portal" />
</appSettings>
Update:
To answer your further question posted in the comments,
I am redirected to a blank page in my browser, with the address localhost:3984 and a text where you can read QnABot Template, followed by some links
Indicates that the bot is working perfectly now and it is in fact the expected behavior. To test the bot locally, you need to use Bot Emulator. Follow the steps mentioned in the link and test the bot. Also you could go through the bot framework links, as that will give you more clarity on Microsoft Bot Framework.
Update 2:
As per your screenshots posted, I think you have changed the Global.asax
file.
The code for registering TableBotDataStore
should be exactly
var store = new TableBotDataStore(ConfigurationManager.AppSettings["AzureWebJobsStorage"]);
No change at all to this.
Secondly as mentioned by Fei Han :
The
Utils.GetAppSetting(string key)
method is for bots running on Azure, if you’d like to run your bot application on local and access settings from your web.config file, you can useConfigurationManager.AppSettings[“your_key”]
to replaceUtils.GetAppSetting(“your_key”)
in your QnAMakerDialog.
The second screenshots shows that you still have Utils.GetAppSetting(“your_key”)
in your code. Replace it to :
var qnaKBId = ConfigurationManager.AppSettings["QnAKnowledgebaseId"];
and so on for other places as well.
Upvotes: 4
Reputation: 27793
the error System.ArgumentNullException: 'Value cannot be null.
As Ashwin Kumar mentioned, you should include the name/value pairs for "AzureWebJobsStorage"
in your web.config file for your bot application.
System.FormatException: 'Settings must be of the form "name=value".
Please check if you get the value ConfigurationManager.AppSettings["AzureWebJobsStorage"]
and pass a valid connection string to initiate TableBotDataStore, not just pass the key "AzureWebJobsStorage"
.
I need to do some alterations and tests in Bot Framework Emulator (using V4) and, to do so, download and run locally my bot
The Utils.GetAppSetting(string key) method is for bots running on Azure, if you’d like to run your bot application on local and access settings from your web.config file, you can use ConfigurationManager.AppSettings[“your_key”] to replace Utils.GetAppSetting(“your_key”) in your QnAMakerDialog, like this:
//var qnaKBId = Utils.GetAppSetting("QnAKnowledgebaseId");
var qnaKBId = ConfigurationManager.AppSettings["QnAKnowledgebaseId"];
Upvotes: 1