I want the method PrintOrderAsync to execute an external EXE to print an order.
The code for method PrintOrderAsync does not show any syntax errors
public async Task<string> PrintOrderAsync(string PrintExe, string ExePath, int nOrderNo)
{
await Task.Factory.StartNew(() => Process.Start(ExePath + PrintExe, nOrderNo.ToString()));
return "";
}
But I am struggling with the syntax for the calling method. Here is what I tried:
Task<string> result = PrintOrderAsync(PrintExe, ExePath, nOrderNo);
And I see syntax error on the above line. What am I missing?
Based on the code that you have shared here you are starting a process. This is concerning as you are not actually waiting for the result of the process, in fact -- it is fire and forget regardless of the async and await keywords unless you wait for the process to exit. There are several ways to do this:
public static Task WaitForExitAsync(this Process process,
int milliseconds,
CancellationToken cancellationToken = default(CancellationToken))
{
return Task.Run(() => process.WaitForExit(milliseconds), cancellationToken);
}
For example, here is an extension method you could use to wrap the waiting for the process in a Task. It could then be awaited like this:
public async Task PrintOrderAsync(string PrintExe, string ExePath, int nOrderNo)
{
return Process.Start(ExePath + PrintExe, nOrderNo.ToString())
.WaitForExitAsync(5000);
}
// Then you could await it wherever...
await PrintOrderAsync(PrintExe, ExePath, nOrderNo);
Alternatively, if you do not want to wait for it to complete (i.e.; you want fire and forget, like you have now) do this:
Process.Start(ExePath + PrintExe, nOrderNo.ToString())
Do not wrap it in a Task or anything, it is an entirely separate process anyways (personally, I prefer the first option I shared).
Try
string result = await PrintOrderAsync(PrintExe, ExePath, nOrderNo);
Related
Dart newbie here, I'm currently learning about asynchronous execution in Dart. I'm a bit irritated about how concurrency works in Dart, take the following scenario from their codelab:
void printOrderMessage () async {
try {
var order = await fetchUserOrder();
print('Awaiting user order...');
print(order);
} catch (err) {
print('Caught error: $err');
}
}
Future<String> fetchUserOrder() {
// Imagine that this function is more complex.
var str = Future.delayed(Duration(seconds: 4), () => throw 'Cannot locate user order');
return str;
}
Future<void> main() async {
await printOrderMessage();
}
In this case, the asynchronous operation is fetching the the user order from say a DB. Now because of Dart's await / async mechanism, every function that is related to the async operation is required to have a Future<> return type and must be tagged with async.
This feels clunky ... Imagine if some value deep in my function chain is being calculated asynchronously, would I really need to always return a future? Is there some other construct to synchronize code in Dart than await? Or have I misunderstood the concept?
If callers need to be able to wait for your asynchronous operation to finish, then your asynchronous function must return a Future that can be awaited. This is contagious; if callers of those callers need to be able to wait, then they too need to have Futures to wait upon.
If callers should not wait, then you can have a "fire-and-forget" function that does not need to return a Future:
Future<void> foo() {
// ...
}
// Does not need to return a Future. Consequently, callers cannot
// directly determine when `foo` completes.
void bar() {
foo();
}
Is there a way to cancel background task made with HostingEnvironment.QueueBackgroundWorkItem?
There is CancellationToken which notifies if tasks was cancelled but how can i do it?
Refering to https://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx
A successful cancellation involves the requesting code calling the CancellationTokenSource.Cancel method
OK. Where can i get access to CancellationTokenSource?
After few trials i came up with the soulution:
HostingEnvironment.QueueBackgroundWorkItem(ct =>
{
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ct);
var cancellationToken = linkedTokenSource.Token;
return Task.Factory.StartNew(() =>
{
// do stuff on background
}, cancellationToken);
});
Update:
Indeed, task is not needed. Thanks svick for bringing that up.
Here is a bit more detailed code sample without task.
HostingEnvironment.QueueBackgroundWorkItem(ct =>
{
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ct);
// following is a dummy method, but you get the idea.
// StoreCancellationTokenSourceSoItCanBeUsedSomewhereElse(linkedTokenSource);
var cancellationToken = linkedTokenSource.Token;
try
{
while(true)
{
cancellationToken.ThrowIfCancellationRequested();
// do bg stuff
}
}
catch (OperationCanceledException ex)
{
// either token is in cancelled state
}
});
The signature of HostingEnvironment.QueueBackgroundWorkItem is:
public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem)
This means that a work item gets access to a CancellationToken. But I don't think that's useful in your case. From the documentation:
The provided CancellationToken will be signaled when the application is shutting down.
If you want to cancel the workItem based on some other condition, you can use a separate CancellationToken, which you create from a CancellationTokenSource. For example, to cancel a work item if it doesn't start within 10 seconds:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
HostingEnvironment.QueueBackgroundWorkItem(_ =>
{
cts.Token.ThrowIfCancellationRequested();
// the code of the work item goes here
});
This will technically still start the work item, even if the CancellationToken is cancelled, but it won't do anything.
Note that cancellation is always cooperative. This means that if you have a long-running work item, and you want to cancel it in the middle of its execution, you will need to keep checking the CancellationToken periodically.
I am using MVVM, inparticular MVVMLight. For boradcasting to all of my modelviews, that no internet connection is available I am using Messenger class. The modelviews subscribe to this event in order to reload itself with offline data, inform user etc.
However, I have a problem. When I have the folowing handler:
private void HandleNoInternetMessage(NoInternetAccessMessage obj)
{
Task.Run(async () => await InitializeForOfflineInternalAsync());
}
public async Task InitializeForOfflineInternalAsync()
{
try
{
WaitingLayerViewModel.ShouldBeVisible = true;
WaitingLayerViewModel.IsBusy = true; //<--exception HRESULT: 0x8001010E (RPC_E_WRONG_THREAD)
bool switchToOffline = await CommonViewModelProvider.InformUserOfNoInternetAccessAndChangeAppState(); //<!- CoreWindow.GetForCurrentThread().Dispatcher is null
await FilterTestItemViewModel.InitializeForOfflineAsync();
await FilterTestItemViewModel.InitializeForOfflineAsync();
WaitingLayerViewModel.ShouldBeVisible = false;
WaitingLayerViewModel.IsBusy = false;
...
}
}
I got exception HRESULT: 0x8001010E (RPC_E_WRONG_THREAD), because in InitializeForOfflineInternalAsync I am changing some properties of the viewmodel wchich are bound in XAML (or at least I think it is because of that). However, it is weird, because I am changing in other code bound properties regularly and have no problems with it (and the thread is a working thread).
Now, how can i solve that?
The messanger let me provide only delegate which is not async (which make kind of sense), so I can not have the HandleNoInternetMessage method async
I am using async await ... no explicit spawning of threads
I dont have access in VM to Dispatcher, because I am in VM which should not know about platform dependent stuff. And when I tried to use it to show a message, NullPointer excpetion was thrown when calling CoreWindow.GetForCurrentThread().Dispatcher; And again when calling from other places, no such exception was thrown
I guess the question is How I can safely run async code, which changes boudn properties, when handling messages from Messenger?
You're responding to messages that are logically events, so this is an acceptable use case for async void.
private async void HandleNoInternetMessage(NoInternetAccessMessage obj)
{
await InitializeForOfflineInternalAsync();
}
public async Task InitializeForOfflineInternalAsync()
{
try
{
WaitingLayerViewModel.ShouldBeVisible = true;
WaitingLayerViewModel.IsBusy = true;
bool switchToOffline = await CommonViewModelProvider.InformUserOfNoInternetAccessAndChangeAppState();
await FilterTestItemViewModel.InitializeForOfflineAsync();
await FilterTestItemViewModel.InitializeForOfflineAsync();
WaitingLayerViewModel.ShouldBeVisible = false;
WaitingLayerViewModel.IsBusy = false;
...
}
}
Remember that Task.Run is for CPU-bound code (as I describe on my blog).
I've been looking for any simple example building async interfaces using ASP.NET WebForms. That is when an async method is done the await shall render.
This is one of the examples I've been looking at, How and When to use `async` and `await`. The implementation I've been looking for would look something like this
protected async void button1_Click(object sender, EventArgs e)
{
// Render when done
textBox1.Text += await WaitAsynchronouslyAsync(RandomNumber(2000, 4000));
// Render when done
textBox1.Text += await WaitAsynchronouslyAsync(RandomNumber(100, 1000));
}
public async Task<string> WaitAsynchronouslyAsync(int delay)
{
await Task.Delay(delay);
return string.Concat(delay, "; ");
}
private int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
This will however always render when everything is done, but at the same time. In the example above the desired result would be the second call to WaitAsynchronouslyAsync to render before the first call since it always will be less delay.
Or is it even possible using webforms? I do know how to do this in JavaScript using webapi's, websockets and whatnot and that's not the solution I desire at the moment.
As I describe on my blog, async does not change the HTTP protocol.
HTTP provides you with one response for each request. So, when an HTTP request arrives, it must execute your page to completion before sending the response.
In the ASP.NET world, await does not yield to the client/browser. Instead, it yields to the ASP.NET runtime. ASP.NET will not send the response until it sees that your processing is all done.
If you want to dynamically update a page (or partially render one), then you'll need to do it yourself using an appropriate technology (SignalR, UpdatePanel, etc).
When you use await in the manner that you did, execution flow is sequential. The first await, and only after it finishes will the second await execute.
If you want them executed concurrently, you can initiate both operations and use Task.WhenAny and assign the value of whichever task finishes first:
Task<string> slowerTask = WaitAsynchronouslyAsync(RandomNumber(2000, 4000));
Task<string> fasterTask = WaitAsynchronouslyAsync(RandomNumber(100, 1000));
List<Task<string>> tasks = new List<Task<string>> { slowerTask, fasterTask };
while (tasks.Count > 0)
{
Task<string> finishedTask = await Task.WhenAny(tasks);
tasks.Remove(finishedTask);
textBox1.Text = await finishedTask;
}
somehow my exceptions seem to being caught by method they are executing in. Here is the code to call the method. As you can see I create a cancellation token with a time out. I register a method to call when the cancellation token fires and then I start a new task. The cancellation token appears to be working OK. As does the registered method.
var cancellationToken = new CancellationTokenSource(subscriber.TimeToExpire).Token;
cancellationToken.Register(() =>
{
subscriber.Abort();
});
var task = Task<bool>.Factory.StartNew(() =>
{
subscriber.RunAsync((T)messagePacket.Body, cancellationToken);
return true;
})
.ContinueWith(anticedant =>
{
if (anticedant.IsCanceled)
{
Counter.Increment(12);
Trace.WriteLine("Request was canceled");
}
if (anticedant.IsFaulted)
{
Counter.Increment(13);
Trace.WriteLine("Request was canceled");
}
if (anticedant.IsCompleted)
{
Counter.Increment(14);
}
The next piece of code is the method that seems to be not only throwing the excetion (expected behavior. but also catching the exception.
public async override Task<bool> ProcessAsync(Message input, CancellationToken cancellationToken)
{
Random r = new Random();
Thread.Sleep(r.Next(90, 110));
cancellationToken.ThrowIfCancellationRequested();
return await DoSomethingAsync(input);
}
The exception is being thrown by the cancellation token but according to intellitrace it is being caught at the end of the method. I have tried a number of different options including throwing my own exception, but no matter what the continuewith function always executes the IsComleted or ran to completion code.
Any ideas on what I am doing wrong?
Thanks
I assume that RunAsync is the same as ProcessAsync.
The exception is being thrown by the cancellation token but according to intellitrace it is being caught at the end of the method.
Yup. Any async method will catch its own exceptions and place them on its returned Task. This is by design.
no matter what the continuewith function always executes the IsComleted or ran to completion code.
Well, let's take another look at the code:
var task = Task<bool>.Factory.StartNew(() =>
{
subscriber.RunAsync((T)messagePacket.Body, cancellationToken);
return true;
})
.ContinueWith(
Consider the lambda passed to StartNew: it calls RunAsync, it ignores the Task that it returns, and then it returns true (successfully). So the Task returned by StartNew will always return successfully. This is why the ContinueWith always executes for a successfully-completed task.
What you really want is to await the Task returned by RunAsync. So, something like this:
var task = Task.Run(async () =>
{
await subscriber.RunAsync((T)messagePacket.Body, cancellationToken);
return true;
})
.ContinueWith(
You're still ignoring the return value of RunAsync (the bool it returns is ignored), but you're not ignoring the Task itself (including cancellation/exception information).
P.S. I'm assuming there's a lot of code you're not showing us; using StartNew/Run to just kick off some async work and return a value is very expensive.
P.P.S. Use await Task.Delay instead of Thread.Sleep.