How to avoid async methods windows phone 8.1 - c#

Im creating an windows phone 8.1 app. When app is started, app prompts user to call certain telephone number. It does this with voice. After instructions are told by app, phone call dialog is showed.
This is the code:
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
StartSpeaking("Please call number !");
CallDialog();
}
private async void StartSpeaking(string text)
{
MediaElement mediaElement = this.media;
// The object for controlling the speech synthesis engine (voice).
var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
// Generate the audio stream from plain text.
SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(text);
// Send the stream to the media object.
mediaElement.SetSource(stream, stream.ContentType);
mediaElement.Play();
}
private async void CallDialog()
{
Windows.ApplicationModel.Calls.PhoneCallManager.ShowPhoneCallUI("123", "123");
var messageDialog = new Windows.UI.Popups.MessageDialog("call ended", "Text spoken");
await messageDialog.ShowAsync();
}
The problem is that I must use synth.SynthesizeTextToStreamAsync method which is async method so call dialog shows up before text is said. How can I avoid that?

async Task methods should be embraced; it is only async void methods that should be avoided (they should only be used as event handlers). I have an MSDN article that describes a few reasons to avoid async void.
In your case, you can use an async void event handler (e.g., for the Loaded event), and make your methods async Task instead of async void and await them:
async void MainPage_Loaded(..)
{
await StartSpeakingAsync("Please call number !");
await CallDialogAsync();
}
private async Task StartSpeakingAsync(string text);
private async Task CallDialogAsync();
Update
To (asynchronously) wait for the media to play, you need to hook into an event that notifies you it's complete. MediaEnded looks like a good choice. Something like this should work:
public static Task PlayToEndAsync(this MediaElement #this)
{
var tcs = new TaskCompletionSource<object>();
RoutedEventHandler subscription = null;
subscription = (_, __) =>
{
#this.MediaEnded -= subscription;
tcs.TrySetResult(null);
};
#this.MediaEnded += subscription;
#this.Play();
return tcs.Task;
}
That method extends the MediaElement with an async-ready PlayToEndAsync method, which you can use like this:
private async Task SpeakAsync(string text)
{
MediaElement mediaElement = this.media;
var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(text);
mediaElement.SetSource(stream, stream.ContentType);
await mediaElement.PlayToEndAsync();
}

Related

I'm not able to use "await" unless it's not in an lambda function

I've been trying to make a function run asynchronously to prevent the window from freezing everytime it pings a new address but when I tried to implement it, VS said that I can't use the await operator as it's current state. Any suggestions?
public MainWindow()
{
//var reader = new Mp3FileReader(#"Resources\Audio\02 Connecting.flac");
MediaFoundationReader sound = new MediaFoundationReader(#"Resources\Audio\Connecting.mp3");
var waveOut = new WaveOut(); // or WaveOutEvent()
waveOut.Init(sound);
waveOut.Play();
InitializeComponent();
ContentRendered += (s, e) => { await Connecting(); };
}
private async Task Connecting()
{
AutoResetEvent waiter = new AutoResetEvent(false);
IPAddress ip = IPAddress.Parse("23.185.0.1");
var pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;
pingSender.SendAsync(ip, 1000, waiter);
}
The issue is that you're trying to use await in a synchronous delegate:
ContentRendered += (s, e) => { await Connecting(); };
To use the await keyword, you'll need an asynchronous delegate defined, to then add it to the event.
This should work - note the async keyword which enables the use of the await keyword:
ContentRendered += async (s, e) => { await Connecting(); };
You should also await the asynchronous pingSender.SendAsync method:
await pingSender.SendAsync(ip, 1000, waiter);
Unless you are using the Connecting asynchronous method in more than one places, it is probably preferable from a maintainability point of view to attach a classic event handler to the ContentRendered event:
ContentRendered += ContentRenderedHandler;
//...
private async void ContentRenderedHandler(object sender, EventArgs e)
{
IPAddress ip = IPAddress.Parse("23.185.0.1");
var pingSender = new Ping();
PingReply pingReply = await pingSender.SendPingAsync(ip, 1000);
// Use the `pingReply` here
}
This is essentially the same with what Ermiya Eskandary suggests in their answer, with the only difference being that the presence on an async void method is visible and explicit. The use of async void here is correct, because the method is an event handler. It's a good idea to be explicit though, because async void methods are too often misused, resulting in unexpected behavior, or compiler warnings, or both.
Update: Your code makes use of the anachronistic PingCompleted + SendAsync approach. The Ping class offers the newer SendPingAsync API (.NET Framework 4.5 and later), that can be consumed directly with async-await.

Allocate separate thread per event in FileSystemWatcher

I am developing a windows service that contains the FileSystemWatcher. Once file creates, I have to make some network calls to a web API.
Please look at below code lines.
watcher.Created += new FileSystemEventHandler((object source, FileSystemEventArgs e) => { ProcessCreateEvent(e); });
Event handler
private async void ProcessCreateEvent(FileSystemEventArgs e){
// make some network calls and do certain tasks
// network calls doing asynchronously
}
I did in deep about the FileSystemWatcher and I understand that it is not the good practice to handle the network call in ProcessCreateEvent method. So how can I allocate the separate thread for each file change?
Events already support async, so you can just do something like:
watcher.Created += this.ProcessCreateEvent;
private async void ProcessCreateEvent(object sender, FileSystemEventArgs e)
{
var result = await asyncApi.GetStuffAsync();
}
You don't need to spin up another Task unless the non-async stuff you are doing in the event handler is expensive.
I think it can simply be done by making ProcessCreateEvent asynchronous like this:
private async Task ProcessCreateEvent(FileSystemEventArgs e)
{
// make some network calls and do certain tasks
// network calls doing asynchronously
await Task.Run(async () => {
var client = new HttpClient();
var response = await client.GetAsync("http://localhost:54522/api/values");
var result = await response.Content.ReadAsStringAsync();
});
}

WIndows Universal MediaPlayer From BackgroundActivated Task Single Processs Model Invoked from WNS

I am trying to play a sound from a BackgroundActivated Task (Single Process) that is activated as a result of Windows Notification Service WNS event.
If the Applications is launched in the Foreground and then minimized ... Things work fine.
If the Application is not currently launched ... This does not work.
My App's OnBacgroundActivated:
protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args) {
PersistLog.v(TAG, "OnBackgroundActivated");
await VANotification.Process(args.TaskInstance);
//base.OnBackgroundActivated(args);
PersistLog.v(TAG, "OnBackgroundActivated:Completed");
}
The VANotification.Proces
public async Task Process(IBackgroundTaskInstance taskInstance) {
PersistLog.v(TAG, "Process");
var Deferral = taskInstance.GetDeferral();
RawNotification notification = (RawNotification)taskInstance.TriggerDetails;
var msg = notification.Content;
PersistLog.i(TAG, "Msg:" + msg);
var a = Record(msg);
await TTSSandSound.Say(a);
Deferral.Complete();
PersistLog.v(TAG, "Process:Complete!");
}
The TTSAndSound.Say ...
public static async Task Say(String text) {
PersistLog.v(TAG, "Say:" + text);
sSynthesize.Voice = SpeechSynthesizer.DefaultVoice;
var ss = sSynthesize.SynthesizeTextToStreamAsync(text);
var t = new TaskCompletionSource<MediaSource>();
ss.Completed = (stream, status) => {
var sr = stream.GetResults();
MediaSource ms = MediaSource.CreateFromStream(sr,sr.ContentType);
t.TrySetResult(ms);
};
var _ms = await t.Task;
var r = await WaitFor(_ms);
PersistLog.v(TAG, "Say:Complete:" + r);
}
private static async Task<bool> WaitFor(MediaSource ms) {
var mp = new MediaPlayer();
mp.Source = ms;
var t = new TaskCompletionSource<bool>();
mp.MediaEnded += (p, o) => {
t.TrySetResult(true);
};
mp.MediaFailed += (p, o) => {
t.TrySetResult(true);
};
mp.Play();
return await t.Task;
}
I am actually not sure if this is a MediaPlayer problem or the fact that the BackgroundActivated task does not seem to honer the deferal. I can see from the log that the MediaPlayer finishes properly. But I get an App Suspending event about the same time I try to do a MediaPlayer Play ... And then none of the async code after the call to:
await TTSSandSound.Say(a);
Seems to run. I have followed:
Background media playback sample
NOTE ... THis always works when the App is in activated in forground mode when the WNS arrives.
The problem appears to be related to the fact that often the Background Activated Task in the same process as the foreground is being suspended before the MediaPlayer is setup properly.
In a few test cases .. the MediaPlayer seems to get setup properly ... and in those cases the MedialPlayer works correctly. But the async tasks not associated with the MediaPlayer still throw exceptions: .
at Hap.App.<OnBackgroundActivated>d_27.MoveNext()
This seems to be related to the Timing of the app being suspended. It seems that a Local Background Activated Task that is triggered by a WNS is only allowed less than 1 second before being suspended.

Windows Phone 8.1 Showing progress view until async/await task finishes

I have two tasks which download an mp3 from web address inside local storage and returns timeSpan.
public async Task<TimeSpan> filedownload_Ignition_Outside()
{
Uri sourceIgnition_Outside = new Uri(TemporaryAddress.download_playCarSound+"Ignition_Outside");
//download and store file
return duration_Ignition_Outside;
}
public async Task<TimeSpan> filedownload_Idle_Outside()
{
Uri sourceIdle_Outside = new Uri(TemporaryAddress.download_playCarSound +"Idle_Outside");
StorageFile destinationFileIdle_Outside;
//download and store file
return duration_Idle_Outside;
}
Now I need to show an indeterminate progressbar in UI while downloading starts till it ends But dont know how to find the task completed?
On my NavigatedTo function I have set it as async and am calling
await downloadFile();
Now inside my downloadFile()
public async Task<TimeSpan> downloadFiles()
{
//ProgressShow
var temp= await filedownload_Ignition_Outside();
//if (filedownload_Ignition_Outside().IsCompleted)
//{
// //progressStop
//}
return temp;
}
But its not executing the stop statement as it waits asynchronously how can I get the event where both task gets finished? Can I call both tasks inside my downloadFiles() method and still able to get an event for both task completion.
Try something similar to the code given below in your OnNavigatedTo event.
ShowProgress=true;
downloadFiles().ContinueWith((sender) =>
{
this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
ShowProgress=false;
);
});
You need to run the ShowProgress=False; in UI thread

await asynchronous method where completion is signalled by event handler

I am working with the Contacts object in Windows Phone 8, calling SearchAysnc from within an async method. SearchAsync requires that a handler be subscribed to the SearchCompleted event, and delivers its results via one of the event args, which the async method requires to do its job (which includes invoking other async methods).
How do you await the asynchronous completion of an event i.e. bridge between the event pattern and the async/await pattern?
The only solution I could come up with was to use an EventWaitHandle, waiting on it within an awaited Task something like this:
using System.Threading;
async Task<string> MyMethod()
{
string result = null;
Contacts cons = new Contacts();
EventWaitHandle handle = new EventWaitHandle(false,EventResetMode.ManualReset);
cons.SearchCompleted += (sender,args) =>
{
// I do all my work on the results of the contact search in this handler
result = SomeOtherSynchronousOperation(args.Results);
// When I'm done, I release the thread which was waiting for the results
handle.Set();
};
cons.SearchAsync(String.Empty, FilterKind.None, "My Contact");
// I can't block this thread (or can I?)
// So, I launch a task whose sole job is to wait
await Task.Run(()=>
{
// This gets released by the Contacts.SearchCompleted handler when its work is finished,
// so that MyMethod can finish up and deliver its result
handle.WaitOne();
}
await DoOtherStuffWithResult(result);
return result;
}
My actual solution (not exactly as shown above) does work. Although the above code doesn't precisely represent the implemented solution, (likely a compile issue or two), it should serve to express the concept and illustrate the point of my question.
It leaves me wondering if this is the only way, or anywhere close to the best practise way to await the execution of an event handler, and if not, what would be the "best practice" to do what is needed here.
Do the Windows synchronization primitives still have a place in an async/await world?
(Based on answers provided)
Would this be correct?
using Microsoft.Phone.UserData;
string ExtractWhatIWantFromResults(IEnumerable<Contact> results)
{
string result;
// Do my processing on the list of contacts, stuff the results into result
return string;
}
async Task<string> MyMethod()
{
Contacts cons = new Contacts();
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
cons.SearchCompleted += (sender,args) =>
{
tcs.TrySetResult(ExtractWhatIWantFromResults(args.Results));
};
cons.SearchAsync(String.Empty, FilterKind.None, "My Contact");
return tcs.Task;
}
TaskCompletionSource is the common way to use.
Not tested (No idea how to test without knowing your classes/methods),
Task<string> MyMethodAsync()
{
Contacts cons = new Contacts();
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
cons.SearchCompleted += (sender,args) =>
{
tcs.TrySetResult(args.Results);
};
cons.SearchAsync(String.Empty, FilterKind.None, "My Contact");
return tcs.Task;
}
To bridge EAP and TAP, you should use TaskCompletionSource, as such:
public static Task<IEnumerable<Contact>> SearchTaskAsync(this Contacts contacts, string filter, FilterKind filterKind)
{
var tcs = new TaskCompletionSource<IEnumerable<Contact>>();
EventHandler<ContactsSearchEventArgs> subscription = null;
subscription = (_, e) =>
{
contacts.SearchCompleted -= subscription;
tcs.TrySetResult(e.Results);
};
contacts.SearchCompleted += subscription;
contacts.SearchAsync(filter, filterKind, null);
return tcs.Task;
}
which you can use like this:
async Task<string> MyMethodAsync()
{
Contacts cons = new Contacts();
var searchResults = await cons.SearchTaskAsync(String.Empty, FilterKind.None);
string result = SomeOtherSynchronousOperation(searchResults);
await DoOtherStuffWithResult(result);
return result;
}
In fact, the MSDN docs for TAP are really of an unusually high quality and I strongly recommend reading through that entire section.
Do the Windows synchronization primitives still have a place in an async/await world?
Not so much, because as soon as you block a thread, you lose the benefits of asynchronous code. That said, you can emulate similar behavior using TAP-based primitives; Stephen Toub has a series of blog entries that explore this and I implemented similar primitives in my AsyncEx library.

Categories