nozzlegear / ShopifySharp

ShopifySharp is a .NET library that helps developers easily authenticate with and manage Shopify stores.
https://nozzlegear.com/shopify-development-handbook
MIT License
747 stars 309 forks source link

Internal application stopped working #1047

Open wockaili opened 6 months ago

wockaili commented 6 months ago

I have a web application (4.8 framework) using ShopifySharp that's been running since 2022 with no issues. I modified something last week and it was still running. I tried to update something this week but the app keeps on hanging on every call to any service. Here's a basic code I've been testing with and when I call the service.async, the application hangs:

using ShopifySharp; using ShopifySharp.Lists; using System; using System.Net; using System.Threading.Tasks;

namespace WebApp_C { public partial class _Default : System.Web.UI.Page { private string shpfyAPIAccessToken = <>; private string shpfyURLMain = <>;

    protected void Page_Load(object sender, EventArgs e)
    {
        ShopifyLocationPopulate();
    }

    protected void ShopifyLocationPopulate()
    {
        // Load Locations
        ListResult<ShopifySharp.Location> spfLocationList = ShopifyLocationListGet().Result;
    }
    public async Task<ListResult<ShopifySharp.Location>> ShopifyLocationListGet()
    {
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
        LocationService spfService = new LocationService(shpfyURLMain, shpfyAPIAccessToken);
        ListResult<ShopifySharp.Location> spfLocationList;
        try
        {
            spfLocationList = await spfService.ListAsync();
            return spfLocationList;
        }
        catch (Exception ex)
        {
            return null;
        }
    }
}

}

nozzlegear commented 6 months ago

Hey @wockaili! I think the problem you have here is due to the way async/await works in dotnet. Specifically, whenever you have an async method that's being called but not awaited, such as in your two void methods, there's usually something fishy going on that might end up causing problems. It's double fishy when the method has to use .Result to get the task result from an async method, instead of just awaiting it. This in particular is the cause of many deadlocks.

If it's possible, see if you can change those void methods to be async as well. I'm not sure which UI framework you're using there, but if your Page_Load method can be async then I bet this problem would be fixed right away:

protected async Task Page_LoadAsync(object sender, EventArgs e)
    {
        await ShopifyLocationPopulate();
    }

    protected void ShopifyLocationPopulate()
    {
        // Load Locations
        ListResult<ShopifySharp.Location> spfLocationList = await ShopifyLocationListGet();
    }
    public async Task<ListResult<ShopifySharp.Location>> ShopifyLocationListGet()
    {
      // ...
     }

If that's not possible, you might be able to make a small modification and use .GetAwaiter().GetResult() to keep your method synchronous. I think, though I can't remember off the top of my head, that .GetAwaiter().GetResult() is the pattern that you want to use for doing this sort of thing when you have no other choice.

protected void ShopifyLocationPopulate()
    {
        // Load Locations
        ListResult<ShopifySharp.Location> spfLocationList = ShopifyLocationListGet().GetAwaiter().GetResult();
    }

Let me know if either of those suggestions help!

djc-wissam commented 6 months ago

I used async on the page_load and that resolved the issue. One more thing, I'm using the 6.13.0 which is supposed to use 2024-01 API version. When I check the API version when running my app, I get 2023-01.