I use Xamarin Auth to authenticate with OneDrive in my android app. I assume this would work, but I have the issue that when the activity for the login prompt is opened the programm will just continue and not wait for the auth to finish.
How can I wait until it's closed or wrap this in a other way async?
Code:
private IDictionary<string, string> authenticationResponseValues;
protected override async Task<AccountSession> GetAuthenticationResultAsync()
{
await Task.Run(() => ShowWebView());
return new AccountSession(authenticationResponseValues, this.ServiceInfo.AppId, AccountType.MicrosoftAccount)
{
CanSignOut = true
};
}
private void ShowWebView()
{
var auth = new OAuth2Authenticator(
clientId: MSA_CLIENT_ID,
scope: string.Join(",", scopes),
authorizeUrl: new Uri(GetAuthorizeUrl()),
redirectUrl: new Uri(RETURN_URL));
auth.Completed += SetAccountInfos;
var intent = auth.GetUI(Application.Context);
intent.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(intent);
}
private void SetAccountInfos(object sender, AuthenticatorCompletedEventArgs eventArgs)
{
if (eventArgs.IsAuthenticated)
{
Debug.WriteLine(eventArgs);
Debug.WriteLine(eventArgs.Account == null ? "IS NULL" : "IS NOT NULL");
if (eventArgs.Account != null)
{
OAuthErrorHandler.ThrowIfError(eventArgs.Account.Properties);
authenticationResponseValues = eventArgs.Account.Properties;
}
}
}
I dont think using async tactic is reasonable, because app runs before login result returns.
Try to use sync way. Make a login page. If success, then switch to your real app.
I found a solution. Here my code:
await ShowWebView();
return new AccountSession(authenticationResponseValues, ServiceInfo.AppId,
AccountType.MicrosoftAccount)
{
CanSignOut = true
};
private Task<bool> ShowWebView()
{
var tcs = new TaskCompletionSource<bool>();
var auth = new OAuth2Authenticator(OneDriveAuthenticationConstants.MSA_CLIENT_ID, string.Join(",", OneDriveAuthenticationConstants.Scopes), new Uri(GetAuthorizeUrl()),
new Uri(OneDriveAuthenticationConstants.RETURN_URL));
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
OAuthErrorHandler.ThrowIfError(eventArgs.Account.Properties);
authenticationResponseValues = eventArgs.Account.Properties;
tcs.SetResult(true);
}
};
var intent = auth.GetUI(Application.Context);
intent.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(intent);
return tcs.Task;
}
And the link to the class in the repo: https://github.com/Apply-Solutions/MoneyManager/blob/master/Src/MoneyManager.Droid/Src/AndroidAuthenticationProvider.cs
Related
I have a problem. scriptEventClick does not see the method in scriptGlobal.
How should I know that scriptGlobal is registered in JS so that I can later call EvaluateScriptAsPromiseAsync
public Task<bool> GetResultAfterPageLoad(string pageUrl)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
EventHandler<LoadingStateChangedEventArgs> onPageLoaded = null;
onPageLoaded = async (sender, args) =>
{
if (!args.IsLoading)
{
_browser.LoadingStateChanged -= onPageLoaded;
// initialization script
_browser.ExecuteScriptAsyncWhenPageLoaded(scriptGlobal);
// script for click button
JavascriptResponse responseClick = await _browser.EvaluateScriptAsPromiseAsync(scriptEventClick);
tcs.SetResult(_result);
}
};
_browser.LoadingStateChanged += onPageLoaded;
_browser.Load(pageUrl);
return tcs.Task;
}
where
scriptGlobal = "async function eventClick(){}";
scriptEventClick = "return eventClick();";
this solution works. but I think this is a bad answer. because I don't want to use delays in a loop
_browser.ExecuteScriptAsyncWhenPageLoaded(scriptGlobal);
JavascriptResponse responseGlobal = null;
do
{
responseGlobal = await _browser.EvaluateScriptAsync("eventClick");
await Task.Delay(100);
}
while (responseGlobal.Result == null);
JavascriptResponse responseClick = await _browser.EvaluateScriptAsPromiseAsync(scriptEventClick);
I am getting this error dialog even after logging in successfully using Microsoft login.
Here is the code to authenticate :
#region IMicrosoftLogin implementation
public async System.Threading.Tasks.Task<Xamarin.Auth.Account> LoginAsync()
{
window = UIApplication.SharedApplication.KeyWindow;
viewController = window.RootViewController;
var auth = new OAuth2Authenticator(
"key_here",//for non- prod
//for production
"openid email https://graph.microsoft.com/user.read",
new Uri("https://login.microsoftonline.com/common/oauth2/V2.0/authorize"),
new Uri("https://myapp_redirect_url"),// for non- prod
null
)
{
AllowCancel = true
};
auth.Completed += Microsoft_Auth_Completed;
var tcs1 = new TaskCompletionSource<AuthenticatorCompletedEventArgs>();
d1 = (o, e) =>
{
try
{
if (e.IsAuthenticated)
{
viewController.DismissViewController(true, null);
tcs1.TrySetResult(e);
}
else
{
viewController.DismissViewController(true, null);
}
}
catch (Exception)
{
tcs1.TrySetResult(new AuthenticatorCompletedEventArgs(null));
}
};
try
{
auth.Completed += d1;
if (viewController == null)
{
while (viewController.PresentedViewController != null)
viewController = viewController.PresentedViewController;
viewController.PresentViewController(auth.GetUI(), true, null);
}
else
{
viewController.PresentViewController(auth.GetUI(), true, null);
UserDialogs.Instance.HideLoading();
}
var result = await tcs1.Task;
return result.Account;
}
catch (Exception)
{
return null;
}
finally
{
auth.Completed -= d1;
}
//auth.Error += (object sender, AuthenticatorErrorEventArgs eventArgs) => {
// auth.IsEnabled = false;
//};
}
private void Microsoft_Auth_Completed(object sender, AuthenticatorCompletedEventArgs e)
{ /// Break point here is not getting triggered.
var authenticator = sender as OAuth1Authenticator;
if (authenticator != null)
{
authenticator.Completed -= Microsoft_Auth_Completed;
}
if (e.IsAuthenticated)
{
var a = e.Account;
}
else
{
}
}
Login async called on button click like this :
btnSignIn.Clicked += async (object sender, EventArgs e) =>
{
if (networkConnection != null && networkConnection.CheckNetworkConnection())
{
UserDialogs.Instance.ShowLoading("Loading", null);
var loginresult = await MicrosoftLogin.LoginAsync();
.....
MicrosoftLogin.cs
namespace projectnamescpace
{
public interface IMicrosoftLogin
{
Task<Account> LoginAsync();
}
}
Please help me.
I have already saw following link solutions and they aren't working for me.
https://forums.xamarin.com/discussion/5866/xamarin-auth-and-infinite-error-alerts
Authentication Error e.Message = OAuth Error = Permissions+error
https://forums.xamarin.com/discussion/95176/forms-oauth-error-after-authenticated-unable-to-add-window-token-android-os-binderproxy
The issue might be caused by the HostName been blocked because of Area Policy .
You could solve this by modifying the DNS (to 8.8.8.8 as an example) for your Mac as well.
Your device, Settings/Wi-Fi
Choose connected Wi-Fi pot
Press DHCP/DNS
Set to 8.8.8.8
Or you could connect phone to the VPN for your apps deployed to device to see corporate servers.
I'm trying to figure out, if it is possible send using Windows.Media.SpeechRecognition; args.Result.Text as parameter from UWP to Console application.
For example by following scenario I'm sending TextToSpeech(args.Result.Text); with args.Result.Text; value, where using Windows.Media.SpeechSynthesis; text-to-speech pronounces the recognition result each time when args.Result.Text; appears. textBlock2.Text = args.Result.Text; also displays result:
private async void ContinuousRecognitionSession_ResultGenerated(
SpeechContinuousRecognitionSession sender, SpeechContinuousRecognitionResultGeneratedEventArgs args)
{
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
textBlock1.Text = args.Result.Text;
TextToSpeech(args.Result.Text);
});
}
but if I'm trying to send args.Result.Text; as parameter to console application, included with UWP in Desktop-Bridge package:
private async void ContinuousRecognitionSession_ResultGenerated(
SpeechContinuousRecognitionSession sender, SpeechContinuousRecognitionResultGeneratedEventArgs args)
{
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
textBlock1.Text = args.Result.Text;
SendTTSResult(args.Result.Text);
});
}
to the requested function:
private async void SendTTSResult(string res)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
ApplicationData.Current.LocalSettings.Values["parameters"] = res;
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("Parameters");
}
});
}
Behavior of failure looks to me not really clear:
With first recognition result, it sends parameter to console application, which successfully loads, gets and displays this parameter. But with second request the problem backs away from this processing level, even if parameters sending function is unambiguously the cause of a failure SendTTSResult(args.Result.Text); function does not receives args.Result.Text but this happens already before function will comes in action, because preceding output display textBlock1.Text = args.Result.Text; also does not receives event anymore.
With async() => behavior is a bit different, it successfully receives event and sends value as parameter to console, in this case it happens 2-3 times from beginning of execution and voice requesting, then event disappears, when it is not even passed through SendTTSResult(string res), to imagine that the something in SendTTSResult(string res) does not allows pass string from recognition, but just stops, even if I put it in the end of TextToSpeech(string text) function, text to speech also stops receive event:
private async void SendTTSResult(string res)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async() =>
{
if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
ApplicationData.Current.LocalSettings.Values["parameters"] = res;
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("Parameters");
}
});
}
It looks like sending of args.Result.Text value as parameter with SendTTSResult(string res) function works fine, sends string successfully, but at the same time presence of this function in ContinuousRecognitionSession_ResultGenerated somehow affects receiving of event inside of it. At the same time behavior of ContSpeechRecognizer_HypothesisGenerated looks completely different, args.Hypothesis.Text event appears each time and result successfully passes as parameter with same SendTTSResult(string res).
What can prevent an event from being executed when the function of sending a parameter is involved in its process, and how to fix it if possible?
Full code of continuous speech recognition added to my question on Windows Dev Center Send speech recognition args.Result as parameter in UWP desktop-bridge package
EDIT 1: **************************************************************************************************
Behind parameter function, Console Connector.exe only shows parameter without running of any app or anything else:
static void Main(string[] args)
{
string result = Assembly.GetExecutingAssembly().Location;
int index = result.LastIndexOf("\\");
string rootPath = $"{result.Substring(0, index)}\\..\\";
if (args.Length > 2)
{
switch (args[2])
{
case "/parameters":
string parameters = ApplicationData.Current.LocalSettings.Values["parameters"] as string;
Console.WriteLine("Parameter: " + parameters);
Console.ReadLine();
break;
}
}
}
Packeage.appxmanifest:
<uap:Extension Category="windows.appService">
<uap:AppService Name="SampleInteropService" />
</uap:Extension>
<desktop:Extension Category="windows.fullTrustProcess" Executable="Connector\Connector.exe">
<desktop:FullTrustProcess>
<desktop:ParameterGroup GroupId="Parameters" Parameters="/parameters" />
</desktop:FullTrustProcess>
</desktop:Extension>
EDIT 2: **************************************************************************************************
I've tried SendTTSResult(SpeechRecogVal); with change of variable value:
private async void ContinuousRecognitionSession_ResultGenerated(
SpeechContinuousRecognitionSession sender, SpeechContinuousRecognitionResultGeneratedEventArgs args)
{
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
SpeechRecogVal = args.Result.Text;
});
}
but it is same behavior tbRec.Text = SpeechRecogVal; shows output successfully until I add SendTTSResult(SpeechRecogVal);,
private string _srVal;
public string SpeechRecogVal
{
get
{
return _srVal;
}
set
{
_srVal = value;
ValueChanged();
}
}
void ValueChanged()
{
tbRec.Text = SpeechRecogVal;
// SendTTSResult(SpeechRecogVal);
}
So, seems like problem is something between await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => and if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0)) and await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => of private async voidContinuousRecognitionSession_ResultGenerated(SpeechContinuousRecognitionSession sender, SpeechContinuousRecognitionResultGeneratedEventArgs args)
Also, I've tried:
private async void ContinuousRecognitionSession_ResultGenerated(
SpeechContinuousRecognitionSession sender, SpeechContinuousRecognitionResultGeneratedEventArgs args)
{
await SendTTSResult(args.Result.Text);
}
as Task:
async Task SendTTSResult(string res)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
ApplicationData.Current.LocalSettings.Values["parameters"] = res;
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("Parameters");
}
});
}
And it is also successful only with first request event instance response, then goes quite. So seems like ContinuousRecognitionSession_ResultGenerated is someway different from other options in Windows.Media.SpeechRecognition Namespace and not compatible with something in async Task SendTTSResult(string res) or rather with this code lines content:
ApplicationData.Current.LocalSettings.Values["parameters"] = args.Result.Text;
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("Parameters");
System.NullReferenceException occurs appservice disconnect scenario, Could you check the apservice's connection before send message?
For explain this, I create sample project that refer Stefanwick blog. And I also reproduce your issue when I does not invoke InitializeAppServiceConnection method in WPF client. If you want to send text to wpf, you could invoke Connection.SendMessageAsync method just like below SendMesssage click envent .
Capability
<Extensions>
<uap:Extension Category="windows.appService">
<uap:AppService Name="SampleInteropService" />
</uap:Extension>
<desktop:Extension Category="windows.fullTrustProcess" Executable="AlertWindow\AlertWindow.exe" />
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
</Capabilities>
WPF
private AppServiceConnection connection = null;
public MainWindow()
{
InitializeComponent();
InitializeAppServiceConnection();
}
private async void InitializeAppServiceConnection()
{
connection = new AppServiceConnection();
connection.AppServiceName = "SampleInteropService";
connection.PackageFamilyName = Package.Current.Id.FamilyName;
connection.RequestReceived += Connection_RequestReceived;
connection.ServiceClosed += Connection_ServiceClosed;
AppServiceConnectionStatus status = await connection.OpenAsync();
if (status != AppServiceConnectionStatus.Success)
{
MessageBox.Show(status.ToString());
this.IsEnabled = false;
}
}
private void Connection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
Application.Current.Shutdown();
}));
}
private async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
// retrive the reg key name from the ValueSet in the request
string key = args.Request.Message["KEY"] as string;
if (key.Length > 0)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
InfoBlock.Text = key;
}));
ValueSet response = new ValueSet();
response.Add("OK", "SEND SUCCESS");
await args.Request.SendResponseAsync(response);
}
else
{
ValueSet response = new ValueSet();
response.Add("ERROR", "INVALID REQUEST");
await args.Request.SendResponseAsync(response);
}
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
ValueSet response = new ValueSet();
response.Add("OK", "AlerWindow Message");
await connection.SendMessageAsync(response);
}
UWP
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
App.AppServiceConnected += MainPage_AppServiceConnected;
App.AppServiceDisconnected += MainPage_AppServiceDisconnected;
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
}
}
private async void MainPage_AppServiceDisconnected(object sender, EventArgs e)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Reconnect();
});
}
private void MainPage_AppServiceConnected(object sender, AppServiceTriggerDetails e)
{
App.Connection.RequestReceived += AppServiceConnection_RequestReceived;
}
private async void AppServiceConnection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
string value = args.Request.Message["OK"] as string;
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
InfoBlock.Text = value;
});
}
private async void Reconnect()
{
if (App.IsForeground)
{
MessageDialog dlg = new MessageDialog("Connection to desktop process lost. Reconnect?");
UICommand yesCommand = new UICommand("Yes", async (r) =>
{
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
});
dlg.Commands.Add(yesCommand);
UICommand noCommand = new UICommand("No", (r) => { });
dlg.Commands.Add(noCommand);
await dlg.ShowAsync();
}
}
private int count = 0;
private async void SendMesssage(object sender, RoutedEventArgs e)
{
count++;
ValueSet request = new ValueSet();
request.Add("KEY", $"Test{count}");
AppServiceResponse response = await App.Connection.SendMessageAsync(request);
// display the response key/value pairs
foreach (string value in response.Message.Values)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
StatusBlock.Text = value;
});
}
}
This is complete code sample.
I have a background task that is supposed to open a toast message, à la: ToastNotificationManager.CreateToastNotifier().Show(toast);. My code executes fine, no errors are thrown, nothing hangs -- but also, no toast message appears.
I checked the Event Viewer logs, and they say this:
An instance of the background task with entry point
BG.ToastBackgroundTask running for user [me] in session [sesh]
returned with error code 0x0.
I have looked all over to see what this error code might mean but found nothing.
Here's my code:
public sealed class ToastBackgroundTask : IBackgroundTask
{
private BackgroundTaskDeferral _deferral;
public async void Run(IBackgroundTaskInstance taskInstance)
{
var cancelToken = new System.Threading.CancellationTokenSource();
taskInstance.Canceled += (s, e) =>
{
cancelToken.Cancel();
cancelToken.Dispose();
};
taskInstance.Task.Completed += Task_Completed;
_deferral = taskInstance.GetDeferral();
try
{
await SendNotificationAsync();
}
finally { _deferral.Complete(); }
}
public static async void Register()
{
var isRegistered = BackgroundTaskRegistration.AllTasks.Values.Any(x => x.Name == nameof(ToastBackgroundTask));
if (isRegistered) return;
var accessStatus = await BackgroundExecutionManager.RequestAccessAsync();
if (accessStatus == BackgroundAccessStatus.DeniedByUser || accessStatus == BackgroundAccessStatus.DeniedBySystemPolicy) return;
var builder = new BackgroundTaskBuilder
{
Name = nameof(ToastBackgroundTask),
TaskEntryPoint = $"{nameof(MyNameSpace)}.{nameof(BG)}.{nameof(ToastBackgroundTask)}"
};
builder.SetTrigger(new TimeTrigger(120, false));
var task = builder.Register();
}
private static void Task_Completed(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
{
try
{
args.CheckResult();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
private Task SendNotificationAsync()
{
var service = new ToastService();
service.CreateToast(new ToastViewModel { Title = "Title", Text = "Text", ImagePath = "", Id = 3 });
return Task.CompletedTask;
}
}
If I run CheckResult() on the completed task, no errors are thrown. Argh! Does anyone know (a) what this Event Viewer log error means, or (b) why my toast isn't showing up?
Here's my Toast code too in case it helps:
public class ToastService
{
public void CreateToast(ToastViewModel model)
{
var visual = new ToastVisual()
{
BindingGeneric = new ToastBindingGeneric()
{
Children =
{
new AdaptiveText() { Text = model.Title },
new AdaptiveText() { Text = model.Text }
},
Attribution = new ToastGenericAttributionText() { Text = "Via Me" }
}
};
var tContent = new ToastContent()
{
Visual = visual,
ActivationType = ToastActivationType.Background,
Scenario = ToastScenario.Reminder
};
var toast = new ToastNotification(tContent.GetXml())
{
ExpirationTime = DateTime.Now.AddDays(model.Expiration)
};
toast.Failed += (o, args) => {
var message = args.ErrorCode;
};
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
Does anyone know (a) what this Event Viewer log error means, or (b) why my toast isn't showing up?
The above event log showed on my side is information level, not error level. The reason for the toast isn't showing up should be that you setting the ExpirationTime property for the ToastNotification. This property is for:
Gets or sets the time after which a toast notification should not be displayed.
So that if the model.Expiration equals to 0, the toast will not show from now. Ensure the expiration time later than now should work.
var toast = new ToastNotification(tContentxml)
{
ExpirationTime = DateTime.Now.AddDays(1)
};
Otherwise your code snippet can work will on my side. If you still have issues, you can provide a minimal reproduced project to let us have a testing.
I have a windows phone 7 app with following code
ServiceReference1.SMSWarriorServiceSoapClient ws = new ServiceReference1.SMSWarriorServiceSoapClient();
ws.BalanceCompleted += new EventHandler<ServiceReference1.BalanceCompletedEventArgs>(ws_BalanceCompleted);
ws.BalanceAsync(textBox1.Text, textBox2.Password);
Now i want to make it also for Windows 8 store app. I try this
var client = new ServiceReference1.SMSWarriorServiceSoapClient() ;
var result = client.BalanceAsync("user", "pass");
resultDetails.Text = result.ToString ;
but with no luck
I also try the Await but I don't know how to use it
If you are calling the web service method from an event handle then use this.
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
var client = new ServiceReference1.SMSWarriorServiceSoapClient();
var result = await client.BalanceAsync("user", "pass");
resultDetails.Text = result.ToString();
}
If you are calling the web service method from a method then use this.
private async Task ServiceCall()
{
var client = new ServiceReference1.SMSWarriorServiceSoapClient();
var result = await client.BalanceAsync("user", "pass");
resultDetails.Text = result.ToString();
}
Ensure you call method ServiceCall() with await keyword.
if u use await then u must use async keyword or use Task
var client = new ServiceReference1.SMSWarriorServiceSoapClient() ;
var result = await client.BalanceAsync("user", "pass");
resultDetails.Text = result.ToString ;
for example:
// Put the keyword, async on the declaration of the event handler.
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
var respose=await <some async operation >
}