Cannot link bot to bot framework emulator - c#

This is my current screen when I have tried to load my bot into the bot Framework Emulator:
And this is what I have entered within the setting for my bot:
But for some reason my bot framework emulator remains empty.
I have also tried setting the Endpoint URL to http://localhost:3979/api/messages but no luck. I am trying to run this locally off of visual studio.
Any help with this is much appreciated!

L. Full, if you followed the instructions from the Azure portal to create a QnA bot from a template, you will need to tweak the code a bit to have it work locally, and in turn work in the emulator.
After you have created your bot using the template (which it sounds like you have done), in ABS, going to Build (under Bot Management)> "Download zip file", you get a copy of your project locally.
If you look at the template Bot code, it works in Azure, because in summary, it is accessing your QnA credentials from within your Application Settings inside the Azure portal, but locally you will need to put the credentials somewhere like your .config file.
Ultimately what we'll have to do now is plug in your QnA credentials into your .config file of your project, as this is not automatically downloaded into the code when you download the zip.
Below I'm just using the QnA Template bot that you can find in the Azure portal (Create Resource > AI + Machine Learning > Web App Bot with Bot template of "Question and Answer")
In Web.config add key-value pairs for AzureWebJobsStorage (if using), QnAAuthKey, QnAKnowledgebaseId, and QnAEndpointHostName
Your own credential values can be found under Application Settings of the Azure portal
<appSettings>
<!-- update these with your Microsoft App Id and your Microsoft App Password-->
<add key="MicrosoftAppId" value="" />
<add key="MicrosoftAppPassword" value="" />
<add key="AzureWebJobsStorage" value="DefaultEndpointsProtocol=https...."/>
<add key="QnAAuthKey" value="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
<add key="QnAKnowledgebaseId" value="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
<add key="QnAEndpointHostName" value="https://YOURQNA.azurewebsites.net/qnamaker" />
<add key="QnASubscriptionKey" value="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" />
</appSettings>
In your Dialog (QnA template as of 7/5/18 has default dialog file named BasicQnAMakerDialog.cs), instead of Utils (default in template), we'll use ConfigurationManager.AppSettings["KeyName"] to access the values you just placed in your Web.config:
Below you can see I've changed the variables (commented out) in QnA template to retrieve values using ConfigurationManager.AppSettings. You may also have to edit the variables in your if-statement as well, depending on the logic your own app needs.
In Root Dialog
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var message = await result as Activity;
// OLD
//var qnaAuthKey = GetSetting("QnAAuthKey");
//var qnaKBId = Utils.GetAppSetting("QnAKnowledgebaseId");
//var endpointHostName = Utils.GetAppSetting("QnAEndpointHostName");
// NEW
var qnaAuthKey = ConfigurationManager.AppSettings["QnAAuthKey"];
var qnaKBId = ConfigurationManager.AppSettings["QnAKnowledgebaseId"];
var endpointHostName = ConfigurationManager.AppSettings["QnAEndpointHostName"];
// 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.");
}
}
In the children Dialogs that get called by your root (BasicQnAMakerDialog for example), be sure to also replace anything that calls for a QnA key with ConfigurationManager.AppSettings["KeyName"].
For example in BasicQnAMakerDialog:
[Serializable]
public class BasicQnAMakerDialog : QnAMakerDialog
{
static readonly string qnaAuthKey = ConfigurationManager.AppSettings["QnAAuthKey"];
static readonly string qnaKBId = ConfigurationManager.AppSettings["QnAKnowledgebaseId"];
static readonly string endpointHostName = ConfigurationManager.AppSettings["QnAEndpointHostName"];
public BasicQnAMakerDialog() : base(new QnAMakerService(
new QnAMakerAttribute
(
qnaAuthKey,
qnaKBId,
"No good match in FAQ.",
0.5,
1,
endpointHostName
)))
{
}
}

One of the possible solution you can do is:
Right click your project in Solution Explorer in Visual Studio.
Click Properties.
Go to Debug Tab. Scroll down a little bit you will see Web Server Settings.. Check the URL and set it to new port. For example if it is: http://localhost:3798 change it to http://localhost:3979 or vice-versa. Changing the port number might solve your issue. Press Ctrl + S to save it.
Build the solution and re-run the project without Debugging (Ctrl +F5).
Open your Bot Framework Emulator and enter the URL that you mentioned in step 3 above.
Note: This doesn't mean it will 100% work, but this is one of the solution that I come across. I had the same problem and I solved it same way.
Hope this helps.

Related

How to get a MSAL access token for SharePoint Online in a federated environment the non-interactive way in a non-interactive .Net console app?

