进行异步调用时出现 AngleSharp 错误

AngleSharp error while making the async calls

我正在尝试使用 AngleSharp 加载许多页面。这个想法是它加载一个页面,如果这个页面有一个 link 到下一个,加载下一个页面等等,方法如下所述。但我得到了内部异常:

Specified argument was out of the range of valid values.
Parameter name: index"

我认为这与 Thread 和同步有关。

    public static bool ContainsNextPage(IDocument document)
    {
        String href = document.QuerySelectorAll(".prevnext a")[0].GetAttribute("href");
        if (href == String.Empty)
            return false;
        else
            return true;
    }

    public static string GetNextPageUrl(IDocument document)
    {
        return document.QuerySelectorAll(".prevnext a")[0].GetAttribute("href");

    }

    public static async Task<IDocument> ParseUrlSynch(string Url)
    {
            var config = new Configuration().WithDefaultLoader();
            IDocument document = await BrowsingContext.New(config).OpenAsync(Url);

            return document;
    }

    public static async Task<ConcurrentBag<IDocument>> GetAllPagesDOMs(IDocument initialDocument)
    {

        ConcurrentBag< IDocument> AllPagesDOM = new ConcurrentBag< IDocument>();
        IDocument nextPageDOM;
        IDocument currentDocument = initialDocument;

        if (initialDocument != null)
        {
            AllPagesDOM.Add(initialDocument);
        }

        while (ContainsNextPage(currentDocument))
        {
            String nextPageUrl = GetNextPageUrl(currentDocument);

            nextPageDOM = ParseUrlSynch(nextPageUrl).Result;
            if (nextPageDOM != null)
                AllPagesDOM.Add(nextPageDOM);

            currentDocument = nextPageDOM;
        }

        return AllPagesDOM;
    }

      static void Main(string[] args)
    {



        List<IDocument> allPageDOMs = new List<IDocument>();
        IDocument initialDocument = ParseUrlSynch(InitialUrl).Result;
        List<String> urls = new List<string>();
        List<Subject> subjects = new List<Subject>();
        IHtmlCollection<IElement> subjectAnchors = initialDocument.QuerySelectorAll(".course_title a");

        String[] TitleAndCode;
        String Title;
        String Code;
        String Description;
        IDocument currentDocument = initialDocument;


        ConcurrentBag<IDocument> documents =          

        GetAllPagesDOMs(initialDocument).Result; //Exception in here
        ...
}

您的直觉是正确的,如果您从具有非默认 SynchronizationContext 的应用程序(例如 WPF、Win Forms 或 ASP.NET 中使用它,那么您将遇到死锁,因为您同步阻塞 async Task 返回函数(这是不好的,应该避免)。当第一个 await 到达阻塞调用内部时,它将尝试 post 到当前 SyncronizationContext 的延续,它已经被阻塞调用锁定(如果您使用 .ConfigureAwait(false) 你避免了这个,但在这种情况下这是一个 hack)。

一个快速的解决方法是通过改变以下方式一直使用异步:

nextPageDOM = ParseUrlSynch(nextPageUrl).Result;

与:

nextPageDOM = await ParseUrlSynch(nextPageUrl);

在你被这个问题刺痛了几次之后,你就会学会在每次阻塞异步方法时在你的脑海中敲响警钟。

错误信息是由这段代码引起的:

document.QuerySelectorAll(".prevnext a")[0]

您的一个文档 prevnext 中没有任何锚点。可能是第一页,也可能是最后一页,无论哪种方式,您都需要检查数组的长度。

另外,阻塞调用异步方法也是一种不好的做法,应该避免。您将在任何 UI 应用程序中遇到死锁。你现在没有得到它的唯一原因是你在控制台应用程序中。