I'm currently trying to write a simple C#-WPF-Application that functions as a simple universal 'launcher'. For different applications we program.
It's purpose is to check the current software version of the 'real' software and if a new one is available it starts to copy the installer from a network share and runs the installer afterwards.
Then it starts the 'real' application and thats it.
The user Interface mainly consists of a startup window which shows the user the currently executed action (version check, copy, installation, startup, ...).
Now I create my view and my viewModel in the overridden StartUp method in App.cs
public override OnStartup(string[] args)
{
var viewModel = new StartViewModel();
var view = new StartView();
view.DataContext = viewModel;
view.Show();
// HERE the logic for the Launch starts
Task.Run(() => Launch.Run(args));
}
The problem is that if I don't go async here the Main Thread is blocked and I cannot update the UI. Therefore I got it working by using the Task.Run(...). This solves my problem of blocking the UI thread, but I have some problems/questions with this:
I cannot await the task, because that would block the UI again. Where to await it?
Is my concept of starting this workflow here ok in the first place?
Some update to clarify: After I show the UI to the user my logic starts to do heavy IO stuff. The possible calls I came up with are the following 3 variants:
view.Show();
// v1: completely blocks the UI, exceptions are caught
DoHeavyIOWork();
// v2: doesn't block the UI, but exceptions aren't caught
Task.Run(() => DoHeavyIOWork());
// v3: doesn't block the UI, exceptions are caught
await Task.Run(() => DoHeavyIOWork());
Currently I'm not at my work PC so i apologies for not giving you the original code. This is an on the fly created version.
I guess v1 and v2 are bad because of exceptions and the UI blocking.
I thought v3 didn't work when I tried it in my office. Now it seems to work in my local example. But I'm really not sure about v3. Because I'm using async void StartUp(...) there. Is it okay here?
I cannot await the task, because that would block the UI again. Where to await it?
await doesn't block the UI. Using await here is fine.
Is my concept of starting this workflow here ok in the first place?
I usually recommend that some UI is shown immediately when doing any asynchronous operation. Then when the async operation is complete, you can update/replace the UI.
Thanks for all the replys.
After reading all your comments and combining some of your answers I came up with the following example. It is working under all circumstances I tested.
Hopefully there is not to much wrong in your opinion.
Code behind from App.xaml.cs
public partial class App : Application
{
readonly StartViewModel viewModel = new StartViewModel();
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var view = new StartWindow
{
DataContext = viewModel
};
view.Show(); // alternative: Run(view);
// alternative: instead of calling it here it is possible
// to move these calls as callback into the Loaded of the view.
await Task.Run(() => DoHeavyIOWork());
}
private string GenerateContent()
{
var content = new StringBuilder(1024 * 1024 * 100); // Just an example.
for (var i = 0; i < 1024 * 1024 * 2; i++)
content.Append("01234567890123456789012345678901234567890123456789");
return content.ToString();
}
private void DoHeavyIOWork()
{
var file = Path.GetTempFileName();
for (var i = 0; i < 20; i++)
{
File.WriteAllText(file, GenerateContent());
File.Delete(file);
Dispatcher.Invoke(() => viewModel.Info = $"Executed {i} times.");
}
}
}
Code in StartViewModel.cs
class StartViewModel : INotifyPropertyChanged
{
private string info;
public event PropertyChangedEventHandler PropertyChanged;
public string Info
{
get => info;
set
{
info = value;
OnPropertyChanged();
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Related
I am building a screen for my app in xamarin.forms the caul is based on a tabbedpage which is built dynamically based on a list of objects which I get as a result of consuming a service.
After I call the method to consume the API that brings the list, I need to go through it based on certain data of it to fill an observable collection of viewmodels, which will be the tabs. The problem I have is that I do not know how to call the async method that consumes the API in a synchronized way so that the consumption of the API does not conflict with the operation of going through the list.
Then a fraction of the code of my ViewModel:
public MonitoringViewModel()
{
LoadThings();
Tabs = new ObservableCollection<MonitoringTabsViewModel>();
foreach (PcThing t in Things)
{
Tabs.Add(new MonitoringTabsViewModel(t.description));
}
}
private async void LoadThings()
{
Things = new List<PcThing>(await App.WebApiManager.GetCustomerThinksAsync());
}
What I get is that in xamarin live player the app after a few seconds go from the green signal to the red one without showing anything, and in the log of it I get this:
Target of GetEnumerator is null (NullReferenceException)
Since you are doing this in the constructor , I would try the following:
using System.Threading.Tasks;
The risk here is if you are not in control of the LoadThings completing, it can hang.
public MonitoringViewModel()
{
var task = Task.Run(async () => { await LoadThings();}
Task.WaitAll(task); //block and wait for task to complete
public async Task<List<PcThing>> LoadThings()
{
return await App.WebApiManager.GetCustomerThinksAsync();
}
And in your ViewModel
Things = LoadThings().GetAwaiter().GetResult();
I've been struggling with this issue for a while and it's now time for me to ask my question here. So, here's the situation:
I've got a WebAPI, a Xamarin.Android application and an IdentityServer4 implementation. The Xamarin.Android app needs to call the WebAPI to get a list of users based on a search. This is done via an async call in a TextChanged event handler. What happens is that when the call to the WebAPI is awaited, it never returns and at some point the task gets cancelled. I've tried using ConfigureAwait(false), I've made the event handler method async void, I've read through several other questions on here about similar issues - none of the options work for me. But here's some code for you to get an idea of what I've doing:
The TextChanged handler:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.SearchPeopleLayout);
this.searchUsersElement = FindViewById<EditText>(Resource.Id.searchUsersField);
this.usersListElement = FindViewById<ListView>(Resource.Id.usersSearchResult);
using (var scope = App.Container.BeginLifetimeScope())
{
this.apiClient = App.Container.Resolve<IUsersApiClient>();
}
this.searchUsersElement.TextChanged += SearchUsersElement_TextChanged;
}
public async void SearchUsersElement_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
var length = e.Start + e.AfterCount;
if (length <= MinUsernameLength)
{
return;
}
var searchName = string.Join(string.Empty, e.Text);
var users = await this.apiClient.GetUsers(searchName, Persistor.ApiClient);
RunOnUiThread(() =>
{
var usersAdapter = new UsersAdapter(this, users.ToList());
this.usersListElement.Adapter = usersAdapter;
});
}
Here's the UsersApiClient implementation:
public async Task<IEnumerable<UserModel>> GetUsers(string username, HttpClient client)
{
try
{
var content = await client.GetStringAsync($"{apiUrl}/users?name={username}").ConfigureAwait(false);
var result = JsonConvert.DeserializeObject<IEnumerable<UserModel>>(content);
return result;
}
catch (Exception ex)
{
throw ex;
}
}
The deadlock happens on the GetStringAsync() call. I've tested the call that it makes via Postman and it is giving me the correct response. Only things I haven't tried yet are implementing the ITextWatcher interface instead of adding an event handler, and changing the code so I don't use a separate method but rather an anonymous delegate - I read in some places that that could prove to be an issue.
I'm really hoping some of you can help me in resolving this issue and making me understand how to do such asynchronous calls correctly.
Best regards.
Okay, so I'm not really sure what fixed the issue, but here's what I did - there was another StackOverflow question with a similar problem where the problem was solved with uninstalling the app from the emulator manually before redeploying it. I also removed the ConfigureAwait(false) call. And suddenly, everything's working. Not sure how it happened, but here it is - uninstalling the app manually and calling the API without the ConfigureAwait(false) did it.
I'm working on an Export-Tool from a Database which I had written in Visual Basic.net before a long time.
I switched to C# and like to reprogram it in C# since I've gathered quite a little bit more experience than I had before :-)
My C# application's UI is hanging because there is a big database query to do. So I've informed myself about asynchronous programming. Tried threads and tasks as well but I'm having problems to find the right method for my concerns.
This is what I have: it's a Windows Forms application and there's a start button which creates a new thread.
The Method called Export is a non static method which I've created in a second class file named actions.cs. It's non static because the method should be reused often in the code but with different parameters.
So I instantiated the method in the Button_Clicked Event on Form1 with the corresponding parameters:
actions KuliMon = new actions()
{
ExportPath = settings.ReadActSetting("baexport", "ExportPfad", ""),
Trennzeichen = settings.ReadGlobSetting("Trennzeichen", ";"),
ConnectionString = settings.ReadGlobSetting("Mand1_odbc", ""),
SQLFile = "kuli.sql",
ExportAktion = "kuli"
};
Then I've started the thread from the Button_click event like this:
Thread ExportThread = new Thread(KuliMon.Export);
ExportThread.Start();
This works. No sticking GUI. But now there is the problem. My method Export in actions.cs is exporting the DB-Query into a csv-File but should also return the result in a string variable which then I can display in a TextBox on Form1.
By reading a little bit around I've found the Invoke-Method this helped quite a little bit. Under Thread.Start() I've added the following:
this.Invoke((MethodInvoker)delegate
{
tx_main_t1.Text = "Hello";
});
When I've clicked the button the TextBox says "hello". But instead of hello I need the Return string from my method Export running in the thread. And here's the problem how can I get the string with the queried results.
In my understanding the thread method has to call a void-method and must not return a value.
I had an idea of creating a public property string and fill the string in Export with the return value like this:
public string results { get; set; }
Instead of using return ReturnValue in Method Export I've tried
results = ReturnValue;
In Form1 I then tried to fill the TextBox with KuliMon.results but it's empty because I've made an instance of Export as I think.
Both database queries and writing to files are I/O-bound operations, so they are a natural fit for async and await.
First, you would define an asynchronous version of KuliMon.Export:
async Task<string> ExportAsync()
{
var data = await myQuery.ToListAsync();
await myStream.WriteAsync(...);
return results;
}
You can, for example, use Entity Framework 6 for asynchronous query support.
Then you can call it from your UI as such:
async void button1_Clicked(...)
{
TextBox1.Text = await myInstance.ExportAsync();
}
If you can't use asynchronous database queries for whatever reason (e.g., I think Oracle doesn't support them at this time), then you can use a background thread that calls the synchronous APIs. Note that Task.Run is a modern replacement for both Thread and BackgroundWorker:
string Export();
...
async void button1_Clicked(...)
{
TextBox1.Text = await Task.Run(() => myInstance.Export());
}
You should look in to the BackGroundWorker class
https://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx
You can assign a function to call when the worker completes the job, and have that function update your UI.
using async await supported in .Net 4.5 and c#5 (you can get support for this in erarlier .Net versions with AsyncBridge package for 3.5 or for 4.0)
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
try
{
//Code will wait here for your method to return without blocking UI Exceptions or Result will be automatically Scheduled to UI thread
string result = await DoStuffAsync("myParameter");
}
catch
{
MessageBox.Show("Ups an error");
}
finally
{
button1.Enabled = true;
}
}
/// <summary>
/// Wraps the synchron implementation off DoStuff
/// </summary>
public Task<string> DoStuffAsync(string s)
{
return Task.Factory.StartNew(DoStuff, s); //here parameter s is forwarded to your synchronus implementation
}
/// <summary>
/// Your orginal synchron implementation with the dbQuerry
/// or long running calculations
/// </summary>
public string DoStuff(string s)
{
//do your normal code;
return result
}
I am new the using Task.Run() along with async and await to make UI more responsive, so likely I have not implemented something correctly.
I have reviewed the great articles from Stephen Cleary about using AsyncCommands and have used his code from Patterns for Asynchronous MVVM Applications: Commands as a basis for having a responsive UI but when I run the code it still seems to freeze up (I am not able to move the window or interact with other buttons until the function has fully finished.
I am trying to perform a search which usually takes 5-10 seconds to return. Below is the code that creates the AsyncCommand along with the what the function does.
Code:
public ICommand SearchCommand
{
get
{
if (_SearchCommand == null)
{
_SearchCommand = AsyncCommand.Create(() => Search());
}
return _SearchCommand;
}
}
private async Task Search()
{
IEnumerable<PIPoint> points = await SearchAsync(_CurrentPIServer, NameSearch, PointSourceSearch).ConfigureAwait(false);
SearchResults.Clear();
foreach (PIPoint point in points)
{
SearchResults.Add(point.Name);
}
}
private async Task<IEnumerable<PIPoint>> SearchAsync(string Server, string NameSearch, string PointSourceSearch)
{
{
PIServers KnownServers = new PIServers();
PIServer server = KnownServers[Server];
server.Connect();
return await Task.Run<IEnumerable<PIPoint>>(()=>PIPoint.FindPIPoints(server, NameSearch, PointSourceSearch)).ConfigureAwait(false);
}
}
I am thinking that the issue is somewhere in how I am pushing the long running function onto a thread and its not getting off of the UI thread or my understanding of how Tasks and async/await are completely off.
EDIT 1:
Following Stephen's answer I updated the functions, but I am not seeing any change in the UI responsiveness. I created a second command that performs the same actions and I get the same response from UI in either case. The code now looks like the following
CODE:
public ICommand SearchCommand
{
get
{
if (_SearchCommand == null)
{
_SearchCommand = AsyncCommand.Create(async () =>
{
var results = await Task.Run(()=>Search(_CurrentPIServer, NameSearch, PointSourceSearch));
SearchResults = new ObservableCollection<string>(results.Select(x => x.Name));
});
}
return _SearchCommand;
}
}
public ICommand SearchCommand2
{
get
{
if (_SearchCommand2 == null)
{
_SearchCommand2 = new RelayCommand(() =>
{
var results = Search(_CurrentPIServer, NameSearch, PointSourceSearch);
SearchResults = new ObservableCollection<string>(results.Select(x => x.Name));
}
,()=> true);
}
return _SearchCommand2;
}
}
private IEnumerable<PIPoint> Search(string Server, string NameSearch, string PointSourceSearch)
{
PIServers KnownServers = new PIServers();
PIServer server = KnownServers[Server];
server.Connect();
return PIPoint.FindPIPoints(server, NameSearch, PointSourceSearch);
}
I must be missing something but I am not sure what at this point.
EDIT 2:
After more investigation on what was taking so long it turns out the iterating of the list after the results are found is what was hanging the process. By simply changing what the Search function was returning and having it already iterated over the list of objects allows for the UI to remain responsive. I marked Stephen's answer as correct as it handled my main problem of properly moving work off of the UI thread I just didnt move the actual time consuming work off.
My first guess is that the work queued to Task.Run is quite fast, and the delay is caused by other code (e.g., PIServer.Connect).
Another thing of note is that you are using ConfigureAwait(false) in Search which updates SearchResults - which I suspect is wrong. If SearchResults is bound to the UI, then you should be in the UI context when updating it, so ConfigureAwait(false) should not be used.
That said, there's a Task.Run principle that's good to keep in mind: push Task.Run as far up your call stack as possible. I explain this in more detail on my blog. The general idea is that Task.Run should be used to invoke synchronous methods; it shouldn't be used in the implementation of an asynchronous method (at least, not one that is intended to be reused).
As a final note, async is functional in nature. So it's more natural to return results than update collections as a side effect.
Combining these recommendations, the resulting code would look like:
private IEnumerable<PIPoint> Search(string Server, string NameSearch, string PointSourceSearch)
{
PIServers KnownServers = new PIServers();
PIServer server = KnownServers[Server];
// TODO: If "Connect" or "FindPIPoints" are naturally asynchronous,
// then this method should be converted back to an asynchronous method.
server.Connect();
return PIPoint.FindPIPoints(server, NameSearch, PointSourceSearch);
}
public ICommand SearchCommand
{
get
{
if (_SearchCommand == null)
{
_SearchCommand = AsyncCommand.Create(async () =>
{
var results = await Task.Run(() =>
Search(_CurrentPIServer, NameSearch, PointSourceSearch));
SearchResults = new ObservableCollection<string>(
results.Select(x => x.Name));
});
}
return _SearchCommand;
}
}
I'm trying to transition from the Event-based Asynchronous Pattern where I tracked running methods using unique id's and the asynoperationmanager. As this has now been dropped from Windows 8 Apps I'm trying to get a similar effect with Async/Await but can't quite figure out how.
What I'm trying to achieve is something like
private async Task updateSomething()
{
if(***the method is already running***)
{
runagain = true;
}
else
{
await someMethod();
if (runagain)
{
run the method again
}
}
}
The part I'm struggling with is finding out if the method is running. I've tried creating a Task and looking at the status of both that and the .status of the async method but they don't appear to be the correct place to look.
Thanks
UPDATE: This is the current code I use in .net 4 to achieve the same result. _updateMetaDataAsync is a class based on the Event-Based Asynchronous Pattern.
private void updateMetaData()
{
if (_updateMetaDataAsync.IsTaskRunning(_updateMetaDataGuid_CheckAllFiles))
{
_updateMetaDataGuid_CheckAllFiles_Again = true;
}
else
{
_updateMetaDataGuid_CheckAllFiles_Again = false;
_updateMetaDataAsync.UpdateMetaDataAsync(_updateMetaDataGuid_CheckAllFiles);
}
}
private void updateMetaDataCompleted(object sender, UpdateMetaDataCompletedEventArgs e)
{
if (_updateMetaDataGuid_CheckAllFiles_Again)
{
updateMetaData();
}
}
async/await itself is intended to be used to create sequential operations executed asynchronously from the UI thread. You can get it to do parallel operations, but generally the operations "join" back to the UI thread with some sort of result. (there's also the possibility of doing "fire-and-forget" types of asynchronous operations with await but it's not recommended). i.e. there's nothing inherent to async/await to support progress reporting.
You can get progress out of code using async/await; but you need to use new progress interfaces like IProgress<T>. For more info on progress reporting with async/await, see http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx. Migrating to this should just be a matter of calling an IProgress delegate instead of a Progress event.
If you're using a Task you've created, you can check the Task's Status property (or just see Task.IsCompleted if completion is the only state you are interested in).
That being said, await will not "return" until the operation either completes, raises an exception, or cancels. You can basically safely assume that, if you're still waiting on the "await", your task hasn't completed.
SemaphoreSlim queueToAccessQueue = new SemaphoreSlim(1);
object queueLock = new object();
long queuedRequests = 0;
Task _loadingTask;
public void RetrieveItems() {
lock (queueLock) {
queuedRequests++;
if (queuedRequests == 1) { // 1 is the minimum size of the queue before another instance is queued
_loadingTask = _loadingTask?.ContinueWith(async () => {
RunTheMethodAgain();
await queueToAccessQueue.WaitAsync();
queuedRequests = 0; // indicates that the queue has been cleared;
queueToAccessQueue.Release()
}) ?? Task.Run(async () => {
RunTheMethodAgain();
await queueToAccessQueue.WaitAsync();
queuedRequests = 0; // indicates that the queue has been cleared;
queueToAccessQueue.Release();
});
}
}
}
public void RunTheMethodAgain() {
** run the method again **
}
The added bonus is that you can see how many items are sitting in the queue!