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
}
Related
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));
}
}
I have the following:
public async Task<bool> SearchForUpdatesAsync()
{
return await TaskEx.Run(() =>
{
if (!ConnectionChecker.IsConnectionAvailable())
return false;
// Check for SSL and ignore it
ServicePointManager.ServerCertificateValidationCallback += delegate { return (true); };
var configurations = UpdateConfiguration.Download(UpdateConfigurationFileUri, Proxy);
var result = new UpdateResult(configurations, CurrentVersion,
IncludeAlpha, IncludeBeta);
if (!result.UpdatesFound)
return false;
_updateConfigurations = result.NewestConfigurations;
double updatePackageSize = 0;
foreach (var updateConfiguration in _updateConfigurations)
{
var newPackageSize = GetUpdatePackageSize(updateConfiguration.UpdatePackageUri);
if (newPackageSize == null)
throw new SizeCalculationException(_lp.PackageSizeCalculationExceptionText);
updatePackageSize += newPackageSize.Value;
_packageOperations.Add(new UpdateVersion(updateConfiguration.LiteralVersion),
updateConfiguration.Operations);
}
TotalSize = updatePackageSize;
return true;
});
}
As you can see I'm using Microsoft.Bcl.
Now in my other class I wrote this code in a normal void:
TaskEx.Run(async delegate
{
// ...
_updateAvailable = await _updateManager.SearchForUpdatesAsync();
MessageBox.Show("Test");
});
The problem I have is that it executes _updateAvailable = await _updateManager.SearchForUpdatesAsync(); and then it doesn't continue the thread, it just stops as if there is nothing after that call. Visual Studio also tells me this after a while: Thread ... exited with code 259, so something seems to be still alive.
I debugged through it to search for any exceptions that could maybe be swallowed, but nothing, everything works fine and it executes the return-statement.
And that is what I don't understand, I never see the MessageBox and/or no code beyond this line's being executed.
After I talked to some friends, they confirmed that this shouldn't be. Did I make a horrible mistake when implementing async-await?
Thanks in advance, that's actually all I can say about that, I got no more information, I appreciate any tips and help as far as it's possible.
The main issue that you're having is that you're unnecessarily wrapping your method in TaskEx.Run() and you are probably experiencing deadlock somewhere.
Your method signature is currently:
public async Task<bool> SearchForUpdatesAsync()
This means the following:
async --> Doesn't actually do anything, but provides a "heads up" that await might be called within this method and that this method can be used as a runnable Task.
Task --> This method returns a runnable task that can be run asynchronously on the threadpool
<bool> --> This method actually returns bool when awaited.
The await TaskEx.Run() is unnecessarily since this says run this method and then don't return until after a value is available. This is most likely causing a synchronization problem. Removing this construct will make your method work properly, however you'll notice that now you have no reason to even include the async operator or the Task<T> portion since the method is actually synchronous anyway. Usually you're only going to use async identifier on the method signature if you have methods that you are going to call await on them.
Instead you have two options.
Whenever you want to call SearchForUpdates() you can wrap this in a Task<bool>.Run() to run it asynchronously (or the Bcl equivalent)
Since you are using WinForms you might be better off using a BackgroundWorker and just calling this method within it.
Regarding using the async-await pattern I think that this is a great article to use to make sure you're following best practices: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
The best practice is to have async all the way through your layers, and then call await or less desirably .Wait() / .Result at the final use site.
Also, try to keep your UI calls separate from the backend work, since you can run into synchronicity/thread-context issue.
public class WinFormsCode
{
private async Task WinsFormCodeBehindMethodAsync()
{
var updatesAvailable = await _updateManager.SearchForUpdatesAsync();
MessageBox.Show("Updates Available: " + updatesAvailable.ToString());
}
private void WinsFormCodeBehindMethodSync()
{
var updatesAvailable = _updateManager.SearchForUpdatesAsync().Result;
MessageBox.Show("Updates Available: " + updatesAvailable.ToString());
}
}
public class UpdateManager
{
public async Task<bool> SearchForUpdatesAsync()
{
return true;
}
}
I've a scenario:
MyApp calls cameraCapture
that fires a callbackFunction
after the callbackFunction (I have a photo captured) completes, I do more stuff.
So I have to wait for callbackFunction to complete before executing another function. How could i do this?
Here my code:
private static readonly Plustek_Camera.PFNCK_EVENT staticFnCamera = fnPFNCK_EVENT;
public static bool fnPFNCK_EVENT(int iEvent, int iParam, IntPtr pUserData)
{
//capture picture and save to folder
}
//I implement callback start camera and fire a callback staticFnCamera
var _status = CameraCtrl.Start(CameraCtrl.ScanMode, CameraCtrl.Resolution, CameraCtrl.ImageFormat, CameraCtrl.Alignment, staticFnCamera);
//waiting for staticFnCamera complete make sure image produced
ReadPassPortText();
If I understand correctly, you have some camera control that provides an asynchronous API to start capturing an image, but you want to wait synchronously for that operation to complete.
If so, there are lots of different ways to accomplish what you're trying to do. One such way would be to use a TaskCompletionSource:
TaskCompletionSource<bool> source = new TaskCompletionSource<bool>();
var _status = CameraCtrl.Start(CameraCtrl.ScanMode, CameraCtrl.Resolution,
CameraCtrl.ImageFormat, CameraCtrl.Alignment,
(iEvent, iParam, pUserData) =>
{
staticFnCamera(iEvent, iParam, pUserData);
source.SetResult(true);
});
//waiting for staticFnCamera complete make sure image produced
await source.Task;
ReadPassPortText();
Note that the above uses await, which is valid only in an async method. You haven't provided enough context to show exactly how that would work in your code, but I strongly recommend following the above. That will avoid blocking the currently running thread; the async method will return at that point, letting the thread continue to run, and will be resumed at the ReadPassPortText(); statement when the operation completes.
If for some reason you simply cannot use the await in your method, you can instead simply do source.Task.Wait();. This will, of course, block the currently executing thread at that statement.
The above requires .NET 4.5. There are other approaches that work with earlier versions of .NET, but you would need to be specific about your requirements to make it worth trying to describe those.
Edit:
Since you are using .NET 4.0, and presumably Visual Studio 2010, the above won't work for you "out-of-the-box". One option is to download the Async CTP for Visual Studio, which will give you the C# 5.0 compiler that would enable the above. But if that's not feasible for you, another option is to just do what the compiler would do on your behalf, by replacing the last two lines above with the following:
source.Task.ContinueWith(task => ReadPassPortText(),
TaskScheduler.FromCurrentSynchronizationContext());
That would attach the continuation delegate that call ReadPassPortText() to the Task object from the TaskCompletionSource, specifying the current synchronization context as the source of the scheduler to use to actually run the continuation.
The method would return after calling ContinueWith() (just as it would in the await version, except that here it's written out explicitly instead of the compiler doing it for you). When the Task object is set to the completed state, the previously-registered continuation will be executed.
Note that your original question isn't very clear about the context. If the code is running in the UI thread, then using FromCurrentSynchronizationContext() is important and will ensure that the continuation is executed in the UI thread as well. Otherwise, you can probably get away without specifying a scheduler in the call to ContinueWith().
This demonstrates an async-await pattern that you can use. As Peter Duniho points out in the comments, you will have to adapt the pattern to the API that you're using. Try playing with it here at this fiddle to understand how these things work.
using System;
using System.Threading.Tasks;
public class MyApp
{
public static void Main()
{
Console.WriteLine("1. MyApp calls camera capture.");
CameraCaptureAsync().Wait();
}
public async static Task CameraCaptureAsync()
{
Console.WriteLine("2. That calls callbackFunction");
var task = CallbackFunction();
Console.WriteLine("4. In the meantime.");
Console.WriteLine("5. Do some other stuff. ");
await task;
Console.WriteLine("7. Process the " + task.Result);
DoMoreStuff();
}
public async static Task<string> CallbackFunction()
{
Console.WriteLine("3. Which takes a picture.");
await Task.Delay(100);
Console.WriteLine("6. After the callback functions completes");
return "Photograph";
}
public static void DoMoreStuff()
{
Console.WriteLine("8. Do more stuff.");
}
}
After try some implement callback waiting, i try to resolve by adding another form for capturing images (frmSecond).
frmFirst call frmSecond and waiting in 5 to 7 seconds to make sure capture completed.
after that processing ReadPassPortText()
frmFirst Code:
frmReadPassport frmReadPass = new frmReadPassport();
frmReadPass.ShowDialog();
ReadPassPortText();
frmSecondCode
private CAMERACTRL CameraCtrl = null;
//Add static for call from camera start , make sure this alive
private static Plustek_Camera.PFNCK_EVENT staticFnCamera ;
public frmReadPassport()
{
InitializeComponent();
staticFnCamera = fnPFNCK_EVENT;
}
Timer formClose = new Timer();
private void frmReadPassport_Load(object sender, EventArgs e)
{
CaptureImages();
formClose.Interval = 7000; // 7 sec
formClose.Tick += new EventHandler(formClose_Tick);
formClose.Start();
}
private void formClose_Tick(object sender, EventArgs e)
{
//free camera first
// check if camera start then stop
ReleaseResourceCamera();
staticFnCamera =null;
formClose.Stop();
formClose.Tick -= new EventHandler(formClose_Tick);
this.Dispose();
this.Close();
}
private void CaptureImages()
{
CameraCtrl = new CAMERACTRL();
CameraCtrl.LoadCameraDll();
CameraCtrl.GetDeviceList();
String temp = CameraCtrl.GetParameter();
CameraCtrl.Start(CameraCtrl.ScanMode,CameraCtrl.Resolution,CameraCtrl.ImageFormat, CameraCtrl.Alignment, staticFnCamera);
}
public static bool fnPFNCK_EVENT(int iEvent, int iParam, IntPtr UserData)
{
captureImage();
return true;
}
}
I have a call I need to wait to finish to proceed. This is a begincreate for an opportunitySet and I'm having issues converting this into a task to wait for.
_context.BeginSaveChanges(OnCreateOpportunityComplete, _context.OpportunitySet);
/// <summary>
/// Callback method invoked when Account is done being created.
/// </summary>
/// <param name="result"></param>
private void OnCreateOpportunityComplete(IAsyncResult result)
{
try
{
_context.EndSaveChanges(result);
Opportunity createdOpportunity = result.AsyncState as Opportunity;
BeginRetrieveOpportunity(createdOpportunity.OpportunityId);
}
catch (SystemException se)
{
_syncContext.Send(new SendOrPostCallback(showErrorDetails), se);
}
}
private void BeginRetrieveOpportunity(Guid _id)
{
try
{
DataServiceQuery<Opportunity> query = (DataServiceQuery<Opportunity>)_context
.OpportunitySet.Where<Opportunity>(o => o.OpportunityId == _id);
query.BeginExecute(OnRetrieveOpportunityComplete, query);
}
catch (DataServiceQueryException dsqe)
{
_syncContext.Send(new SendOrPostCallback(showErrorDetails), dsqe);
}
}
Does anyone know how to handle this? I've tried numerous times and there seems to be some issues when creating the task. Or if there is any other way for this to wait for the multiple opportunities in the set to be created that would be awesome too.
EDIT: To clarify, the first line in the code is a line in my main function where after I gather all the opportunities I want to add I call the create methods to call the inserts provided in the CRM kit. This does insert, but by the time the program reaches its end more often than not all of the opportunities have not been created.
When making your method, make sure to mark it as "async". Then when calling it don't use the keyword "await" and you will get the its Task. From their you can call yourTask.Wait(). Which will wait until the execution of that method has finalized.
I couldn't really tell what method that you wanted to make async because your question is a little unclear, but if you follow this simple method, you should be able to make your own async method. Let's say you start with this method:
private int DoSomething(int someValue)
{
...
}
We can run it with async in this way:
private async int DoSomethingAsync(int someValue)
{
int result = await Task.Run(() => DoSomething(someValue));
// Do something with result here when it arrives
}
UPDATE >>>
You can use the Task.Wait method in Silverlight. If you take a look at the How to: Wait on One or More Tasks to Complete page on MSDN, you can get an idea of how it is done. This page is only for .NET 4 and 4.5 so I don't know if it will all work with Silverlight but you can try. You can still use your method in a Task like I showed you in the example above.
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!