I have implemented SqlBotDataStore for bot storage but the LoadAsync method is silently failing. This is in the MessageController's POST. No exceptions are thrown anywhere, it just stops at this line, the chat bot continues as if nothing ever happened but storage does not work:
var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
var key = Address.FromActivity(activity);
try
{
var userData = await botDataStore.LoadAsync(key, BotStoreType.BotPrivateConversationData, CancellationToken.None);
userData.SetProperty<Translator>("translator", new Translator());
userData.SetProperty<bool>("autoDetectLanguage", true);
userData.SetProperty<bool>("autoTranslateToBot", true);
userData.SetProperty<bool>("autoTranslateToUser", true);
await botDataStore.SaveAsync(key, BotStoreType.BotPrivateConversationData, userData, CancellationToken.None);
}
catch (HttpException e)
{
Debug.WriteLine(e.Message);
}
I cannot seem to get past this and unfortunately don't have any more information because literally no error or anything happens here. When debugging it just never goes to the next line and continues execution silently.
Based on this github sample using Azure Sql Storage to store the bot state, I modify the sample with following updates and do a test, which work for me. You can compare the sample with your implementation to find differences.
In MessagesController:
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
if (activity.Text == "savetest")
{
var message = activity as IMessageActivity;
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
var key = Address.FromActivity(activity);
try
{
var userData = await botDataStore.LoadAsync(key, BotStoreType.BotPrivateConversationData, CancellationToken.None);
//userData.SetProperty<Translator>("translator", new Translator());
userData.SetProperty<bool>("autoDetectLanguage", true);
userData.SetProperty<bool>("autoTranslateToBot", true);
userData.SetProperty<bool>("autoTranslateToUser", true);
await botDataStore.SaveAsync(key, BotStoreType.BotPrivateConversationData, userData, CancellationToken.None);
await botDataStore.FlushAsync(key, CancellationToken.None);
}
catch (HttpException e)
{
Debug.WriteLine(e.Message);
}
}
}
await Conversation.SendAsync(activity, () => new Dialogs.EchoDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
In EchoDialog:
var tval = context.PrivateConversationData.GetValueOrDefault<bool>("autoTranslateToBot", false);
await context.PostAsync("You said: " + message.Text + $"; autoTranslateToBot is {tval.ToString()}");
context.Wait(MessageReceivedAsync);
Test result:
Related
im trying to send a HTTP POST request from xamarin forms app to a webservice API on ASP.NET MVC, However, when i do it, i get status code 500 back from the server. I suspect it has something to do with the values in sending to API but i have not been able to figure it out.
Anyhelp is much appeciated
here is the
WEB API CODE
public void LogInFromMobile([FromBody] List<Creds> detail)
{
......
}
here is the
XAMARIN-FORMS APP CODE
public async void Button_Clicked(object sender, EventArgs e)
{
try
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Creds cr = new Creds();
cr.username = user.Text;
cr.password = pass.Text;
List<Creds> cred = new List<Creds>();
cred.Add(cr);
string url = #"http://IPHERE/LoginWebService.asmx/LogInFromMobile";
string json = JsonConvert.SerializeObject(cred);
HttpContent content = new StringContent(json);
var response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode)
{
await DisplayAlert("Alert", "Success", "Ok");
return;
}
else
{
await DisplayAlert("Alert", "Error", "Ok");
return;
}
}
}
catch(Exception ex)
{
await DisplayAlert("", ex.Message, "ok");
}
}
Here is the code that works but it doesn't wait until the completion. How do I make sure the file has been saved?
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
ExecutablePath = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
Headless = false,
});
var page = (await browser.PagesAsync()).First();
page.Response += async (object sender, ResponseCreatedEventArgs e) =>
{
if (e.Response.Url.Contains(".mp4"))
{
byte[] buff = await e.Response.BufferAsync();
File.WriteAllBytes($"{DateTime.UtcNow.ToFileTime()}.mp4", buff);
}
};
await page.GoToAsync("https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_480_1_5MG.mp4");
await Task.Delay(30000);
Here, just wrote it:
public static async Task<FileInfo> DownloadFileAsync(string url)
{
try
{
await _page.GoToAsync(url);
}
catch (NavigationException)
{
// Trying to open a file page throws navigation exception, should be ignored
}
await _page.WaitForNetworkIdleAsync();
while (Directory.GetFiles(_downloadDirectory, "*.crdownload", SearchOption.AllDirectories).Length > 0)
{
await Task.Delay(250);
}
for (int i = 0; i < 100; i++)
{
var finishedFiles = (new DirectoryInfo(_downloadDirectory)).GetFiles();
var downloadedFile = finishedFiles.OrderByDescending(f => f.LastWriteTime).FirstOrDefault();
if (downloadedFile != null)
{
return downloadedFile!;
}
await Task.Delay(250);
}
throw new Exception($"Download failed for: {url}");
}
I am trying to capture an image/pick up an image from gallery in Xamarin Forms app. I have installed the nuget manager > Birdie.MediaPlugin. During On click on the button in the Register page throws below error;
Plugin.Media.Abstractions.MediaPermissionException: <Timeout exceeded getting exception details Could someone please advise where should we add persmission in Xamarin.Forms app ?
// Register.xaml:
<Image x:Name="imageDisplay" />
<Button x:Name="uploadButton"
Text="Upload Image" Clicked="UploadButton_Clicked"/>
// PlayerDetails.cs
public ImageSource Source { get; internal set; }
//Register.xaml.cs
PlayerDetails myDetails;
public Register(PlayerDetails playD)
{
InitializeComponent();
BindingContext = myDetails;
}
private async void UploadButton_Clicked(object sender, EventArgs e)
{
//myDetails.Image = new Image();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
return;
}
var status = await GetPermissions();
if(status == true)
{
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
Directory = "Sample",
Name = "flower1.jpg"
});
if (file == null)
return;
await DisplayAlert("File Location", file.Path, "OK");
myDetails.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
}
else
{
await DisplayAlert("Permissions Denied", "Unable to take photos.", "OK");
//On iOS you may want to send your user to the settings screen.
if (Device.RuntimePlatform == Device.iOS)
CrossPermissions.Current.OpenAppSettings();
}
}
//I have split the permission function as below;
public static async Task<bool> GetPermissions()
{
bool permissionsGranted = true;
var permissionsStartList = new List<Permission>()
{
Permission.Location,
Permission.LocationAlways,
Permission.LocationWhenInUse,
Permission.Storage,
Permission.Camera
};
var permissionsNeededList = new List<Permission>();
try
{
foreach (var permission in permissionsStartList)
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
if (status != PermissionStatus.Granted)
{
permissionsNeededList.Add(permission);
}
}
}
catch (Exception ex)
{
Console.WriteLine("Nice, exception! " + ex);
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(permissionsNeededList.ToArray());
try
{
foreach (var permission in permissionsNeededList)
{
var status = PermissionStatus.Unknown;
//Best practice to always check that the key exists
if (results.ContainsKey(permission))
status = results[permission];
if (status == PermissionStatus.Granted || status == PermissionStatus.Unknown)
{
permissionsGranted = true;
}
else
{
permissionsGranted = false;
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine("Last, exception! " + ex);
}
return permissionsGranted;
}
You can update your OnClick event code to add the permissions logic as well:
var cameraStatus = await CrossPermissions.Current.CheckPermissionStatusAsync<CameraPermission>();
var storageStatus = await CrossPermissions.Current.CheckPermissionStatusAsync<StoragePermission>();
if (cameraStatus != PermissionStatus.Granted || storageStatus != PermissionStatus.Granted)
{
cameraStatus = await CrossPermissions.Current.RequestPermissionAsync<CameraPermission>();
storageStatus = await CrossPermissions.Current.RequestPermissionAsync<StoragePermission>();
}
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
return;
}
if (cameraStatus == PermissionStatus.Granted && storageStatus == PermissionStatus.Granted)
{
var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions
{
Directory = "Sample",
Name = "flower1.jpg"
});
if (file == null)
return;
await DisplayAlert("File Location", file.Path, "OK");
myDetails.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
}
else
{
await DisplayAlert("Permissions Denied", "Unable to take photos.", "OK");
//On iOS you may want to send your user to the settings screen.
if (Device.RuntimePlatform == Device.iOS)
CrossPermissions.Current.OpenAppSettings();
}
Note:It will become a long function so I recommend breaking it up into different functions.
Please tell me what is wrong.
public void ConfigureAuth(IAppBuilder app)
{
var mo = new MicrosoftAccountAuthenticationOptions();
mo.ClientId = "xxxxxxxxxxxxxxxxx";
mo.ClientSecret = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
mo.Scope.Add("wl.basic"); // No effect if this commented out
mo.Scope.Add("wl.emails");
// IF I COMMENT NEXT TWO PROPERTIES, USER IS AUTHENTICATED, BUT THE DB IS NOT
// UPDATED. LEAVE THEM AND THE REDIRECT FROM MSLIVE ENDS ON LOGIN PAGE
mo.SignInAsAuthenticationType = "External";
mo.Provider = new MicrosoftAccountAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
// Set breakpoint here to see the context.Identity.Claims HAS CLAIMS DESIRED.
// SO IT APPEARS TO ME Nothing to do here but verify they exist in the debugger.
//(context.Identity.Claims).Items ARE:
//{http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: xxxxxxxxx}
//{http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: yyyy yyyyy}
//{urn:microsoftaccount:id: xxxxxxxx}
//{urn:microsoftaccount:name: yyyy yyyyy}
//{http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: xxxxxxxx#hotmail.com}
return Task.FromResult(0);
}
};
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseMicrosoftAccountAuthentication(mo);
}
A reasonable expectation asserts that the framwework will transparently handle the addition of a Scope to the default *AuthenticationOptions. Subsequently, wrt the MVC5 template, the developer can extract and persist Claims in ExternalLoginConfirmation code. Another reasonable expectation is that the framework will transform incoming standard ClaimTypes into Claims in the ClaimsIdentity exposed by the framework.
I am very glad source code is available MicrosoftAccountAutheticationHandler.cs, and I will check it to solve this; lacking a response. Best wishes to Katana as the documentation and the framework are maturing. Is there a way for the framework to help the developer spot config issues?.
I would have agreed with you if we both had not hit the same logical brick wall of reasonning ....
I think it is something to do with a detached Owin Security Context while the web application operates in a seperate Context and you have to 'seed' the web one. So what I've deduced is this:
in Startup.Auth.cs
var microsoftOptions =
new Microsoft.Owin.Security.MicrosoftAccount.MicrosoftAccountAuthenticationOptions
{
CallbackPath = new Microsoft.Owin.PathString("/Callbacks/External"),//register at oAuth provider
ClientId = "xxxx",
ClientSecret = "yyyyyyyyyyyyyyyyy",
Provider = new Microsoft.Owin.Security.MicrosoftAccount.MicrosoftAccountAuthenticationProvider
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new Claim(providerKey, context.Identity.AuthenticationType));
context.Identity.AddClaim(new Claim(ClaimTypes.Name, context.Identity.FindFirstValue(ClaimTypes.Name)));
return System.Threading.Tasks.Task.FromResult(0);
}
}
};
microsoftOptions.Scope.Add("wl.basic");
microsoftOptions.Scope.Add("wl.emails");
app.UseMicrosoftAccountAuthentication(microsoftOptions);
and in AccountController:
[AllowAnonymous]
public async Task<ActionResult> oAuthCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
if (User.Identity.IsAuthenticated)
return RedirectToAction("Index", "Manage");
else
return RedirectToAction("Login");
}
var currentUser = await UserManager.FindAsync(loginInfo.Login);
if (currentUser != null)
{
await StoreExternalTokensOnLocalContext(currentUser);
}
//.... rest as same as per AspNet Sample project.
}
private async Task StoreExternalTokensOnLocalContext(ApplicationUser user)
{
if (user == null)
return;
var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
if (externalIdentity != null)
{
// Retrieve the existing claims for the user and add the FacebookAccessTokenClaim
var currentClaims = await UserManager.GetClaimsAsync(user.Id);
//var providerClaim = externalIdentity.FindFirstValue("provider") ?? string.Empty;
await StoreClaim("provider", user.Id, externalIdentity);
await StoreClaim("FacebookId", user.Id, externalIdentity);
await StoreClaim("image", user.Id, externalIdentity);
await StoreClaim("link", user.Id, externalIdentity);
await StoreClaim(ClaimTypes.Name, user.Id, externalIdentity);
await StoreClaim(ClaimTypes.Email, user.Id, externalIdentity);
var addedClaims = await UserManager.GetClaimsAsync(user.Id);
}
}
private async Task StoreClaim(string typeName, string userId, ClaimsIdentity externalIdentity)
{
var providerClaim = externalIdentity.Claims.FirstOrDefault(c => c.Type.Equals(typeName));
if (providerClaim == null)
return;
var previousClaims = await UserManager.GetClaimsAsync(userId);
if (previousClaims.IndexOf(providerClaim) >= 0)
return;
var idResult = await UserManager.AddClaimAsync(userId, providerClaim);
}
When I use HttpClient.GetAsync(url),but the url is not a reachable address,but it always redirect to another address,and it return a statuecode with ok.
var httpClient = new HttpClient(handler);
httpClient.DefaultRequestHeaders.ExpectContinue = false;
//using ()
{
HttpResponseMessage response = new HttpResponseMessage();
response = await httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync();
Debug.WriteLine(response.StatusCode.ToString());
}
else
{
// problems handling here
Debug.WriteLine(
"Error occurred, the status code is: {0}",
response.StatusCode
);
}
}