进行异步调用时出现 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 应用程序中遇到死锁。你现在没有得到它的唯一原因是你在控制台应用程序中。
我正在尝试使用 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 应用程序中遇到死锁。你现在没有得到它的唯一原因是你在控制台应用程序中。