Skip to content

Can't use multiple YoutubeClient instances concurrently because of static HtmlParser #955

Description

@rho-cassiopeiae

Version

v6.6.0

Environment

.NET 10

Steps to reproduce

var tasks = new List<Task<Video>>();
for (int i = 0; i < 5; ++i)
{
    var yt = new YoutubeClient();
    tasks.Add(yt.Videos.GetAsync("YLpVDA3j6e8").AsTask());
}

var results = await Task.WhenAll(tasks);

Results in:

Unhandled exception. System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at System.Collections.Generic.Dictionary`2.set_Item(TKey key, TValue value)
   at AngleSharp.BrowsingContext.CreateChild(String name, Sandboxes security, Boolean isFrameContext)
   at AngleSharp.Html.Dom.HtmlFrameElementBase.NewChildContext()
   at AngleSharp.Html.Dom.HtmlFrameElementBase.SetupElement()
   at AngleSharp.Html.Dom.HtmlIFrameElement.SetupElement()
   at AngleSharp.Dom.Element.AngleSharp.Html.Construction.IConstructableElement.SetupElement()
   at AngleSharp.Html.Parser.HtmlDomBuilder`2.CloseNodeAt(Int32 index)
   at AngleSharp.Html.Parser.HtmlDomBuilder`2.CloseCurrentNode()
   at AngleSharp.Html.Parser.HtmlDomBuilder`2.Text(StructHtmlToken& token)
   at AngleSharp.Html.Parser.HtmlDomBuilder`2.Home(StructHtmlToken& token)
   at AngleSharp.Html.Parser.HtmlDomBuilder`2.Consume(StructHtmlToken& token)
   at AngleSharp.Html.Parser.HtmlDomBuilder`2.Parse(HtmlParserOptions options, TokenizerMiddleware middleware)
   at AngleSharp.Html.Parser.HtmlParser.Parse(HtmlDocument document, String stopAt)
   at AngleSharp.Html.Parser.HtmlParser.ParseDocument(String source)
   at YoutubeExplode.Utils.Html.Parse(String source) in /_/YoutubeExplode/Utils/Html.cs:line 10
   at YoutubeExplode.Bridge.VideoWatchPage.TryParse(String raw) in /_/YoutubeExplode/Bridge/VideoWatchPage.cs:line 125
   at YoutubeExplode.Videos.VideoController.GetVideoWatchPageAsync(VideoId videoId, CancellationToken cancellationToken) in /_/YoutubeExplode/Videos/VideoController.cs:line 64
   at YoutubeExplode.Videos.VideoClient.GetAsync(VideoId videoId, CancellationToken cancellationToken) in /_/YoutubeExplode/Videos/VideoClient.cs:line 37

Details

The problem seems to be this:

internal static class Html
{
    private static readonly HtmlParser HtmlParser = new();

    public static IHtmlDocument Parse(string source) => HtmlParser.ParseDocument(source);
}

Expected behavior:
I understand that the lib is not supposed to be used as a singleton, but, as you can see, even when creating a new client instance for every request it still fails, which I'm not sure it's supposed to. Can we have an option to have a dedicated HtmlParser for every client instance?

Checklist

  • I have looked through existing issues to make sure that this bug has not been reported before
  • I have provided a descriptive title for this issue
  • I have made sure that this bug is reproducible on the latest version of the package
  • I have provided all the information needed to reproduce this bug as efficiently as possible
  • I have sponsored this project
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions