BUG in Cells .NET SDK - Aysnc/Await deadlock issue

Hello,

The .NET SDK for Aspose.Cells-Cloud (v 24.9.0) has deadlock issues caused by the current aysnc/await implementation.

The issue is easily reproduced with a Windows Forms or ASP.NET project, I tested on .NETFramework 4.5.2, .net standard 2.0 and net6.0. The good news is it’s easily fixed (example below).

This affects Windows Forms and ASP.NET projects, it does not effect .NET console applications because there is no UI or Request context (which causes the deadlock)

Read here for a good explanation, a blog post written by Microsoft MVP who literally wrote the book on concurrency in C#.

In brief, if your helper methods are async, then your requesting thread must also await or else you’ll have a deadlock situation with the UI or Request context.

Take for example Aspose.Cells.Cloud.SDK.Api.CellsApi.DeleteFolder()

The DeleteFolder() has helper functions that use async/await several levels deep (for example ApiInvoker.cs → GetResponseAsync()), yet DeleteFolder() itself is not async, so you have the classic deadlock case the linked article above refers to.

With minor modifications to CellsApi.cs this can be resolved by making the public methods awaitable. For example DeleteFolder() becomes

public  async Task<string> DeleteFolder(DeleteFolderRequest request)
{
    requestHandlers.ForEach(p => p.ProcessUrl(""));
    var result = await invoker.InvokeApiAsync<  string  >(request.CreateHttpRequest(BaseUri +"/" +Version, this.invoker.DefaultHeaderMap, this.requestHandlers));
    return result;
}

Then you can await DeleteFolder() in your UI or Request context and it works as expected.

Let me know if you’d like more information, examples, but this is easily reproduced and fixed. I use your other .NET SDKs, including Words Cloud, PDF Cloud and the async/await is implemented differently / correctly, thus no issues with deadlock.

Another example in CellsApi.cs

  'turning this:
  public SaveResponse  PostWorkbookSaveAs(PostWorkbookSaveAsRequest request)
  {
      RequestHandlers.ForEach(p >= p.ProcessUrl(""));
      var result = Invoker.InvokeApiAsync < SaveResponse > (Request.CreateHttpRequest(BaseUri + "/" + Version, this.invoker.DefaultHeaderMap, this.requestHandlers)).Result;
      return result;
  }

  'into this:
  public async Task<SaveResponse> PostWorkbookSaveAs(PostWorkbookSaveAsRequest request)
  {
      RequestHandlers.ForEach(p >= p.ProcessUrl(""));
      var result = await Invoker.InvokeApiAsync<    SaveResponse  >(request.CreateHttpRequest(BaseUri +"/" +Version, this.invoker.DefaultHeaderMap, this.requestHandlers));
      return result;
  }

So now, PostWorkbookSaveAs() is awaitable in context. Vital for Win Forms and ASP.NET projects.

Also note that you can’t simply call .Result() on the returned Task, this also results in deadlock. So .Result() needs to be removed.

The entire call stack must be async/await.

@thomp361 We will check this issue as soon as possible

Thanks for looking into this.

For those looking for a workaround in their ASP.NET or Windows Forms projects, you can spawn child threads, I currently prefer Task.Run(), then the aspose.cells - cloud SDK methods will run in their own context, and thus no deadlock with the Request or UI context.

Task.WhenAll().GetAwaiter.GetResult() makes it easy to join those child threads back with your Request or UI context.

@thomp361 Thanks for your help. In subsequent versions, we will consider adding a set of syntax using async await to solve this problem.

Thanks @xuejianzhang , I forked the SDK, it’s more work than I thought to change and test all of those methods.

One question I’ve had on the Cells SDK is PutConvertWorkbook() and PostWorkbookSaveAs() seems to ignore the scaling parameters (isAutoFitColumns, isAutoFitRows, etc). GetWorkbook() scaling parameters(isAutoFit, etc) seem to work.

The API endpoints seem to ignore them as well. The resulting pdf documents are the same no matter what parameters it receives. Might be something to look into, though I’d imagine you’re very busy.

Thanks for all you do!

@thomp361,

We will check your questions as soon as possible.