Home > Back-end >  Cannot implicitly convert type 'Task<System.Collections.Generic.IEnumerable<T>>
Cannot implicitly convert type 'Task<System.Collections.Generic.IEnumerable<T>>

Time:10-15

I have an ASP.NET Core 3.1 Web API project which is leveraging Dapper for database operations.

I have following method in the ISqlDapperClient.cs

ISqlDapperClient.cs

public interface ISqlDapperClient
{
    Task<IReadOnlyList<T>> QueryReadOnlyListAsync<T>(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
}

SqlDapperClient.cs

public class SqlDapperClient : ISqlDapperClient
{
    private readonly ILogger<SqlDapperClient> _logger;
    private readonly IAsyncPolicy _resiliencyPolicy;
    private readonly IConfiguration _configuration;
    private readonly string _dbConnection;
    private readonly IDBAuthTokenService _dbTokenService;
    private readonly IDbConnection _connection;
    public SqlDapperClient(ILogger<SqlDapperClient> logger, IConfiguration configuration, IDBAuthTokenService dbTokenService)
    {
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _resiliencyPolicy = SqlResiliencyPolicy.GetSqlResiliencyPolicy(); //resiliencyPolicy ?? throw new ArgumentNullException(nameof(resiliencyPolicy));
        _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
        // Read the connectionstring
        _dbConnection = _configuration[C.VaultKeys.DataDBConnString] ?? _configuration[C.AppKeys.LocalDataDBConn];
        _dbTokenService = dbTokenService ?? throw new ArgumentNullException(nameof(dbTokenService));
        _connection = OpenConnectionWithRetryAsync().Result;
    }

    /// <summary>
    /// Method that returns IDbConnection to connect with database
    /// </summary>
    /// <returns>IDbConnection</returns>
    private async Task<IDbConnection> OpenConnectionWithRetryAsync()
    {
        var conn = new SqlConnection(_dbConnection)
        {AccessToken = await _dbTokenService.GetTokenAsync()};
        await conn.OpenAsync();
        return conn;
    }

    public Task<IReadOnlyList<T>> QueryReadOnlyListAsync<T>(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) => ExecuteWithResiliency((s, p, c) => c.QueryAsync<T>(s, p, transaction, commandTimeout, commandType), sql, param);
    private async Task<T> ExecuteWithResiliency<T>(Func<string, object, SqlConnection, Task<T>> connectionFunc, string sql, object param = null, [CallerMemberName] string operation = "")
    {
        return await _resiliencyPolicy.ExecuteAsync(ctx => connectionFunc(sql, param, (SqlConnection)_connection), ContextHelper.NewContext((SqlConnection)_connection, _logger, sql, param, operation));
    }
}

I am getting compile time error in the method : QueryReadOnlyListAsync

Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<T>>' to 'System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<T>>'

Can anyone help me here by providing their guidance?

CodePudding user response:

QueryReadOnlyListAsync calls the Dapper extension method QueryAsync, which returns a Task<IEnumerable<T>>. IEnumerable doesn't implement IReadOnlyList. You can't return Task<IEnumerable> if the method's return type is Task<IReadOnlyList>. You need to convert the IEnumerable into a collection that implements IReadOnlyList, such as a regular List:

//Make method async so you can await the Task returned by ExecuteWithResiliency
public async Task<IReadOnlyList<T>> QueryReadOnlyListAsync<T>(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
    //Converting using .ToList() for simplicity. Use whatever type suits your use-case best.
    return (await ExecuteWithResiliency((s, p, c) => c.QueryAsync<T>(s, p, transaction, commandTimeout, commandType), sql, param)).ToList();
}

private async Task<T> ExecuteWithResiliency<T>(Func<string, object, SqlConnection, Task<T>> connectionFunc, string sql, object param = null, [CallerMemberName] string operation = "")
{
    return await _resiliencyPolicy.ExecuteAsync(ctx => connectionFunc(sql, param, (SqlConnection)_connection), ContextHelper.NewContext((SqlConnection)_connection, _logger, sql, param, operation));
}
  • Related