简体   繁体   中英

Why is the using variable disposing itself before leaving the method?

using PuppeteerSharp;
using System;
using System.Threading.Tasks;

namespace Video_Handler
{
    public class VideoHost
    {
        private static bool Is_HTTPS_URL(string url)
        {
            Uri uriResult;

            bool result = Uri.TryCreate(url, UriKind.Absolute, out uriResult) && (uriResult.Scheme == Uri.UriSchemeHttps);
            return result;
        }

        #region BrowserCreationCode
        private static async Task FectchBrowserIfItIsNotThere()
        {
            var browserFetcher = new BrowserFetcher();
            await browserFetcher.DownloadAsync();
        }
        internal static async Task<Page> GetPageAsync(string url, bool isPageInvisible = true, Action<Page> action)
        {
            if(!Is_HTTPS_URL(url))
            {
                throw new ArgumentException($"The url | {url} | is not an https url.");
            }
            await FectchBrowserIfItIsNotThere();
            await using var browser = await Puppeteer.LaunchAsync(
                new LaunchOptions { Headless = isPageInvisible });
            await using var page = await browser.NewPageAsync();
            await page.GoToAsync(url);
            action(page);
            return page;
        }
    }
}
//Boiler Plate code
async static void Main()
{
  Action<Page> action = (page) => Foo(page);
  await GetPageAsync("https://google.com", false , action);
}
public static async Task Foo(Page p){ 
   await p.EvaluateExpression("//fill google search bar"); //first line
   await p.EvaluateExpression("//click search button");  //second line
   await p.WaitForNavigationAsync(); //third line
   await p.EvaluateExpression("alert("hi")"); //fourth line
}

I am having an issue where when I send the page variable to the action which takes in a page variable it causes the page or browser variable to be disposed. From what I understand about using, this should only happen if I leave the function's parenthesis. I have read Microsoft's documentation on using and I can't find anything that tells me that the page variable disposes itself upon going to another function within the function the using variable is in.

Also, occasionally the code will be able to evaluate some of the function's expressions but it usually fails by the third. However, if I debug and run step by step, it always fails on the first line. This is what led me to believe it is a disposal issue.

To anyone wondering why I have not just removed the using from browser and page variables and dispose of them myself, I have two reasons. One, I don't have experience with disposing unmanaged code and when I tried to add the dispose to the finalizer/destructor it doesn't work and Secondly, I don't want to write code to do what the language already does for me.

The issue was using Action instead of Func<Page, Task>.

Action always returns a void. Since the function Action was calling was a async method but was not sending the method's output it causes the function that called Action to exit which released the unmanged resources. The Func<Page, Task> retains the output so it can be awaited so the main thread is blocked till completion preventing the unmanaged resources from being release early.

async static void Main()
{
   Func<FileStream,Task> func = (FileStream fs) => Foo(fs); //Input to function is FileStream and Output of Function is Task
   Action<FileStream> action = (FileStream fs) => Foo(fs); //Equivalent to Func<FileStream , void>
   using var fs = new FileStream();
   //action(fs); //This can fail if the main thread is finished before it
   await func(fs); //This will succeed since the main thread is blocked till completion

}
async static Task Foo(FileStream fs) => await fs.SomeLongAsyncMethod();


The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM