C#中如何将PDF二进制字符串转为MS SQL varBinary(max)并调用存储过程
问题描述
在MS SQL查询中,我可以将PDF二进制字符串转换为varBinary(max)并插入,PDF能正常打开。但用C#调用MS SQL存储过程执行相同转换时,插入后的PDF无法打开,提示格式错误。以下是可正常运行的SQL代码及存在问题的C#代码,求解决建议。
可正常运行的SQL代码
Declare @ContentTest varbinary(max) Declare @Doc varchar(max) -- PDF Binary字符串 Set @Doc = '0x255044462d312e340a25e2e3cfd30a332030206f626a0a3c3c2f54797065202f506167650a2.......'; SET @ContentTest = CONVERT(VARBINARY(max), @Doc, 1); EXEC dbo.SP_AddDocument @UserID = 2, @Subject = "User Details Report", @Details = "Report", @DocType = "PDF", @Compression = 0, @Content = @ContentTest, @CorroDate = "2022-11-25 10:05:47", @RequiresCheck = 0;
存在问题的C#代码
public static async Task<string> syncDocumentToBPServer(JObject data) { dbConnect(); _sqlCon.Open(); int lastInsertID = 0; int k = 0; if (_sqlCon.State == System.Data.ConnectionState.Open) { int bpPatientId = (int)data["bpPatientId"]; String content = data["content_binary"].ToString(); byte[] theBytes = Encoding.UTF8.GetBytes(content); string sql = @"DATABASE.dbo.[SP_AddDocument]"; SqlCommand cmd = new SqlCommand(sql, _sqlCon); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new SqlParameter("@PatientID", bpPatientId)); cmd.Parameters.Add(new SqlParameter("@Subject", "User Details Report")); cmd.Parameters.Add(new SqlParameter("@Details", "Report")); cmd.Parameters.Add(new SqlParameter("@DocType", "PDF")); cmd.Parameters.Add(new SqlParameter("@Compression", 0)); cmd.Parameters.Add("@Content", SqlDbType.VarBinary, 1).Value = theBytes; cmd.Parameters.Add(new SqlParameter("@CorroDate", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); cmd.Parameters.Add(new SqlParameter("@RequiresCheck", false)); SqlParameter returnParameter = cmd.Parameters.Add("RecordID", SqlDbType.Int); returnParameter.Direction = ParameterDirection.ReturnValue; k = cmd.ExecuteNonQuery(); if (k != 0) { lastInsertID = (int)returnParameter.Value; } } var result = new { success = k, recordId = lastInsertID, }; _sqlCon.Close(); return JsonConvert.SerializeObject(result); }
解决建议
你的C#代码存在三个关键错误,直接导致PDF格式损坏:
二进制字符串转字节数组的逻辑错误
SQL中CONVERT(VARBINARY(max), @Doc, 1)是把以0x开头的十六进制字符串直接解析为二进制数据,但你用Encoding.UTF8.GetBytes(content)是把整个十六进制字符串当作普通文本转字节,完全破坏了原始二进制结构。比如字符串里的0x25,SQL会转成单个字节0x25,而UTF8会转成0x30、0x78、0x32、0x35四个字节。正确转换方式:先去掉字符串开头的
0x,再将十六进制字符串转为字节数组:String content = data["content_binary"].ToString(); // 移除开头的0x标识 if (content.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { content = content.Substring(2); } // 十六进制字符串转字节数组 byte[] theBytes = Enumerable.Range(0, content.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(content.Substring(x, 2), 16)) .ToArray();VarBinary参数长度设置错误
你设置SqlDbType.VarBinary, 1意味着参数仅保留1字节,会截断大部分PDF数据。应去掉长度参数,或设置为-1表示varbinary(max):cmd.Parameters.Add("@Content", SqlDbType.VarBinary).Value = theBytes; // 或者明确指定max长度 cmd.Parameters.Add("@Content", SqlDbType.VarBinary, -1).Value = theBytes;日期参数传递方式优化
将DateTime.Now转为字符串再传递可能引发格式解析问题,直接传入DateTime类型即可:cmd.Parameters.Add(new SqlParameter("@CorroDate", DateTime.Now));
内容的提问来源于stack exchange,提问作者Prashant Rajput
相关产品推荐
相关产品推荐

