如何将依赖SqlFileStream的代码迁移至.NET6+ Linux环境?
迁移.NET FILESTREAM代码到.NET 6+ Linux环境的最佳方案
问题背景
你之前的代码是这么用SqlFileStream访问SQL Server FILESTREAM的:
var result = CreateSQLQuery($@"select [{ColumnName}].PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() as context from [{TableName}] where Id = :id") .SetParameter("id", entity.Id) .UniqueResult<object[]>(); return new SqlFileStream((string) result[0], (byte[]) result[1], fileAccess);
但到了Linux环境就失效了——因为SqlFileStream是Windows专属实现,底层依赖SMB协议,完全不支持跨平台。针对.NET 6+的跨平台场景,最靠谱的替代方案是用SQL Server 2019+官方推出的FILESTREAM REST API,下面给你一步步说怎么实现。
具体实现步骤
1. 先配置SQL Server支持REST访问
首先得确保你的SQL Server是2019或更高版本,然后开启FILESTREAM的HTTP访问:
- 打开SQL Server配置管理器,找到目标实例,启用「针对文件流的HTTP访问」
- 设置共享名称和端口(默认8080),同时在SQL Server所在机器的防火墙里开放这个端口,让Linux服务器能访问到
2. 替换原有SqlFileStream代码逻辑
核心就是把原来的SMB文件流操作,改成HTTP请求读写,下面是具体的代码示例:
读取FILESTREAM数据
using System.Net.Http; using System.Data.SqlClient; public async Task<byte[]> ReadFilestreamDataAsync(Guid entityId, string connectionString) { using var conn = new SqlConnection(connectionString); await conn.OpenAsync(); // 必须在SQL事务内操作,保证数据一致性 using var tx = await conn.BeginTransactionAsync(); // 查询获取REST访问地址和事务上下文 var cmd = new SqlCommand(@" SELECT CONCAT('http://你的SQL服务器IP或域名:端口/', REPLACE([ColumnName].PathName(), '\', '/')) AS RestUrl, GET_FILESTREAM_TRANSACTION_CONTEXT() AS TransactionContext FROM [TableName] WHERE Id = @id", conn, tx); cmd.Parameters.AddWithValue("@id", entityId); using var reader = await cmd.ExecuteReaderAsync(); await reader.ReadAsync(); var restUrl = reader.GetString(0); var transactionContext = (byte[])reader.GetValue(1); // 用HttpClient发送GET请求读取数据,带上事务上下文头 using var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("TransactionContext", Convert.ToBase64String(transactionContext)); return await httpClient.GetByteArrayAsync(restUrl); }
写入FILESTREAM数据
public async Task WriteFilestreamDataAsync(Guid entityId, byte[] data, string connectionString) { using var conn = new SqlConnection(connectionString); await conn.OpenAsync(); using var tx = await conn.BeginTransactionAsync(); // 同样先获取REST地址和事务上下文 var cmd = new SqlCommand(@" SELECT CONCAT('http://你的SQL服务器IP或域名:端口/', REPLACE([ColumnName].PathName(), '\', '/')) AS RestUrl, GET_FILESTREAM_TRANSACTION_CONTEXT() AS TransactionContext FROM [TableName] WHERE Id = @id", conn, tx); cmd.Parameters.AddWithValue("@id", entityId); using var reader = await cmd.ExecuteReaderAsync(); await reader.ReadAsync(); var restUrl = reader.GetString(0); var transactionContext = (byte[])reader.GetValue(1); // 发送PUT请求写入数据 using var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Add("TransactionContext", Convert.ToBase64String(transactionContext)); var content = new ByteArrayContent(data); var response = await httpClient.PutAsync(restUrl, content); // 确保请求成功,失败直接抛出异常 response.EnsureSuccessStatusCode(); await tx.CommitAsync(); }
3. 几个关键注意点
- 版本硬性要求:SQL Server必须是2019及以上,这是FILESTREAM REST API的最低支持版本
- 事务必须存在:所有读写操作都要在SQL事务中执行,并且必须携带
TransactionContext请求头,否则SQL Server会拒绝访问 - HttpClient优化:如果频繁操作FILESTREAM,建议复用
HttpClient实例(比如通过依赖注入注册为单例),避免频繁创建销毁带来的性能开销 - 网络连通性:Linux服务器要能正常访问SQL Server的HTTP端口,提前检查防火墙、网络路由是否正常
内容的提问来源于stack exchange,提问作者Sahin
相关产品推荐
相关产品推荐

