dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.89k stars 4.63k forks source link

[API Proposal]: Add Async Methods to IDataReader #81876

Open RAAvenger opened 1 year ago

RAAvenger commented 1 year ago

Background and motivation

I'm writing a code that exposes an NpgsqlDataReader. I would like to use async methods of DataReader and also be able to test my code by mocking DataReader, so i prefer to expose an IDataReader that can be mocked but if i do this i can't use async methods. Of course there is workaround like writing wrapper and ... but it would be great if the interface contains async methods.

API Proposal

namespace System.Data
{
    public interface IDataReader : IDisposable, IDataRecord
    {
        int Depth { get; }
        bool IsClosed { get; }
        int RecordsAffected { get; }
        void Close();
        Task CloseAsync();
        DataTable? GetSchemaTable();
        Task<DataTable?> GetSchemaTableAsync(CancellationToken cancellationToken);
        bool NextResult();
        Task<bool> NextResultAsync(CancellationToken cancellationToken);
        bool Read();
        Task<bool> ReadAsync(CancellationToken cancellationToken);
    }
}

API Usage


var connection = new NpgsqlConnection(connectionString);
await connection.OpenAsync(cancellationToken).ConfigureAwait(false);
var command = connection.CreateCommand();
command.CommandText = query;
IDataReader reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
while(await reader.ReadAsync(connectionString).ConfigureAwait(false))
{
// get data
}

Alternative Designs

No response

Risks

No response

ghost commented 1 year ago

Tagging subscribers to this area: @dotnet/area-system-threading-tasks See info in area-owners.md if you want to be subscribed.

Issue Details
### Background and motivation I'm writing a code that exposes an NpgsqlDataReader. I would like to use async methods of DataReader and also be able to test my code by mocking DataReader, so i prefer to expose an IDataReader that can be mocked but if i do this i can't use async methods. Of course there is workaround like writing wrapper and ... but it would be great if the interface contains async methods. ### API Proposal ```csharp namespace System.Data { public interface IDataReader : IDisposable, IDataRecord { int Depth { get; } bool IsClosed { get; } int RecordsAffected { get; } void Close(); Task CloseAsync(); DataTable? GetSchemaTable(); Task GetSchemaTableAsync(CancellationToken cancellationToken); bool NextResult(); Task NextResultAsync(CancellationToken cancellationToken); bool Read(); Task ReadAsync(CancellationToken cancellationToken); } } ``` ### API Usage ```csharp var connection = new NpgsqlConnection(connectionString); await connection.OpenAsync(cancellationToken).ConfigureAwait(false); var command = connection.CreateCommand(); command.CommandText = query; IDataReader reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false); while(await reader.ReadAsync(connectionString).ConfigureAwait(false)) { // get data } ``` ### Alternative Designs _No response_ ### Risks _No response_
Author: RAAvenger
Assignees: -
Labels: `api-suggestion`, `area-System.Threading.Tasks`
Milestone: -
svick commented 1 year ago

Just adding methods to an interface is a massive breaking change, so it's not going to happen.

Adding them as default interface methods is much less of a breaking change, but then the question becomes what the default implementation should be and I'm not sure there is a good answer to that.

Can't you mock DbDataReader for your tests instead?

RAAvenger commented 1 year ago

thanks for your suggestion. using DbDataReader will resolve my issue. A non-breaking option that comes to mind is to define a new Interface (e.g. IAsyncDataReader) for all those async method overloads of DbDataReader class and let DbDataReader implement the aforementioned interface alongside the existing IDataReader