The task as simple as to have a scheduled .NET console app which will download a file from SharePoint Online on a regular basis using AD domain user account.
If I use recommended way
var token = publicApplication.AcquireTokenByIntegratedWindowsAuth(scopes).ExecuteAsync().Result;
I'm getting
UriFormatException: Invalid URI: The hostname could not be parsed.
What does it mean? Which URI, hostname? Should I override something somewhere or add some special parameter?
I've googled thru this stuff a lot, and I have no idea where to look further, any advice will be appreciated.
P.S. I have no permissions to do anything on SharePoint side, I'm not a SP admin. I just have access to specific folder on the site from which I'm downloading the file. And also I have a code which works interactively:
WebRequest.DefaultWebProxy = WebRequest.GetSystemWebProxy();
WebRequest.DefaultWebProxy.Credentials = CredentialCache.DefaultNetworkCredentials;
var scopes = new string[] { "https://tenant.sharepoint.com/.default" };
var options = new PublicClientApplicationOptions()
{
TenantId = "tenant.com",
ClientId = "{872cd9fa-d31f-45e0-9eab-6e460a02d1f1}",//known Visual Studio Id
};
var publicApplication = PublicClientApplicationBuilder.CreateWithApplicationOptions(options).Build();
var token = publicApplication.AcquireTokenInteractive(scopes).WithLoginHint("name.surname#tenant.com").ExecuteAsync().Result;
But it shows a browser window
No questions asked, pop-up disappear, and I get the token which is used further to download a file from SPOnline using /_api/web/GetFileByServerRelativeUrl(' stuff.
So just run the app, see the popup, get the file downloaded. No interaction needed.
But this approach doesn't work if I put this routine really non-interactive:
Showing a modal dialog box or form when the application is not running in UserInteractive mode is not a valid operation. Specify the ServiceNotification or DefaultDesktopOnly style to display a notification from a service application.
Turns out the non-interactive way is only possible using tenant-side registered application. Implemented using certificate authentication.
But surprisingly the token obtained by ConfidentialClientApplicationBuilder doesn't work the way I wanted/expected (scopes/user impersonation issues). So now we use Graph client approach.
This is the only way which works for me (.NetFramework 4.7.2):
using Azure.Identity;
using Microsoft.Graph;
//...
static async Task GetFile(GraphServiceClient graphClient, string fileName2get)
{
var fileitem = graphClient
.Sites["SiteGuidYouMayGetBy /sites/[your site name]/_api/site/id"]
.Drives["CrazyLongDriveIdYouMayGetByEnumeratingDrivesHere"]
.Root
.ItemWithPath($"/Path To The File starting from Drive Root/{fileName2get}")
.Content
.Request().GetResponseAsync();
var stream = fileitem.GetAwaiter().GetResult();
using (var fileStream = System.IO.File.Create($"C:/Temp/{fileName2get}"))
{
await stream.Content.CopyToAsync(fileStream);
}
}

Xamarin iOS Program: HealthKit User Permission Dialog not Shown

I follow the tutorial here (Code from Git Code repo here) for Xamarin building the first ios health-kit app but the permission dialog is not shown in the user's end. Both keywords NSHealthShareUsageDescription and NSHealthUpdateUsageDescription are in the info.plist. The code asking permission is
private void ValidateAuthorization ()
{
//Request / Validate that the app has permission to store heart-rate data
var heartRateId = HKQuantityTypeIdentifierKey.HeartRate;
var heartRateType = HKObjectType.GetQuantityType (heartRateId);
var typesToWrite = new NSSet (new [] { heartRateType });
//We aren't reading any data for this sample
var typesToRead = new NSSet ();
healthKitStore.RequestAuthorizationToShare (
typesToWrite,
typesToRead,
ReactToHealthCarePermissions);
}
If I run the app on iOS simulator, the output reports "Missing com.apple.developer.healthkit entitlement" error.
I have enabled the HealthKit permission in the Entitlements.plist file and selected the option accordingly.
HKWork[935:10236] [default] connection error: Error
Domain=com.apple.healthkit Code=4 "Missing
com.apple.developer.healthkit entitlement."
UserInfo={NSLocalizedDescription=Missing com.apple.developer.healthkit
entitlement.} Thread started: #2 HKWork[935:10236] [auth] Failed to
determine authorization status: Error Domain=com.apple.healthkit
Code=4 "Missing com.apple.developer.healthkit entitlement."
UserInfo={NSLocalizedDescription=Missing com.apple.developer.healthkit
entitlement.} HKWork[935:10241] [plugin] AddInstanceForFactory: No
factory registered for id <CFUUID 0x60000167c9a0>
F8BB1C28-BAE8-11D6-9C31-00039315CD46
Any amount of help would be appreciated.
I found my problem is: at Project Options->iOS Bundle signing, I need to configure both the platform of iPhoneSimulator and the platform of iPhone (select the dropdown menu to configure both). Both the signing identity and provisioning profile can't be automatic. The custom Entitlements needs to include Entitlemets.plist. I didn't set under the platform of iPhone. This change enables poping up permission page when simulating on iPhone, but not on the simulator.
Meanwhile, in Entitlement.pList, enabling capability of HealthKit might change the value of the key "com.apple.developer.healthkit". This might be a bug in Visual Studio and just don't manually change the value back because that will disable the healthkit capability.

.cscfg file gives error when i specify <Setting name="serilog:write-to:AzureDocumentDB.endpointUrl" />

When I publish my API project to Azure here is the error what i'm getting.
Is there any way to resolve this issue and here is the code and the problem comes when this symbol ":" is init.
Here are some more details.
It's a web API Project
Version 4.6
Locally it's running without any issues but when it comes to release automation I should be able to change the value of endpointurl , key, and TTL manually so that I need to modify .csfg and .csdef file environment to environment. When i do that .csdef does not support that colon mark ":" so the build fails.
Expecting : Build is successful so that the log works as expected.
Actual : Build fails and log is not working as expected.
As you mentioned that ServiceDefinition:NamedElementNameString doesn't allow ':' (colon) in name. But we could add it with Azure friendly name. Then we could get it with following code. I also do a demo on my side, it works as expected.
var endpoint = RoleEnvironment.GetConfigurationSettingValue("endpointUrl");
var authorizationKey = RoleEnvironment.GetConfigurationSettingValue("authorizationKey");
var logger = new LoggerConfiguration()
.WriteTo.Console() //if no writeto.console there is no document in documentdb
.WriteTo.AzureDocumentDB(endpoint, authorizationKey)
.CreateLogger();
logger.Information("Tom Test");//log demo
About .csdef configuration please refer to the screenshot.
We could get more information from Configure Azure cloud service roles with Visual Studio
Check from Azure Portal:
Related serilog sdk
It seems this is not supported.
ServiceDefinition:NamedElementNameString doesn't allow ':' (colon) in name
So that I implemented custom configuration values and extract the values at run-time when the logger is initialized.
Here is the implementation.
.cscfg, .csdef, and web.config contains
<add key="LogEndpointUrl" value="xxxxxx/" />
<add key="LogAuthorizationKey" value="xxxxxxxxxxxxxxx=" />
<add key="LogTTL" value="1" />
When initializing got the values as follows from web.config
var endpoint = Common.Configuration.GetSetting(Constants.AppSettings.LogEndpointUrl);
var authorizationKey = Common.Configuration.GetSetting(Constants.AppSettings.LogAuthorizationKey);
int ttl = (int)Convert.ToInt64((Common.Configuration.GetSetting(Constants.AppSettings.LogTTL)));
And then
Log.Logger = new LoggerConfiguration().ReadFrom.AppSettings().WriteTo.AzureDocumentDB(endpoint, authorizationKey,timeToLive: ttl).CreateLogger();
// Used to debug serilog itself and confirm it is writing entries to document db
Serilog.Debugging.SelfLog.Enable(Console.Out);
var errorOrInformation = new Dictionary<string, string>();
errorOrInformation.Add(Constants.LoggingProperties.PartitionKey, logMetadata.PartitionKey);
errorOrInformation.Add(Constants.LoggingProperties.RowKey, logMetadata.RowKey);
//Add as many items as you want
Log.Verbose("Log Information Message {Information}", errorOrInformation);
// Also good idea to force flush of log entries before the app ends
Log.CloseAndFlush();

How to setup buttons with "imBack" type in Slack channel using ms bot builder

I've developed few bots using ms botbuilder, there was no problems with Buttons with "imBack" type on Skype, FB, Telegram and web chat.
However trying to make it work on Slack i found (and seems like its not documented) that you need extra configuring of Interactive Messages in APP admin panel. So here's my questions regarding this issue:
is it true that its the only way?
If so what's the real reason for that, everything works just fine in all other channels.
Is there a way to setup it programmatically, cos it will be real bad for distribution of bot?
even when i setup endpoint in admin panel looks like it makes request that is barely compatible with how ms builder works (it sends some GET where we need post with relevant info)
Code sample:
...
var reply = activity.CreateReply("hi, can i ask you few question?");
reply.Attachments = new List<Attachment>(){};
var buttonSelect = new CardAction
{
Value = $" /startCommand",
Type = "imBack",
Title = "ok, ask me"
};
var cardForButton = new ThumbnailCard { Buttons = new List<CardAction> { buttonSelect } };
reply.Attachments.Add(cardForButton.ToAttachment());
await connector.Conversations.CreateDirectConversationAsync(botaccount, userAccount, reply);
...
2 things you can try that are possible solutions
You probably did, but did you activate interactive messages in your slack api dashboard?
There is a token (Verification Token) that you need to get from the oauth section of the Slack api site for your app. you need to include that with the other information here https://slack.botframework.com/Dev/?botId={yourBotID}
Actually all needed to be done is put https://slack.botframework.com/api/Actions in Request URL when enabling Interactive Messages in Slack, not sure that it was documented earlier on Ms bot framework panel, but it is now. Issue resolved.

Unable to get some user account information in UWP app - In-premise active directory (Not Azure AD)

In a UWP app, I have enabled the User Account Information capability.
I need to get the username and the domain name (each of them separately) of the currently logged on user (The users are logged on with an in-premise Active Directory account - Not Azure AD).
For example, the user would log in to the Active Directory domain domain1 using the username user1. i.e. domain1\user1.
I am using the following code to try to get the required details:
IReadOnlyList<User> users = await User.FindAllAsync();
var user = users.FirstOrDefault();
// get domain
var data1 = await user.GetPropertyAsync(KnownUserProperties.DomainName);
string strDomainName = (string)data1;
// get username
var data2 = await user.GetPropertyAsync(KnownUserProperties.AccountName);
string strUserName = (string)data2;
Issues:
strDomainName returns domain1.com\user1. Why does this include the .com part for all our domains? On c# winforms applications we can easily get domain1\user1 without any issue.
strUserName returns an empty string. i.e. "". Why does this not return any value?
I also checked the following:
KnownUserProperties.FirstName returns an empty string. i.e. ""
KnownUserProperties.LastName returns an empty string. i.e. ""
KnownUserProperties.PrincipalName returns an empty string. i.e. ""
KnownUserProperties.ProviderName returns an empty string. i.e. ""
KnownUserProperties.GuestHost returns an empty string. i.e. ""
Is there anything else I need to enable similar to the User Account Information capability? Or are there any other permissions that need to be granted to the app to get this information?
I understand that I can get the value of strDomainName and perform string functions to get what I need. But I want to know if there is any way to get this information directly. Also curious why KnownUserProperties.AccountName and other properties listed above such as FirstName, LastName etc. just returns an empty string.
I am running the following version of Windows:
I have the following set as the Target version and Min Version:
To verify, I also tested with the UserInfo sample project by Microsoft from GitHub and I got the following output:
The following was automatically enabled in Settings > Privacy > Account Info.
TestApp is the app I tried with and User Info C# Sample is the sample app from GitHub:
Update:
After also enabling the Enterprise Authentication capability, KnownUserProperties.PrincipalName does return the expected value. i.e. user1#domain1.com.
However, other properties listed above such as FirstName, LastName etc. just returns an empty string and I am still unable to find any property that returns domain1\user1 (without the .com part)
The Information you are trying to access are not reliable, as they (as you mentioned) do not have to be set and also they can be restricted access to via privacy settings in general.
I had a similar problem and would advise you to use the UWP OneDrive API
using Microsoft.OneDrive.Sdk;
and then request wl.basic scope. This scope contains at least a reliable username.
public static async Task<bool> GetAuthenticatedClient()
{
string oneDriveConsumerBaseUrl = "https://api.onedrive.com/v1.0";
var scopes = new List<string>
{
"wl.signin",
"wl.basic",
};
Task authTask;
var onlineIdAuthProvider = new OnlineIdAuthenticationProvider(scopes.ToArray());
authTask = onlineIdAuthProvider.RestoreMostRecentFromCacheOrAuthenticateUserAsync();
oneDriveClient = new OneDriveClient(oneDriveConsumerBaseUrl, onlineIdAuthProvider);
AuthProvider = onlineIdAuthProvider;
try
{
await authTask;
if (!AuthProvider.IsAuthenticated)
{
return false;
}
}
catch (ServiceException exception)
{
// Swallow the auth exception but write message for debugging.
//Debug.WriteLine(exception.Error.Message);
return false;
}
return true;
}
As for the domain, I'm not sure, but you could try to access it via Environment.UserDomainName like described on MSDN or with Windows.Networking.Connectivity.NetworkInformation.GetHostNames() like described here.
I found another possible solution to this. If you are still debugging this locally or the app was already installed on the target machine, I could enable the capabality User Account Information but this was not propagated to the actual installed app:
when your search for your app name in the start menu and then right click the entry and select App settings you get something like this:
As soon as I enabled the highlighted option (basically it says 'Account information') it worked.

Categories