CancellationToken with await Task - wpf

I want to use CancellationToken in my GUI but it doesn't work.
When I click on the cancel button I want to cancel the operation
this.tokenSource.Cancel();
In other place I have other button that need to do main operation. The main part includes Task and CancellationToken token and this part doesn works
private CancellationTokenSource tokenSource;
private async void DataSynchronization(object notInUse)
{
this.tokenSource = new CancellationTokenSource();
CancellationToken ct = new CancellationToken();
ct.ThrowIfCancellationRequested();
await Task.Run(() =>
{
try
{
// do main operation
}
catch (Exception e)
{
}
finally
{
// final operation
}
if (ct.IsCancellationRequested)
{
ct.ThrowIfCancellationRequested();
}
}, this.tokenSource.Token)
.ContinueWith(
completedTaskResult =>
{
// I want to check if cancel was presed
}
);
}
This is main structure but something wrong. I don't receive cancel operation

There are several problems here. First you shouldn't create your own CancellationToken, that's what CancellationTokenSource is for! It's the source for your token. Second, you should use the Run overload that takes a CancellationToken as the second argument, and third, you need to check the CancellationToken.IsCancellationRequested property in your do main operation to see if it's been cancelled and stop doing what you are doing if it is.
See here for a good example.
So you code might end up looking something like:
this.tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
await Task.Run(() =>
{
while(notDone && !token.IsCancellationRequested)
{
// do some stuff
}
}, token);
Now when you do:
this.tokenSource.Cancel();
It will signal to the associated Token that the operation is cancelled and somewhere inside your task you'll pick that up and stop doing that thing.

Related

Flutter .listen called multiple times

I using https://pub.dev/packages/flutter_uploader in my project.
repository
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
final taskId = await uploader.enqueue(
url:
'https://xxxx',
files: files,
data: {
....
},
method: UploadMethod.POST,
showNotification: true,
tag: title);
final subscription = uploader.result.listen((result) async {
print("response " + result.response);
}, onError: (ex, stacktrace) {
print(ex.toString());
});
}
} catch (e) {
...
}
}
When first time I call this, uploader.result.listen will only print once. But if I call this method again, uploader.result.listen will call twice. Why?
Edit
I have changed my code to this
PageA
StreamSubscription<UploadTaskResponse> _subscription;
FlutterUploader uploader = FlutterUploader();
#override
void initState() {
super.initState();
_subscription = uploader.result.listen(
(result) {
// insert result to database
.....
},
onError: (ex, stacktrace) {
// ... code to handle error
},
);
}
void dispose() {
super.dispose();
_subscription.cancel();
_defectBloc.dispose();
}
In page A, it has floatingActionButton. When the floating action button is clicked, it will open page B. I will pass the uploader param to PageB and bloc, so it can listen to the uploader. Data able to insert into local database if I on the init page. How can I let the insert work too if I exit the app?
When you call uploader.result.listen it'll add a subscription each time, if you call that n times, n subscription will be added.
To fix the issue, either you need to cancel previous subscription using cancel() method or you have to add the subscription only once (In your initState and cancel in your dispose method).

WPF , howto to know that a task has completed

I am developping a MVVM WPF app, and I have some task to do.
first load files csv and parse it
In background don´t block the ui Thread and save the values in the database.To save the rows to the database I need to be with Async Await Task.
My problem is I don´t know how to notice the user with a popup notification or something else that values are already saved in database.
in My ViewModel
private void SaveDatasInDatabase()
{
ShowLoadingPanel = true;
_service.SaveValuesInDatabase(rows);
}
private async void startActions()
{
await LoadandParseCsv();
await SaveDatasInDatabase();
}
in my Service.cs
public string SaveDatasInDatabase(List<Object> rows)
{
Task.Run(async () =>
{
await SaveEntity(rows);
return "Done";
});
}
Thanks in advance.
Jolynce
You know that the task has completed once the remainder of the startActions() method is executed:
private async void startActions()
{
await LoadandParseCsv();
await SaveDatasInDatabase();
MessageBox.Show("done");
}
...provided that actually await the SaveEntity method in the SaveDatasInDatabase() method:
public async Task<string> SaveDatasInDatabase(List<Object> rows)
{
await SaveEntity(rows);
return "Done";
}
If you just call Task.Run without awaiting the returned Task, you don't know when it has finished.
The return type of the SaveDatasInDatabase method should be Task or Task<T> for you to be able to await it. The same thing applies to the SaveEntity method.

Nancy perform AfterRequest action after OnError

