Skip to content

[API Proposal]: CancellationToken parameters on async XmlReader methods #116587

Open
@lilinus

Description

@lilinus

Background and motivation

The abstract XmlReader class has been around since the beginning of .NET, and it is foundational to System.Xml.Linq among others.

One problem is that all async methods on XmlReader is missing CancellationToken parameters. For example, this causes the cancellation token used in XDocument.LoadAsync to not be respected (#114555).

The new methods could also have ValueTask return types, but I opted for regular Tasks in this proposal for simplicity.

The System.Xml namespace has many synchronous methods that are missing asynchronous counterparts, but they are not considered in this proposal.

API Proposal

namespace System.Xml
public class XmlReader
{
    public virtual System.Threading.Tasks.Task<string> GetValueAsync();
+   public virtual System.Threading.Tasks.Task<string> GetValueAsync(CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<bool> ReadAsync();
+   public virtual System.Threading.Tasks.Task<bool> ReadAsync(CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<object> ReadContentAsAsync(Type returnType, System.Xml.IXmlNamespaceResolver? namespaceResolver);
+   public virtual System.Threading.Tasks.Task<object> ReadContentAsAsync(Type returnType, System.Xml.IXmlNamespaceResolver? namespaceResolver, CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<int> ReadContentAsBase64Async(byte[] buffer, int index, int count);
+   public virtual System.Threading.Tasks.Task<int> ReadContentAsBase64Async(byte[] buffer, int index, int count, CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<int> ReadContentAsBinHexAsync(byte[] buffer, int index, int count);
+   public virtual System.Threading.Tasks.Task<int> ReadContentAsBinHexAsync(byte[] buffer, int index, int count, CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<object> ReadContentAsObjectAsync();
+   public virtual System.Threading.Tasks.Task<object> ReadContentAsObjectAsync(CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<string> ReadContentAsStringAsync();
+   public virtual System.Threading.Tasks.Task<string> ReadContentAsStringAsync(CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<object> ReadElementContentAsAsync(Type returnType, System.Xml.IXmlNamespaceResolver namespaceResolver);
+   public virtual System.Threading.Tasks.Task<object> ReadElementContentAsAsync(Type returnType, System.Xml.IXmlNamespaceResolver namespaceResolver, CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<int> ReadElementContentAsBase64Async(byte[] buffer, int index, int count);
+   public virtual System.Threading.Tasks.Task<int> ReadElementContentAsBase64Async(byte[] buffer, int index, int count, CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<int> ReadElementContentAsBinHexAsync(byte[] buffer, int index, int count);
+   public virtual System.Threading.Tasks.Task<int> ReadElementContentAsBinHexAsync(byte[] buffer, int index, int count, CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<object> ReadElementContentAsObjectAsync();
+   public virtual System.Threading.Tasks.Task<object> ReadElementContentAsObjectAsync(CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<string> ReadElementContentAsStringAsync();
+   public virtual System.Threading.Tasks.Task<string> ReadElementContentAsStringAsync(CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<string> ReadInnerXmlAsync();
+   public virtual System.Threading.Tasks.Task<string> ReadInnerXmlAsync(CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<string> ReadOuterXmlAsync();
+   public virtual System.Threading.Tasks.Task<string> ReadOuterXmlAsync(CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task<int> ReadValueChunkAsync(char[] buffer, int index, int count);
+   public virtual System.Threading.Tasks.Task<int> ReadValueChunkAsync(char[] buffer, int index, int count, CancellationToken cancellationToken);
    public virtual System.Threading.Tasks.Task SkipAsync();
+   public virtual System.Threading.Tasks.Task SkipAsync(CancellationToken cancellationToken);
}

API Usage

// Fancy the value
var c = new MyFancyCollection<int>();
c.Fancy(42);

// Getting the values out
foreach (var v in c)
    Console.WriteLine(v);

Alternative Designs

No response

Risks

Default implementation of virtual methpos ReadAsync and GetValueAsync simply throws NotImplementedException, kind of like "optional" abstract methods I intepret it like.

All async-supporting, built-in classes deriving from XmlReader (i.e. XmlTextReader etc.) should have the overrides for these new methods added as part of this change.

But it might be unclear how this change would affect custom subclasses for XmlReader that for example would override ReadAsync() but not ReadAsync(CancellationToken).

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-System.Threading.TasksuntriagedNew issue has not been triaged by the area owner

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions