I have an UWP application in which I am trying to store and retrieve some data from a local text file but no matter how I try to do it the application gets deadlocked. Due to synchronous stuff that needs to happen, I try to use a task and wait for its completion but nevertheless, the application locks.
I have a page in my UWP application called "MainPage" and in it's constructor I have the following code:
var listenkeyViewModel = new ListenkeyViewModel();
listenkeyViewModel.GetKey();
listenkey = listenkeyViewModel.Listenkey;
The get key is the issue here because it calls a method on the ViewModel (which I created to be synchronous because I thought making the call synchronous asap would be preferable.
public void GetKey()
{
try
{
var listenKeyTask = RetrieveListenKey();
_listenkey = listenKeyTask.Result;
}
catch (Exception e)
{
}
}
public static async Task<string> RetrieveListenKey()
{
try
{
var storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var listenkeyFile = await storageFolder.GetFileAsync("listenkey.txt");
return await Windows.Storage.FileIO.ReadTextAsync(listenkeyFile);
}
catch (Exception e)
{
throw new Exception("Could not load file");
}
}
I know the thing is "async all the way down" but this is not possible here. I cannot make the constructor where the original code lies asynchronous. How are you supposed to not get deadlocked? I do not understand.
Convert GetKey to async/await
public async Task GetKey() {
try {
var listenKeyTask = RetrieveListenKey();
_listenkey = await listenKeyTask;
} catch (Exception e) {
//...should handle/log error
}
}
Move the calling of this out of the constructor and into an event handler. like page load or some other event called early in the lifecycle of the page.
partial class MainPage : Page {
ListenkeyViewModel listenkeyViewModel;
string listenkey;
public MainPage() {
InitializeComponent();
listenkeyViewModel = new ListenkeyViewModel();
// add a handler to be called when the page has been loaded
this.Loaded += OnPageLoaded;
}
async void OnPageLoaded(object sender, RoutedEventArgs e) {
await listenkeyViewModel.GetKey();
listenkey = listenkeyViewModel.Listenkey;
}
// Shown for demonstration purposes only.
// This is typically autogenerated by Visual Studio.
private void InitializeComponent() {
}
}
async void is allowed on event handlers so this should allow the process to flow without deadlock.
Related
I am trying to add a basic callback to my app whereby a loading state label updates as the app progresses through an update task. For some reason though, after calling one particular async method, any events raised thereafter are not updating the UI.
I've tried various configure await settings and looked through the async method itself but I can't find anything obviously wrong.
public async Task RefreshTable<T>() where T : class, IEntity
{
try
{
OnContentUpdateProgressChange(this, new MessageEventArgs($"RefreshTable before {typeof(T).Name}"));
var tableJsonData = await ApiService.GetEntityListAsync<T>();
OnContentUpdateProgressChange(this, new MessageEventArgs($"RefreshTable after {typeof(T).Name}"));
await LoadTableData(Set<T>(), tableJsonData);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
}
public async Task<List<T>> GetEntityListAsync<T>(string url = null) where T : class
{
if (string.IsNullOrEmpty(url))
{
url = typeof(T).Name.Replace("_", "");
}
try
{
string entityList = null;
HttpResponseMessage response = await Client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
entityList = await response.Content.ReadAsStringAsync();
var backupFile = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), typeof(T).Name);
using (var writer = File.CreateText(backupFile))
{
await writer.WriteLineAsync(entityList.ToString());
}
}
return await Task.Factory.StartNew(() => JsonConvert.DeserializeObject<List<T>>(entityList));
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
throw;
}
}
private void DB_OnContentUpdateProgressChange(object sender, library.EventArguments.MessageEventArgs e)
{
lblLoadingState.Text = e.Message;
}
The event raised before the call to GetEntityListAsync successfully updates the UI, the one after however doesn't.
from what I read my understanding tells me this is a UI thread issue When you make some changes in a Background thread in your case the async method it is always recommended that the changes that you have made which will affect the UI should be done on the MainThread or the UIThread. Now what you need to do is quite simple. Whenever you make a change that is supposed to affect the UI in any kind do it on the UI thread.
What I like to do is make all the UI changes in a method then I like to have a base version of my Activity class that has helpers that let me check if it is the MainThread or not and make the changes accordingly use that method.
Add an Activity that inherits from AppCompatActivity and then add the following to it.
public abstract class BaseActivity : AppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
}
public bool IsMainThread => Build.VERSION.SdkInt >= BuildVersionCodes.M
? Looper.MainLooper.IsCurrentThread
: Looper.MyLooper() == Looper.MainLooper;
public void RunOnMainThread(Action action)
{
if (IsMainThread) action();
else RunOnUiThread(action);
}
}
Then make UI changes like:
RunOnMainThread(() => { LabelDoSomething.Text = "New Text"; });
I am trying to implement a long-running background process, that periodically reports on its progress, to update the UI in a UWP app. How can I accomplish this? I have seen several helpful topics, but none have all of the pieces, and I have been unable to put them all together.
For example, consider a user who picks a very large file, and the app is reading in and/or operating on the data in the file. The user clicks a button, which populates a list stored on the page with data from the file the user picks.
PART 1
The page and button's click event handler look something like this:
public sealed partial class MyPage : Page
{
public List<DataRecord> DataRecords { get; set; }
private DateTime LastUpdate;
public MyPage()
{
this.InitializeComponent();
this.DataRecords = new List<DataRecord>();
this.LastUpdate = DateTime.Now;
// Subscribe to the event handler for updates.
MyStorageWrapper.MyEvent += this.UpdateUI;
}
private async void LoadButton_Click(object sender, RoutedEventArgs e)
{
StorageFile pickedFile = // … obtained from FileOpenPicker.
if (pickedFile != null)
{
this.DataRecords = await MyStorageWrapper.GetDataAsync(pickedFile);
}
}
private void UpdateUI(long lineCount)
{
// This time check prevents the UI from updating so frequently
// that it becomes unresponsive as a result.
DateTime now = DateTime.Now;
if ((now - this.LastUpdate).Milliseconds > 3000)
{
// This updates a textblock to display the count, but could also
// update a progress bar or progress ring in here.
this.MessageTextBlock.Text = "Count: " + lineCount;
this.LastUpdate = now;
}
}
}
Inside of the MyStorageWrapper class:
public static class MyStorageWrapper
{
public delegate void MyEventHandler(long lineCount);
public static event MyEventHandler MyEvent;
private static void RaiseMyEvent(long lineCount)
{
// Ensure that something is listening to the event.
if (MyStorageWrapper.MyEvent!= null)
{
// Call the listening event handlers.
MyStorageWrapper.MyEvent(lineCount);
}
}
public static async Task<List<DataRecord>> GetDataAsync(StorageFile file)
{
List<DataRecord> recordsList = new List<DataRecord>();
using (Stream stream = await file.OpenStreamForReadAsync())
{
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
// Does its parsing here, and constructs a single DataRecord …
recordsList.Add(dataRecord);
// Raises an event.
MyStorageWrapper.RaiseMyEvent(recordsList.Count);
}
}
}
return recordsList;
}
}
The code for the time check I got from following this.
As written, this code makes the app unresponsive with a large file (I tested on a text file on the order of about 8.5 million lines). I thought adding async and await to the GetDataAsync() call would prevent this? Does this not do its work on a thread aside from the UI thread? Through Debug mode in Visual Studio, I have verified the program is progressing as expected... it is just tying up the UI thread, making the app unresponsive (see this page from Microsoft about the UI thread and asynchronous programming).
PART 2
I have successfully implemented before an asynchronous, long-running process that runs on a separate thread AND still updates the UI periodically... but this solution does not allow for the return value - specifically the line from PART 1 that says:
this.DataRecords = await MyStorageWrapper.GetDataAsync(pickedFile);
My previous, successful implementation follows (most of the bodies cut out for brevity). Is there a way to adapt this to allow for return values?
In a Page class:
public sealed partial class MyPage : Page
{
public Generator MyGenerator { get; set; }
public MyPage()
{
this.InitializeComponent();
this.MyGenerator = new Generator();
}
private void StartButton_Click(object sender, RoutedEventArgs e)
{
this.MyGenerator.ProgressUpdate += async (s, f) => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, delegate ()
{
// Updates UI elements on the page from here.
}
this.MyGenerator.Start();
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
this.MyGenerator.Stop();
}
}
And in the Generator class:
public class Generator
{
private CancellationTokenSource cancellationTokenSource;
public event EventHandler<GeneratorStatus> ProgressUpdate;
public Generator()
{
this.cancellationTokenSource = new CancellationTokenSource();
}
public void Start()
{
Task task = Task.Run(() =>
{
while(true)
{
// Throw an Operation Cancelled exception if the task is cancelled.
this.cancellationTokenSource.Token.ThrowIfCancellationRequested();
// Does stuff here.
// Finally raise the event (assume that 'args' is the correct args and datatypes).
this.ProgressUpdate.Raise(this, new GeneratorStatus(args));
}
}, this.cancellationTokenSource.Token);
}
public void Stop()
{
this.cancellationTokenSource.Cancel();
}
}
Finally, there are two supporting classes for the ProgressUpdate event:
public class GeneratorStatus : EventArgs
{
// This class can contain a handful of properties; only one shown.
public int number { get; private set; }
public GeneratorStatus(int n)
{
this.number = n;
}
}
static class EventExtensions
{
public static void Raise(this EventHandler<GeneratorStatus> theEvent, object sender, GeneratorStatus args)
{
theEvent?.Invoke(sender, args);
}
}
It is key to understand that async/await does not directly say the awaited code will run on a different thread. When you do await GetDataAsync(pickedFile); the execution enters the GetDataAsync method still on the UI thread and continues there until await file.OpenStreamForReadAsync() is reached - and this is the only operation that will actually run asynchronously on a different thread (as file.OpenStreamForReadAsync is actually implemented this way).
However, once OpenStreamForReadAsync is completed (which will be really quick), await makes sure the execution returns to the same thread it started on - which means UI thread. So the actual expensive part of your code (reading the file in while) runs on UI thread.
You could marginally improve this by using reader.ReadLineAsync, but still, you will be returning to UI thread after each await.
ConfigureAwait(false)
The first trick you want to introduce to resolve this problem is ConfigureAwait(false).
Calling this on an asynchronous call tells the runtime that the execution does not have to return to the thread that originally called the asynchronous method - hence this can avoid returning execution to the UI thread. Great place to put it in your case is OpenStreamForReadAsync and ReadLineAsync calls:
public static async Task<List<DataRecord>> GetDataAsync(StorageFile file)
{
List<DataRecord> recordsList = new List<DataRecord>();
using (Stream stream = await file.OpenStreamForReadAsync().ConfigureAwait(false))
{
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
string line = await reader.ReadLineAsync().ConfigureAwait(false);
// Does its parsing here, and constructs a single DataRecord …
recordsList.Add(dataRecord);
// Raises an event.
MyStorageWrapper.RaiseMyEvent(recordsList.Count);
}
}
}
return recordsList;
}
Dispatcher
Now you freed up your UI thread, but introduced yet another problem with the progress reporting. Because now MyStorageWrapper.RaiseMyEvent(recordsList.Count) runs on a different thread, you cannot update the UI in the UpdateUI method directly, as accessing UI elements from non-UI thread throws synchronization exception. Instead, you must use UI thread Dispatcher to make sure the code runs on the right thread.
In the constructor get reference to the UI thread Dispatcher:
private CoreDispatcher _dispatcher;
public MyPage()
{
this.InitializeComponent();
_dispatcher = Window.Current.Dispatcher;
...
}
Reason to do it ahead is that Window.Current is again accessible only from the UI thread, but the page constructor definitely runs there, so it is the ideal place to use.
Now rewrite UpdateUI as follows
private async void UpdateUI(long lineCount)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// This time check prevents the UI from updating so frequently
// that it becomes unresponsive as a result.
DateTime now = DateTime.Now;
if ((now - this.LastUpdate).Milliseconds > 3000)
{
// This updates a textblock to display the count, but could also
// update a progress bar or progress ring in here.
this.MessageTextBlock.Text = "Count: " + lineCount;
this.LastUpdate = now;
}
});
}
First of all, I'm Java programmer and I'm new on C# and I need opinion of C# developers. I'm developing an application that connecting to database (firebird 1.5), query some data and return to me so there's nothing to be complicated but unfortunately I've stuck in some things :
As we know the database connection should be realised in separate thread cause it's a highweight operation and all the connections should be in connection pool in order to reuse already opened connection instead create the new one.
So here go my first question - how to organize connection pool properly?
(What about connection pool I've read that usually connection pool is already realised by data providers and I can just set it in connection parametres someway like "connectionBuilder.Pooling = true;")
What about queries? I mean that I've always use a Query per-Thread (and I think that is right cause we also do a highweight operation, am I wrong? Anyway I'd glad to see your best practices with organizing database work) and in Java I just do return Query result from separate thread by use an interfaces and anonymous classes like this:
In DBHelper.class (DBHelper is a singleton)
public interface QueryListener {
public void onSuccess(ArrayList<?>);
public void onError(Exception e);
}
public synchronized void getPromoActions(final QueryListener listener) {
if (listener != null) {
try {
ArrayList<String> myPromoActions;
.............
// some query's code
.....
listener.onSucces(myPromoActions);
} catch(Exception e) {
listener.onError(e);
} finally {
closeDatabase();
}
}
}
in some UI-class (for eaxample MainWindow)
public void getPromoActions(){
new Thread(new Runnable() {
#Override
public void run() {
DBHelper.getInstance().getPromoActions(new QueryListener() {
#Override
public void onSuccess(ArrayList<?>) {
// set Data to UI element such as Table
}
#Override
public void onError(Exception e){
// Handling exception
}
});
}
}).start();
}
In C# I should use delegates to mark which method will execute in thread, but unfortionally I can't send any callback as parameter - so how I should return my Query results to main UI thread?
UPD
I've understand a little bit how to work with delegates and events but have a problem with raising a custom event. I had declared an EventHandler and an custom EventArgs:
public delegate void QueryResultEventHandler(object sender, QueryResultEventArgs e);
public class QueryResultEventArgs : EventArgs
{
public List<String> QueryResult { get; set; }
public int QueryRecordsCount { get; set; }
}
And in My DBHelper.class I declared a next field and event:
private QueryResultEventHandler _queryResult;
public event QueryResultEventHandler onQueryResult
{
add
{
lock (this)
{
_queryResult += value;
}
}
remove
{
lock (this)
{
_queryResult -= value;
}
}
}
In UI class (MainWindow) I use next code:
public void GetAllDistricts() {
DBHelper.Instance.onQueryResult += new QueryResultEventHandler(GetAllDistricsResultHandler);
DBHelper.Instance.GetAllDistricts();
}
public void GetAllDistricsResultHandler(object sender, QueryResultEventArgs e){
// Here I'm adding the query result to Table
}
So my problem now is a how to raise an event asynchronously? In my DBHelper.class I'm trying to use beginInvoke&endInvoke with _query delegate but it seems that I had missed some code lines whatever it was I can't understand what I'm doing wrong an how to raise event asynchronously? Here my DBHelper.class code:
public void GetAllDistricts() {
try
{
if (_queryResult != null)
{
//** This code should run asynchronously ---------->
using (FbConnection connection = GetConnection())
{
FbCommand getAllDistrictsCommand = new FbCommand();
getAllDistrictsCommand.CommandText = "SELECT * FROM SEND";
getAllDistrictsCommand.Connection = connection;
QueryResultEventArgs args = new QueryResultEventArgs();
using (FbDataReader reader = getAllDistrictsCommand.ExecuteReader())
{
while (reader.Read())
{
//Here must be the processing of query results and filling the
//QueryResultEventArgs
args.QueryResult.Add(reader[0].ToString());
}
args.QueryRecordsCount = reader.GetInt32(reader.GetOrdinal("Rows"));
// And here after sucessfull query I should call OnQueryResult()
OnQueryResult(args);
}
}
//**<--------------------
}
else
{
throw new Exception("...Some exception message...");
}
}
catch (Exception e)
{
log.ErrorException(e.Message, e);
throw new Exception("...Some exception message...");;
}
finally {
CloseConnection();
}
}
// The QueryResultEvent method
protected void OnQueryResult(QueryResultEventArgs e)
{
if (_queryResult != null)
{
_queryResult(this, e);
}
}
First about connection pooling. If you will use ADO.NET then you do not need to worry about that, because it's already there. You don't need to do any extra work, you just create a connection:
using (var connection = new SqlConnection(connectionString))
{
// Queries to DB
}
You should always Close or Dispose you connections. The names of the methods look "scary" but actually connections are reused. Please read this MSDN article to get more details.
The code you proposed looks over-complicated. I think you should consider using async/await pattern which is in general not multithreaded, but it handles UI responsiveness issues and simplifies writing/reading of the code. In newer versions of .NET almost all methods that are potentially long to execute has async versions. So for example your data access layer might look like that (I'm using Dapper ORM's QueryAsync method just to keep code short and simple):
public async Task<IList<District>> GetAllDistrictsAsync()
{
using (var connection = await GetConnectionAsync())
{
return (await connection.QueryAsync<District>("select * from Districts")).ToList();
}
}
public async Task<IDbConnection> GetConnectionAsync()
{
var connectionString =
ConfigurationManager.ConnectionStrings["DbConnectionString"].ConnectionString;
var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
return connection;
}
And then somewhere on UI:
private async void Button_Click(object sender, EventArgs e)
{
var districts = await GetAllDistrictsAsync();
}
If you still need to execute some code in different thread you should look at Tasks namespace.
Task.Factory
.StartNew<IList<District>>(GetAllDistricts)
.ContinueWith(districts =>
{
// UI thread
}, TaskScheduler.FromCurrentSynchronizationContext());
In this example GetAllDistricts is not async and is executed in different thread. But ContinueWith will be executed in UI thread because of TaskScheduler.FromCurrentSynchronizationContext().
public void GetAllDistricts() {
DBHelper.Instance.onQueryResult +=
new QueryResultEventHandler(GetAllDistricsResultHandler);
new Thread(
new ThreadStart(DBHelper.Instance.GetAllDistricts)
).Start();
}
But the problem you will face is that you won't be able to access your UI controls from the EventHandler as it will be denied because you are not in the same thread anymore...
Refer to that article for some explanation
How to update the GUI from another thread in C#?
To avoid this you can maybe use the BackgroundWorker control.
Use this option
http://www.asp.net/mvc/overview/older-versions-1/models-(data)/creating-model-classes-with-the-entity-framework-cs
it is easy to use and easy to database operation with less code.
I have Windows phone page that fetch data from the web url using async. In my page class consructor I cannot call a async method. How do I initialize properties from the web url repsonse in the constructor.
public MyProfile()
{
InitializeComponent();
_populateFields();
}
private async void _populateFields()
{
try
{
var taskObj = await UserProfile.getUserProfile().getUserProfileFromServer();
//PoolCircle.UserProfile.ProfileResponseJson userObj = taskObj;
setDataContext(taskObj);
}
catch (Exception ex) { Debug.WriteLine(ex.Message); }
}
How do I fix this dependency? I am not sure how a factory method fix it. I am not creating object for the page class..
Try it from the OnNavigatedTo method. Overriding it. Its a method who you can put all your logic before the page appears
protected async override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
_populateFields();
}
Documentation
hope helps! Greetings!
Make a method like PostData(); and call this after InitializeComponent();
private async void PostData()
{
try
{
var taskObj = await UserProfile.getUserProfile().getUserProfileFromServer();
//PoolCircle.UserProfile.ProfileResponseJson userObj = taskObj;
setDataContext(taskObj);
}
catch (Exception ex) { Debug.WriteLine(ex.Message); }
}
I have the following code in Windows Phone:
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
}
private void Button_LogIn_Click(object sender, RoutedEventArgs e)
{
Service1SoapClient web_service = new Service1SoapClient();
web_service.LogInAsync(TextBox_Username.Text, TextBox_Password.Password);
web_service.LogInCompleted += new EventHandler<LogInCompletedEventArgs>(login_complete);
}
private void login_complete(object obj, ClientWebService.LogInCompletedEventArgs e)
{
string answer = e.Result.ToString();
if (answer.Equals("Success") || answer.Equals("success"))
{
NavigationService.Navigate(new Uri("/Authenticated.xaml", UriKind.Relative));
}
else
{
MessageBox.Show("The log-in details are invalid!");
}
}
}
The code makes use of a web service in order to log-in the user into the system. The log-in system works as it should.
My question is, where should I insert the try catch statement in order to catch exception when the web service is NOT running? I tried in the button_click event handler to no avail and even in the line when I am getting the result.
It's not clear what type your Service1SoapClient is based upon so the statements below may not be accurate. It doesn't appear that you're using the Mobile Services Client since you're passing in a username and password and returning some other state.
However, the ...Async suffix on the LoginAsync method name indicates that this API returns a Task<T> which means that this API is built to be used by the new async and await keywords of C# 5.
Therefore, I recommend altering your code to read as follows:
```
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
}
private async void Button_LogIn_Click(object sender, RoutedEventArgs e)
{
try
{
Service1SoapClient web_service = new Service1SoapClient();
string answer = await web_service.LogInAsync(TextBox_Username.Text, TextBox_Password.Password);
if (answer.ToLower().Equals("success"))
{
NavigationService.Navigate(new Uri("/Authenticated.xaml", UriKind.Relative));
}
else
{
MessageBox.Show("The log-in details are invalid!");
}
catch (<ExceptionType> e)
{
// ... handle exception here
}
}
}
```
Note that one of the side-benefits of async and await is that they allow you to write your code logically, including your exception handling code which, prior to async and await was hard to get right!