在自定义流类中调用其他* Async方法

时间:2016-08-29 13:05:52

标签: c# asynchronous stream async-await

我有一个派生自Stream的类,在其读/写中,我需要访问一个数据库。我想使用SqlData对象的* Async方法但当然它希望我将Read的签名更改为具有这样的东西(我认为):

public async override Task <int> Read( byte[] buffer, int offset, int count )

这与实际签名不符,因此我收到一条编译错误消息,说明这一点。知道如何在这个流中使用* Async,或者我应该让它同步吗?

我还使用了来自https://blogs.msdn.microsoft.com/pfxteam/2011/01/15/asynclazyt/

的Stephen Toub的AsyncLazy

我的课程正在启用SQL Server中VarBinary(max)字段的数据流,其中包含来自http://www.syntaxwarriors.com/2013/stream-varbinary-data-to-and-from-mssql-using-csharp/的大多数想法。

以下是代码中的有趣位(异步位被注释掉):

public class BinaryDataStream<T> : Stream
{
    /* Async */Lazy<SqlDataReader> lazyReader;
    SqlConnection connection;
    SqlCommand firstUpdate;
    SqlCommand otherUpdates;
    long position;

    public BinaryDataStream( DbContext context, string tableName, string keyName, string columnName, T keyValue )
    {
        connection = new SqlConnection( context.Database.GetDbConnection().ConnectionString );

        lazyReader = new /* Async */Lazy<SqlDataReader>( /* async */ () =>
        {
            using ( var cmd = new SqlCommand( $"SELECT TOP 1 [{columnName}] FROM [dbo].[{tableName}] WHERE [{keyName}] = @id", connection ) )
            {
                cmd.Parameters.AddWithValue( "@id", keyValue );
                /* await */ connection.Open/* Async */();

                var r = /* await */ cmd.ExecuteReader/* Async */( System.Data.CommandBehavior.SequentialAccess | System.Data.CommandBehavior.SingleResult | System.Data.CommandBehavior.SingleRow | System.Data.CommandBehavior.CloseConnection );
                r.Read();

                return r;
            }
        } );

        firstUpdate = new SqlCommand( $"UPDATE [dbo].[{tableName}] SET [{columnName}] = @firstchunk WHERE [{keyName}] = @id", connection );
        firstUpdate.Parameters.AddWithValue( "@id", keyValue );
        firstUpdate.Parameters.AddWithValue( "@firstchunk", new byte[] { } );

        otherUpdates = new SqlCommand( $"UPDATE [dbo].[{tableName}] SET [{columnName}].WRITE( @chunk, NULL, @length ) WHERE [{keyName}] = @id", connection );
        otherUpdates.Parameters.AddWithValue( "@id", keyValue );
        otherUpdates.Parameters.AddWithValue( "@length", 0 );
        otherUpdates.Parameters.AddWithValue( "@chunk", new byte[] { } );
    }

    public /* async */ override /* Task< */int/* > */ Read( byte[] buffer, int offset, int count )
    {
        var reader = /* await */ lazyReader.Value;
        var bytesRead = reader.GetBytes( 0, position, buffer, offset, count );
        position += bytesRead;
        return (int)bytesRead;
    }

    public /* async */ override void Write( byte[] buffer, int offset, int count )
    {
        if ( count == 0 ) return;

        /* await */ connection.Open/* Async */();

        try
        {
            if ( firstUpdate != null )
            {
                firstUpdate.Parameters[ "@firstchunk" ].Value = buffer;
                /* await */ firstUpdate.ExecuteNonQuery/* Async */();
                firstUpdate = null;
            }
            else
            {

                var chunk = buffer;
                if ( count < buffer.Length )
                {
                    chunk = new byte[ count ];
                    Array.Copy( buffer, 0, chunk, 0, count );
                }

                otherUpdates.Parameters[ "@chunk" ].Value = chunk;
                otherUpdates.Parameters[ "@length" ].Value = count;
                /* await */ otherUpdates.ExecuteNonQuery/* Async */();
            }
        }
        finally
        {
            connection.Close();
        }
    }
}

1 个答案:

答案 0 :(得分:2)

Stream类具有其方法的同步和异步版本。同样,您执行的数据库操作也会暴露其方法的同步和异步版本。使用同步实现覆盖同步方法,并使用异步实现覆盖异步方法。