AngleSharp by Florian Rappl

<PackageReference Include="AngleSharp" Version="0.8.5" />

 BrowsingContextExtensions

public static class BrowsingContextExtensions
A set of extensions for the browsing context.
using AngleSharp.Dom; using AngleSharp.Dom.Html; using AngleSharp.Dom.Svg; using AngleSharp.Dom.Xml; using AngleSharp.Extensions; using AngleSharp.Network; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; namespace AngleSharp { [DebuggerStepThrough] public static class BrowsingContextExtensions { public class VirtualResponse : IResponse, IDisposable { private Url address; private HttpStatusCode status; private Dictionary<string, string> headers; private TextSource source; private Stream content; private bool dispose; Url IResponse.Address { get { return address; } } Stream IResponse.Content { get { return content; } } Dictionary<string, string> IResponse.Headers { get { return headers; } } HttpStatusCode IResponse.StatusCode { get { return status; } } public VirtualResponse() { address = Url.Create("http://localhost/"); status = HttpStatusCode.OK; headers = new Dictionary<string, string>(); content = Stream.Null; source = null; dispose = false; } public VirtualResponse Address(Url url) { address = url; return this; } public VirtualResponse Address(string address) { return Address(Url.Create(address ?? string.Empty)); } public VirtualResponse Address(Uri url) { return Address(Url.Convert(url)); } public VirtualResponse Status(HttpStatusCode code) { status = code; return this; } public VirtualResponse Status(int code) { return Status((HttpStatusCode)code); } public VirtualResponse Header(string name, string value) { headers[name] = value; return this; } public VirtualResponse Headers(object obj) { Dictionary<string, string> dictionary = obj.ToDictionary((object m) => m.ToString()); foreach (KeyValuePair<string, string> item in dictionary) { Header(item.Key, item.Value); } return this; } public VirtualResponse Content(string text) { Release(); source = new TextSource(text); return this; } public VirtualResponse Content(Stream stream, bool shouldDispose = false) { Release(); content = stream; dispose = shouldDispose; return this; } private void Release() { if (content != null && dispose) content.Dispose(); else if (source != null) { source.Dispose(); } dispose = false; source = null; content = null; } void IDisposable.Dispose() { Release(); } internal TextSource CreateSourceFor(IConfiguration configuration) { if (source != null) return source; if (content != null) return new TextSource(content, configuration.DefaultEncoding()); return new TextSource(string.Empty); } } public static Task<IDocument> OpenNewAsync(this IBrowsingContext context, string url = null) { return context.OpenAsync(delegate(VirtualResponse m) { m.Address(url); }); } public static async Task<IDocument> OpenAsync(this IBrowsingContext context, IResponse response, CancellationToken cancel) { if (response == null) throw new ArgumentNullException("response"); if (context == null) context = BrowsingContext.New(null); TextSource source = new TextSource(response.Content, context.Configuration.DefaultEncoding()); IDocument document = await context.LoadDocumentAsync(response, source, cancel).ConfigureAwait(false); context.NavigateTo(document); return document; } public static async Task<IDocument> OpenAsync(this IBrowsingContext context, DocumentRequest request, CancellationToken cancel) { if (request == null) throw new ArgumentNullException("request"); IResponse response = await context.Loader.SendAsync(request, cancel).ConfigureAwait(false); if (response != null) { IDocument document = await context.OpenAsync(response, cancel).ConfigureAwait(false); response.Dispose(); return document; } return await context.OpenNewAsync(request.Target.Href).ConfigureAwait(false); } public static Task<IDocument> OpenAsync(this IBrowsingContext context, Url url, CancellationToken cancel) { if (url == null) throw new ArgumentNullException("url"); DocumentRequest documentRequest = new DocumentRequest(url); if (context != null && context.Active != null) documentRequest.Referer = context.Active.DocumentUri; return context.OpenAsync(documentRequest, cancel); } public static async Task<IDocument> OpenAsync(this IBrowsingContext context, Action<VirtualResponse> request, CancellationToken cancel) { if (request == null) throw new ArgumentNullException("request"); if (context == null) context = BrowsingContext.New(null); using (VirtualResponse response = new VirtualResponse()) { request(response); TextSource source = response.CreateSourceFor(context.Configuration); IDocument document = await context.LoadDocumentAsync(response, source, cancel).ConfigureAwait(false); context.NavigateTo(document); return document; } } public static Task<IDocument> OpenAsync(this IBrowsingContext context, Action<VirtualResponse> request) { return context.OpenAsync(request, CancellationToken.None); } public static Task<IDocument> OpenAsync(this IBrowsingContext context, Url url) { return context.OpenAsync(url, CancellationToken.None); } public static Task<IDocument> OpenAsync(this IBrowsingContext context, string address) { if (address == null) throw new ArgumentNullException("address"); return context.OpenAsync(Url.Create(address), CancellationToken.None); } private static async Task<IDocument> LoadDocumentAsync(this IBrowsingContext context, IResponse response, TextSource source, CancellationToken cancel) { string contentType = response.Headers.GetOrDefault(HeaderNames.ContentType, MimeTypes.Html); if (contentType.IndexOf(';') > 0) contentType = contentType.Substring(0, contentType.IndexOf(';')).Trim(); if (contentType.Equals(MimeTypes.Xml, StringComparison.OrdinalIgnoreCase) || contentType.Equals(MimeTypes.ApplicationXml, StringComparison.OrdinalIgnoreCase)) return await XmlDocument.LoadAsync(context, response, source, cancel).ConfigureAwait(false); if (contentType.Equals(MimeTypes.Svg, StringComparison.OrdinalIgnoreCase)) return await SvgDocument.LoadAsync(context, response, source, cancel); return await HtmlDocument.LoadAsync(context, response, source, cancel).ConfigureAwait(false); } } }