C#& Asp.Net:将文件从SQL Server传输到浏览器客户端,无需保存在应用程序服务器上

时间:2015-09-10 04:05:03

标签: asp.net sql-server-2008-r2

我有一个应用程序,可以持续存储更多2,5 Gb的大文件。当客户端请求下载此文件时,我希望文件进入客户端浏览器而不像我今天那样保存在应用程序服务器上。

我使用的是SQL Server 2008 R2,Asp.Net 3.5,存储该文件的列的数据类型为Varbinary

1 个答案:

答案 0 :(得分:0)

我经历了同样的情况,并在这篇文章中得到了解决方案。您将使用VarbinaryStream类,如下所示:

Original Post here.

VarbinaryStream filestream = new VarbinaryStream(
                                DbContext.Database.Connection.ConnectionString, 
                                "FileContents", 
                                "Content", 
                                "ID", 
                                (int)filepost.ID, 
                                true);

代码:

public class VarbinaryStream : Stream
{
    private SqlConnection _Connection;

    private string  _TableName;
    private string  _BinaryColumn;
    private string  _KeyColumn;
    private int     _KeyValue;

    private long    _Offset;

    private SqlDataReader _SQLReader;
    private long _SQLReadPosition;

    private bool _AllowedToRead = false;

    public VarbinaryStream(
        string ConnectionString,
        string TableName,
        string BinaryColumn,
        string KeyColumn,
        int KeyValue,
        bool AllowRead = false)
    {
        // create own connection with the connection string.
        _Connection = new SqlConnection(ConnectionString);

        _TableName = TableName;
        _BinaryColumn = BinaryColumn;
        _KeyColumn = KeyColumn;
        _KeyValue = KeyValue;


        // only query the database for a result if we are going to be reading, otherwise skip.
        _AllowedToRead = AllowRead;
        if (_AllowedToRead == true)
        {
            try
            {
                if (_Connection.State != ConnectionState.Open)
                    _Connection.Open();

                SqlCommand cmd = new SqlCommand(
                                @"SELECT TOP 1 [" + _BinaryColumn + @"]
                                FROM [dbo].[" + _TableName + @"]
                                WHERE [" + _KeyColumn + "] = @id",
                            _Connection);

                cmd.Parameters.Add(new SqlParameter("@id", _KeyValue));

                _SQLReader = cmd.ExecuteReader(
                    CommandBehavior.SequentialAccess |
                    CommandBehavior.SingleResult |
                    CommandBehavior.SingleRow |
                    CommandBehavior.CloseConnection);

                _SQLReader.Read();
            }
            catch (Exception e)
            {
                // log errors here
            }
        }
    }

    // this method will be called as part of the Stream ímplementation when we try to write to our VarbinaryStream class.
    public override void Write(byte[] buffer, int index, int count)
    {
        try
        {
            if (_Connection.State != ConnectionState.Open)
                _Connection.Open();

            if (_Offset == 0)
            {
                // for the first write we just send the bytes to the Column
                SqlCommand cmd = new SqlCommand(
                                            @"UPDATE [dbo].[" + _TableName + @"]
                                                SET [" + _BinaryColumn + @"] = @firstchunk 
                                            WHERE [" + _KeyColumn + "] = @id",
                                        _Connection);

                cmd.Parameters.Add(new SqlParameter("@firstchunk", buffer));
                cmd.Parameters.Add(new SqlParameter("@id", _KeyValue));

                cmd.ExecuteNonQuery();

                _Offset = count;
            }
            else
            {
                // for all updates after the first one we use the TSQL command .WRITE() to append the data in the database
                SqlCommand cmd = new SqlCommand(
                                        @"UPDATE [dbo].[" + _TableName + @"]
                                            SET [" + _BinaryColumn + @"].WRITE(@chunk, NULL, @length)
                                        WHERE [" + _KeyColumn + "] = @id",
                                     _Connection);

                cmd.Parameters.Add(new SqlParameter("@chunk", buffer));
                cmd.Parameters.Add(new SqlParameter("@length", count));
                cmd.Parameters.Add(new SqlParameter("@id", _KeyValue));

                cmd.ExecuteNonQuery();

                _Offset += count;
            }
        }
        catch (Exception e)
        {
            // log errors here
        }
    }

    // this method will be called as part of the Stream ímplementation when we try to read from our VarbinaryStream class.
    public override int Read(byte[] buffer, int offset, int count)
    {
        try
        {
            long bytesRead = _SQLReader.GetBytes(0, _SQLReadPosition, buffer, offset, count);
            _SQLReadPosition += bytesRead;
            return (int)bytesRead;
        }
        catch (Exception e)
        {
            // log errors here
        }
        return -1;
    }
    public override bool CanRead
    {
        get { return _AllowedToRead; }
    }

    #region unimplemented methods
    public override bool CanSeek
    {
        get { return false; }
    }

    public override bool CanWrite
    {
        get { return true; }
    }

    public override void Flush()
    {
        throw new NotImplementedException();
    }

    public override long Length
    {
        get { throw new NotImplementedException(); }
    }

    public override long Position
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }
    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new NotImplementedException();
    }

    public override void SetLength(long value)
    {
        throw new NotImplementedException();
    }
    #endregion unimplemented methods
}