I want to add some request timings to the response headers of a request to a Nancy module. I've added some before/after request handlers into the RequestStartup and added the headers no problem (example below) and all was good. I've also added an OnError handler to the ApplicationStartup, to catch errors and return a nice formatted Json response.
pipelines.BeforeRequest += ctx =>
{
ctx.Items.Add("X-RequestStart", DateTime.Now.ToString());
return null;
};
pipelines.AfterRequest += ctx =>
{
var now = DateTime.Now;
try
{
//Not got around to forcing the culture on the datetime parsing yet...
var startTime = DateTime.Parse(ctx.Items["X-RequestStart"].ToString());
ctx.Response.Headers.Add("X-RequestStart", startTime.ToString(CultureInfo.InvariantCulture));
ctx.Response.Headers.Add("X-RequestComplete", now.ToString(CultureInfo.InvariantCulture));
ctx.Response.Headers.Add("X-RequestDuration", (now - startTime).ToString());
}
catch (Exception)
{
ctx.Response.Headers.Add("X-RequestComplete", now.ToString(CultureInfo.InvariantCulture));
}
};
pipelines.OnError += (ctx, exception) =>
{
return ErrorResponse.FromException(exception);
};
What I am noticing however, is that when I have an error thrown, the AfterRequest action is not performed - thus I have no timing headers in to the error response. I've tried moving the before/after request handling to the application startup, but this has no effect either.
The question is in two parts really, firstly, is it possible to get the framework to perform an AfterRequest action after the OnError action has been performed, or is the pipeline set up in a way to prevent this, and secondly, should these before/after request actions be part of the RequestStartup or ApplicationStartup? ApplicationStartup seemed sensible for error handling, whereas RequestStartup seemed sensible for interacting with the response headers as it should be on a per request basis, but I'm not sure if there is a convention for this, or if my assumptions were incorrect.
Unfortunately, this does not seem possible in NancyFx. I took a detailed look at the source code, specifically DefaultRequestDispatcher. Dispatch catches any exceptions thrown during route processing, calls ResolveErrorResult, then gets the response from the negotiator. There does not appear to be an extensibility point to modify responses generated in this way.
In my opinion, this is an oversight that the developers should consider addressing.
public async Task<Response> Dispatch(NancyContext context, CancellationToken cancellationToken)
{
// TODO - May need to make this run off context rather than response .. seems a bit icky currently
var resolveResult = this.Resolve(context);
context.Parameters = resolveResult.Parameters;
context.ResolvedRoute = resolveResult.Route;
try
{
context.Response = await ExecuteRoutePreReq(context, cancellationToken, resolveResult.Before)
.ConfigureAwait(false);
if(context.Response == null)
{
context.Response = await this.routeInvoker.Invoke(resolveResult.Route, cancellationToken,
resolveResult.Parameters, context)
.ConfigureAwait(false);
if (context.Request.Method.Equals("HEAD", StringComparison.OrdinalIgnoreCase))
{
context.Response = new HeadResponse(context.Response);
}
}
await this.ExecutePost(context, cancellationToken, resolveResult.After, resolveResult.OnError)
.ConfigureAwait(false);
}
catch(Exception ex)
{
context.Response = this.ResolveErrorResult(context, resolveResult.OnError, ex);
if (context.Response == null)
{
throw;
}
}
return context.Response;
}
private Response ResolveErrorResult(NancyContext context, Func<NancyContext, Exception, dynamic> resolveResultOnError, Exception exception)
{
if (resolveResultOnError != null)
{
var flattenedException = exception.FlattenInnerExceptions();
var result = resolveResultOnError.Invoke(context, flattenedException);
if (result != null)
{
return this.negotiator.NegotiateResponse(result, context);
}
}
return null;
}

Silverlight async unit testing

