1

Is it possible to use async/await based methods inside an Acumatica(6.00.1263) PXLongOperation block?

When I try this, I get this System.InvalidOperationException:

An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.

My code looks like this:

PXLongOperation.StartOperation(this, async delegate ()
{
    FooProcess graph = PXGraph.CreateInstance<FooProcess>();
    await graph.ImportDocumentsAsync();
});

I've also tried:

PXLongOperation.StartOperation(this, delegate ()
{
    FooProcess graph = PXGraph.CreateInstance<FooProcess>();
    graph.ImportDocumentsAsync().GetAwaiter().GetResult();
});

I have added an answer that works, but I hope there is(or will be) a better way to do this, perhaps a different API or overload for long operations that handles async/await natively.

Tobarja
  • 63
  • 6

1 Answers1

1

Reading through Synchronously waiting for an async operation, and why does Wait() freeze the program here, I was able to find a variant that seems to work:

PXLongOperation.StartOperation(this, delegate ()
{
    FooProcess graph = PXGraph.CreateInstance<FooProcess>();
    var task = Task.Run(async () =>
        await graph.ImportDocumentsAsync().ConfigureAwait(false));
    task.Wait();
});

I am hesitant to mark this as resolved, as I read many scary warnings about forcing asynchronous methods to run synchronously.

Note: It also worked without the .ConfigureAwait(false), but again, scary warnings.

Tobarja
  • 63
  • 6
  • PXLongOperation is already running in it's own thread. There's no advantage whatsoever to run an asynchronous method inside that long operation thread. Running the asynchronous method in a synchronous task is the proper solution. The counter-indication don't apply because you are already executing the async method in an asynchronous thread (long operation). – Hugues Beauséjour Feb 13 '20 at 15:13
  • ConfigureAwait isn't necessary indeed. – Hugues Beauséjour Apr 15 '21 at 23:41
  • @HuguesBeauséjour One advantage of using async here is if you need to use async libraries with the long-running process, for example, HttpClient, Azure Blob Storage. – pettys Dec 14 '21 at 23:42
  • @pettys It will allow you to use async libraries in a non async way. Ideally you would use a non async method because there's no advantage to run asynchronous code synchronously. Given that there's no synchronous option for a library this becomes an acceptable solution indeed. – Hugues Beauséjour Dec 15 '21 at 18:07
  • @HuguesBeauséjour Thanks for that. The original poster's question remains: if you need to use a library with only async methods in a PXLongOperation, do you know what is the safest approach to do that without risking reentrant deadlocks or thread exhaustion? The answer's approach is what I'm going with for now, but it would be nice to see some acumatica guidance since creating an async scope in sync space... I've been bitten by strange & unpredictable bugs in this space in the past. – pettys Dec 19 '21 at 00:04