关于C#和SQL Server不一致关于字符串是否有效Base64:C#和SQL Server不同意字符串是否有效Base64 – 哪个是正确的?

C# and SQL Server disagree about whether a string is valid Base64 - which is correct?

在SQL Server 2008 R2(SP1)数据库上有下表:

1
2
3
4
-- irrelevant columns omitted
create table Person
           ( PersonID int,
             Portrait varchar(max) )

Person.Portrait列包含从JPG图像编码的base64字符串-这是由我们无法控制的第三方系统填充的。我需要将此数据转换回原始字节,以便在报告中显示:

1
2
3
select isnull(cast(N'' as xml).value('xs:base64Binary(sql:column("psn.Portrait"))', 'varbinary(max)'), 0xdeadbeef) as [Portrait]
  from Person psn with (nolock)
 where psn.PersonID = <n>

对于某些行,这将返回有效的varbinary数据,而对于其他行,它将返回OxDEADBEEF(换句话说,XML表达式的结果是返回null)。

但是,如果我对在SQL Server中返回nullPerson表中的行运行以下c代码,则会得到有效的JPG图像输出:

1
2
3
4
5
6
7
8
9
var portraitBytes = Convert.FromBase64String(Sql.SelectSingleString(
@"select psn.Portrait
    from Person psn with (nolock)
   where psn.PersonID = <n>"));

using (var writer = new FileStream(@"C:\portrait.jpg", FileMode.CreateNew))
{
  writer.Write(portraitBytes, 0, portraitBytes.Length);
}

我能看到的SQL Server视为"有效"的值与那些"无效"的值之间的唯一区别是"无效"的值以字符Z结尾。如果我用=替换这个字符,那么SQL Server会很高兴。

如果我在以Z结尾的base64字符串上运行上述c代码,但用=替换该字符,代码运行良好,输出的图像小1字节,但(显然)呈现相同。

所以我的问题是:

  • Z结束base64字符串有效吗?
  • 哪一个行为不当:C接受无效的base64字符串,还是SQL Server拒绝有效的字符串?
  • =替换Z是否安全,以允许SQL Server不吐?换句话说,结果字节是否可能不是有效的JPG数据?

  • 对。
  • 两者都没有,见下文。
  • 不再相关,见下文。
  • 经过大量的思考,我发现psn.Portrait中的数据包含一个尾随的NUL(\0字符,在SQL Server Management Studio中运行select时不显示该字符。所以每次我从SSMS复制数据以作为文本进行测试时,它都不会有一个尾随的NUL,因此会正确解码。当然,当引用列中的实际值时,NUL会出现在乘坐过程中,并导致mssql正确拒绝字符串。

    在C端,结果发现Sql.SelectSingleStringhelper方法中有一行表示result.Trim('\0')。我不明白为什么会这样,但这也解释了为什么C没有被NUL卡住……它不在那里窒息。