Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Use Microsoft.Data.SqlClient streaming methods to process large values without first loading the complete value into application memory. Streaming is useful for binary files, large text, XML, JSON, and server-to-server transfer.
Streaming doesn't make the value seekable or make concurrent operations on a reader safe. The connection, command, reader, source stream, and destination object must remain alive until the transfer finishes.
The examples in this article assume that an open SqlConnection named connection targets the AdventureWorks sample database.
The C# examples require using Microsoft.Data.SqlClient;. Examples that use SqlDbType or CommandBehavior also require using System.Data;.
Stream data from a SQL database
Execute the command with CommandBehavior.SequentialAccess and read columns in ordinal order. With sequential access, after you advance past a column, don't read an earlier column in the same row.
Use these SqlDataReader methods:
| Method | Result | Typical SQL data |
|---|---|---|
| GetStream | Stream | binary, varbinary, image, and user-defined type (UDT) data |
| GetTextReader | TextReader | Character and JSON data |
| GetXmlReader | XmlReader | xml |
Call IsDBNull before requesting a stream for a nullable column. A streaming getter used with an incompatible SQL type throws. Consume or dispose the current stream before reading another column, advancing the row, or moving to the next result.
GetStream isn't supported for encrypted columns. GetTextReader doesn't support sequential access to an encrypted column.
CommandTimeout applies while Microsoft.Data.SqlClient waits for network packets during execution and reading. Time that your application spends processing already received data isn't counted. For cancellation and timeouts, see Asynchronous programming.
Stream binary data
AdventureWorks stores file content in the nullable varbinary(max) Production.Document.Document column. This example copies one value to a file with a bounded buffer:
using var command = new SqlCommand("""
SELECT TOP (1) Document
FROM Production.Document
WHERE Document IS NOT NULL
ORDER BY ModifiedDate DESC;
""", connection);
using SqlDataReader reader = command.ExecuteReader(
CommandBehavior.SequentialAccess);
if (reader.Read())
{
using Stream source = reader.GetStream(0);
using FileStream destination = File.Create("document.bin");
source.CopyTo(destination);
}
For text, use GetTextReader and copy to a TextWriter. For XML, use GetXmlReader and process XML nodes without converting the complete value to string.
Stream data to a SQL database
Set Value to a streaming object and choose a compatible SQL type:
| Value type | Compatible parameter types |
|---|---|
| Stream | Binary, VarBinary, and the legacy Image type |
| TextReader | Char, NChar, VarChar, NVarChar, the legacy Text and NText types, Xml, and Json |
| XmlReader | Char, NChar, VarChar, NVarChar, the legacy Text and NText types, Xml, and Json |
Set Size explicitly. Size limits the amount transferred. Use -1 for a (max) parameter when you want to send the complete source.
For bounded-memory transfer, use VarBinary, VarChar, or NVarChar with Size = -1, or use Xml or Json. Microsoft.Data.SqlClient buffers the source into a byte array or string before execution for non-(max) character and binary types and the legacy Image, Text, and NText types.
Stream a parameter value
This example sends a file through a varbinary(max) parameter and returns the number of bytes received. It doesn't store the value:
using FileStream input = File.OpenRead("document.bin");
using var command = new SqlCommand(
"SELECT DATALENGTH(@content);",
connection);
command.Parameters.Add(
new SqlParameter("@content", SqlDbType.VarBinary, -1)
{
Value = input
});
long length = (long)command.ExecuteScalar()!;
Console.WriteLine($"{length} bytes");
Keep the input object open until command execution completes. Pass a cancellation token to an asynchronous execution method or call Cancel to request cancellation of the streaming operation. Cancellation is best effort. The operation might finish before cancellation takes effect.
An exception from the source stream or reader faults command execution. Don't retry from the same object unless you can establish its position and the database operation is safe to repeat.
Stream data from one SQL database to another
This example passes an AdventureWorks document stream directly to a parameter on another open SqlConnection named destinationConnection. The sample command reports the received length. Replace it with the destination database's parameterized insert or update command:
using var readSource = new SqlCommand("""
SELECT TOP (1) Document
FROM Production.Document
WHERE Document IS NOT NULL
ORDER BY ModifiedDate DESC;
""", connection);
using SqlDataReader sourceReader = readSource.ExecuteReader(
CommandBehavior.SequentialAccess);
if (sourceReader.Read())
{
using Stream content = sourceReader.GetStream(0);
using var write = new SqlCommand(
"SELECT DATALENGTH(@content);",
destinationConnection);
write.Parameters.Add(
new SqlParameter("@content", SqlDbType.VarBinary, -1)
{
Value = content
});
Console.WriteLine(write.ExecuteScalar());
}
The source and destination commands don't share a transaction. If your application requires coordinated atomic work across servers, design and test that transaction boundary separately.