SQL Server UDF SQLCLR调用将字符转换为问号

时间:2016-08-24 17:26:12

标签: c# asp.net sql-server encoding sqlclr

我在Google或SO上找不到任何与我的问题相符的内容。

在SQL Server中,我有一个标量函数(我们称之为dbo.MySqlStringFunction)。 这个函数的作用是调用用C#编写的实用程序,该实用程序调用ASP.Net视图并将HTML作为SqlString返回。

SQL Server中的函数定义是:

RETURNS [nvarchar](max) WITH EXECUTE AS CALLER
AS EXTERNAL NAME [Utils.UserDefinedFunctions].[MySqlStringFunction]

简化的C#代码是:

var request = (HttpWebRequest)WebRequest.Create("www.mydomain.com");

using (var response = (HttpWebResponse)request.GetResponse())
using (var stream = response.GetResponseStream())
{
   using (var streamReader = new StreamReader(stream, Encoding.UTF8)
   {
      return new SqlString(streamReader.ReadToEnd());
   }
}

当我将C#代码放入控制台应用程序并运行它时,我会完全按照应有的方式获取所有内容。

当我直接在浏览器中访问网址时,它会完全按照原样显示。

当我SELECT MySqlStringFunction()时,诸如™,§,¤等字符分别显示为2或3个问号。

它似乎介于return new SqlString(..)和sql函数之间,返回值,表明某些事情变得很糟糕。但是我不知道它会是什么。

1 个答案:

答案 0 :(得分:2)

问题似乎是return的位置。当前代码(在问题中显示)返回3个using块的中间,其中一个是正在读取的UTF-8流。这可能会使事情变得混乱,因为SQLCLR是来自主SQL Server内存的隔离内存,通常您无法通过流返回。最好先关闭开放流,然后让using块调用Dispose()。因此:

  1. 在第一个using(即string _TempReturn = String.Empty;
  2. 上方创建一个字符串
  3. 在最内层using内,将return替换为:_TempReturn = streamReader.ReadToEnd();
  4. 在最后一个using结束括号下方,添加:return new SqlString(_TempReturn);
  5. 旧答案,将在不久的将来删除

    问题在于网页和SQL Server之间的编码差异。您正在使用Encoding.UTF8作为网页(鉴于UTF-8是最常用的互联网编码,这很可能是正确的),但SQL Server(以及一般的.NET和Windows)是UTF-16小恩迪安。这就是为什么你为Code Point 127上面的每个字符获得2或3 ?的原因:UTF-8是一个多字节编码,每个字符使用1,2或3个字节,而UTF-16总是2字节(好的,补充字符是4字节,但这是由于是一对双字节值)。

    您需要先将编码转换为UTF-16 Little Endian,或者将其传回流。并且,UTF-16 Little Endian是.NET中的Unicode编码,而Big Endian Unicode是指“UTF-16 Big Endian”。因此,您希望转换为Unicode编码。

    或者,它可能是相反的:网页不是UTF-8,在这种情况下你在StreamReader中错误地声明了它。如果是这样,那么您需要在StreamReader构造函数中指定正确的编码。