I'm having a weird issue with Silverlight Unit Test Framework. The very first method executed fails, every time. I have a second test with the exact same code, and it passes. The strange thing about the first time it's called is that it actually waits for the timeout and then executes the repository call (underneath it's an HTTP PUT if you care). Here's the code - the first one fails every time, second one passes every time:
[TestMethod]
public void AuthShouldSucceed()
{
var autoResetEvent = new AutoResetEvent(false);
_authRepository.Authenticate(_username, _password, response =>
{
Assert.IsTrue(response);
autoResetEvent.Set();
});
if (!autoResetEvent.WaitOne(Constants.Timeout))
{
Assert.Fail("Test timed out.");
}
}
[TestMethod]
public void AuthShouldSucceed2()
{
var autoResetEvent = new AutoResetEvent(false);
_authRepository.Authenticate(_username, _password, response =>
{
Assert.IsTrue(response);
autoResetEvent.Set();
});
if (!autoResetEvent.WaitOne(Constants.Timeout))
{
Assert.Fail("Test timed out.");
}
}
Edit:
My final solution is a modification of Vladmir's solution:
[TestMethod]
[Asynchronous]
public void AuthShouldSucceed()
{
var complete = false;
var result = false;
_authRepository.Authenticate(_username, _password, response =>
{
complete = true;
result = response;
});
EnqueueConditional(() => complete);
EnqueueCallback(() => Assert.IsTrue(result));
EnqueueTestComplete();
}
If you're using Silverlight Unit Tests Framework try to rewrite your test next way:
[TestMethod]
[Asynchronous]
public void AuthShouldSucceed()
{
var done = false;
var authResult = false;
_authRepository.Authenticate(_username, _password, response =>
{
var done = true;
authResult = response;
});
EnqueueConditional(() => done);
EnqueueCallback(() => Assert.IsTrue(authResult));
EnqueueTestComplete();
}
Your test class should be derived from SilverlightTest class:
[TestClass]
public class MyTests: SilverlightTest
Summarizing all written you should be aware of couple important points in writing Unit Tests for Silverlight.
[Asynchronous]
Attribute of test method shows that you are testing part which includes async operations and want to syncronize them for testing purposes. Asynchrony itself in Silverlight Unit Tests Framework is a bit distorted. All "Enqueue" directives are like "postpone this until something happens" which is not a sense which the traditional programming asynchrony meaning has.
EnqueueConditional
Otherwords means wait until condition will be met. And this is one of the most important parts of async tests. After condition becomes legal all EnqueueCallbacks until the next EnqueueConditional will be executed.
Important note:
EnqueueConditional repeatedly calls the predicate passed to it on a
timer/background thread, checking each time to see if it returns true.
That's why you should avoid using heavy, complex logic within conditions.
EnqueueCallback
Defers code execution until EnqueueConditional that precedes it will met condition. It enqueues an Actoin or an array of Actions.
EnqueueDelay
Enqueues minimum number of milliseconds/time delay before continuing.
EnqueueTestComplete
Enqueues an action to call TestComplete which signals that a test is complete when using Async testing.
Important Note(from documentation):
If you use your own methods for completing, such as an HtmlTimer or
other threading method, it is possible that this call will occur
AFTER the test has timed out when using Timeouts. As such, be very careful as you could complete the call to the next test.
You can use the Asynchronous keyword in the TestMethod
[TestMethod]
[Asynchronous]
[Description("This test checks when NULL is passed")]
public void Testing()
{
bool done = false;
EnvViewModel test = new EnvViewModel ();
.
.
test.AsyncCallBackCompleted += (() => done = true);
EnqueueCallback(() => test.DataCommand.Execute(null));
EnqueueConditional(() => done);
EnqueueCallback(() => Assert.IsTrue(test.AADTDecisionModelList.Count == 0,
"The result does not have any data."));
EnqueueTestComplete();
}
And make a delegate in the ViewModel to be used to every method that is being tested...
public delegate void AsynCallComplete();
public event AsynCallComplete AsyncCallBackCompleted;
public void InformCallbackCompleted()
{
if (AsyncCallBackCompleted != null)
{
AsyncCallBackCompleted();
}
}

Surviving TPL, Delegates, Threads, and Invokes

I'm facing a serious problem of deadlock in a multithreaded desktop/windows application. I fear I'm not using the correct approach to delegates in a very async environment. Also, even though I "sink" my events into the calling UI thread, if possible, I still have to Invoke on the UI thread to see some action. Follows, is the details.
The application is basically a client for users of an online file storage service. That service exposes functionality through REST calls. I first created a managed code wrapper DLL for such calls that allows for a .NET consumer to create a static instance of this DLL and call the functions. I'll take the file upload operation as an example.
Now, in the wrapper, here is the public interface for a file upload:
public Int32 UploadFile(FileSystemObject FolderToUploadTo, FileInfo LocalFileAndPath, OperationProgressReportEventHandler onOperationProgressReport, FileSystemObjectUploadCompletedEventHandler onOperationCompleted) {
Int32 ReplyNumber = 0;
try {
var TheOperation = new UploadFileObjectOperation(FolderToUploadTo, LocalFileAndPath, _User.APIKey) {
onProgressReport = onOperationProgressReport,
onUploadCompleted = onOperationCompleted
};
//Add it to the pool of operations
OperationPool.Add(TheOperation);
//Start the operation through the factory
OperationFactory.StartNew(() => {
TheOperation.Start();
});
//Chain the *actual* TPL Task to flush after usage
TheOperation.InnerTask.ContinueWith(t => {
t.Dispose(); //Dispose the inner task
OperationPool.Remove(TheOperation); //Remove the operation from the pool
TheOperation = null; //Nullify the Operation
});
ReplyNumber = TheOperation.TaskId;
}
catch {
ReplyNumber = 0;
}
return ReplyNumber;
}
As you can see, the actual UI application, that will refer this DLL, will be sending delegates for progress and completed to the operation(s). Now, the body of the operation itself:
public class UploadFileObjectOperation : BaseOperation, IDisposable {
//Store
public FileSystemObjectUploadCompletedEventHandler onUploadCompleted;
//Constructors
//Disposing stuff
protected override void PerformWork() {
try {
//Init the WebClient
UploadClient.UploadProgressChanged += (UploadProgressChanged_s, UploadProgressChanged_e) => {
//This is my event in base class being raised
ReportProgress(UploadProgressChanged_e.ProgressPercentage, UploadProgressChanged_e);
};
UploadClient.UploadFileCompleted += (UploadFileCompleted_s, UploadFileCompleted_e) => {
if (UploadFileCompleted_e.Error != null) {
throw new ApplicationException("Upload failed. " + UploadFileCompleted_e.Error.Message);
}
JObject JSONLiveObject = JObject.Parse(Encoding.UTF8.GetString(UploadFileCompleted_e.Result));
if (String.Compare((String)JSONLiveObject["status"], Constants._CONST_RESTRESPONSE_STATUS_VALUE_FAIL, false) == 0) {
throw new ApplicationException("Upload response failed. " + (String)JSONLiveObject["result"]["message"]);
}
//Eureka! Success! We have an upload!
//This is my event being raised
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = null,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Success,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
};
//Start the async upload
UploadClient.UploadFileAsync(AddressOfRESTURI, UploadingMethod, _FileToUpload.FullName);
}
catch (OperationCanceledException exp_Canceled) {
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = exp_Canceled,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Canceled,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
// To ensure that the calling code knows the task was canceled
//throw;
}
catch (Exception exp) {
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = exp,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Error,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
// If the calling code also needs to know.
//throw;
}
}
protected void UploadTaskCompleted(UploadFileObjectOperationEventArg arg) {
if (onUploadCompleted == null)
return;
//Sinking into calling UI thread, if possible
if (onUploadCompleted.Target is Control) {
Control targetForm = onUploadCompleted.Target as Control;
targetForm.Invoke(onUploadCompleted, new object[] { arg });
}
else {
onUploadCompleted(arg);
}
Status = OperationRunningStatus.Completed;
}
}
The PerformWork() raises the two events: Progress reporting and completion. Note that while raising an event, I check if can get a route to the calling thread and push the event directly so to avoid invokes at UI.
Now, lets see how I'm using all of the above in a desktop client:
private void UploadFile(FileInfo DraggedFileInfo, FileSystemObject ParentDefination) {
SessionLifetimeStuff.APICore.UploadFile(ParentDefination, DraggedFileInfo,
(PercentageCompleted) => {
#region Progress
this.InvokeEx(f => {
UpdateTaskProgress(newTaskQueue.OID, PercentageCompleted.Progress, PercentageCompleted);
});
#endregion
}, (Result) => {
#region Completion
this.InvokeEx(f => {
switch (Result.Status) {
case OperationExitStatus.Success:
Console.WriteLine(String.Format("File: {0} uploaded to {1}", Result.UploadedFileSystemObject.DocumentFullname, Result.UploadedFileSystemObject.FolderId));
break;
case OperationExitStatus.Canceled:
DialogManager.ShowDialog(DialogTypeEnum.Warning, "Dropbox", "Upload canceled.", null, this);
break;
case OperationExitStatus.Error:
DialogManager.ShowDialog(DialogTypeEnum.Error, "Dropbox", "Upload failed.", Result.Error, this);
break;
}
});
#endregion
});
}
I'm using an extension method I found on Stackoverflow for adding the Invoking functionality:
public static class InvokeExtensions {
public static void InvokeEx<T>(this T #this, Action<T> action) where T : Control {
if (#this.InvokeRequired) {
#this.Invoke(action, new object[] { #this });
}
else {
if (!#this.IsHandleCreated)
return;
if (#this.IsDisposed)
throw new ObjectDisposedException("#this is disposed.");
action(#this);
}
}
public static IAsyncResult BeginInvokeEx<T>(this T #this, Action<T> action)
where T : Control {
return #this.BeginInvoke((Action)(() => #this.InvokeEx(action)));
}
public static void EndInvokeEx<T>(this T #this, IAsyncResult result)
where T : Control {
#this.EndInvoke(result);
}
}
In my code, i have commented out the invokes as I though i don't need then as the events being raised are coming in sinked. However, i realized that my UI was not doing anything at all. So, I added the InvokeEx({ code; }) and my UI started to shoe activity.
Now, why do I need to invoke?
If I attempt different operations from UI, eventually, my UI freezes although the application still behaves as normally functioning.
I found an old article at http://msdn.microsoft.com/en-us/library/ff649143.aspx#scag-ch06_topic4 that described the usage of delegates and I see that there is a IAsyncResult involved.
Could someone point me as to where I'm going wrong here?
Update:
Ok, with the invoking code commented on the UI, I get no activity at all. But upon using the this.InvokeEx or wrapping a work in this.BeginInvokeEx, I get UI updates but after a while, here are the two exceptions occurring (in this order):
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

Resources