SQL Server中Uri.EscapeDataString函数表现不符合预期
问题描述
我用.NET Framework 4.8控制台程序测试字符串转义,执行Console.WriteLine(Uri.EscapeDataString("*")),输出符合预期的%2A。
随后在另一个.NET Framework 4.8类库中编写了如下CLR函数:
[SqlFunction(DataAccess = DataAccessKind.None)] [return: SqlFacet(MaxSize = -1)] public static SqlString UrlEncode([SqlFacet(MaxSize = -1)] string url) { return new SqlString(Uri.EscapeDataString(url)); }
将该类库作为CLR程序集添加到SQL Server 2022中,并创建对应的SQL函数:
CREATE FUNCTION [dbo].[UrlEncode](@url [nvarchar](max)) RETURNS nvarchar(max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SqlClrFunctions].[Utils].UrlEncode GO
执行查询select dbo.UrlEncode('*'),结果为*,显然不符合预期。同一函数为何表现不同?
问题分析与解决
这个差异的核心原因是SQL Server的CLR宿主环境对.NET框架的API行为做了调整:
- 独立控制台程序中,
Uri.EscapeDataString严格遵循RFC 3986标准,会将*这类保留字符转义为%2A。 - 但在SQL Server CLR宿主里,默认启用兼容旧版编码规则的模式,
*被视为无需转义的字符,因此直接输出原字符。
解决方式有两种:
改用
HttpUtility.UrlEncode方法
该方法的编码行为在CLR宿主环境中更稳定,会正确转义*。需要在类库中引用System.Web程序集,修改后的代码如下:using System.Web; using Microsoft.SqlServer.Server; using System.Data.SqlTypes; public class Utils { [SqlFunction(DataAccess = DataAccessKind.None)] [return: SqlFacet(MaxSize = -1)] public static SqlString UrlEncode([SqlFacet(MaxSize = -1)] string url) { return new SqlString(HttpUtility.UrlEncode(url)); } }部署时需确保CLR程序集的权限设置允许访问
System.Web。手动实现严格的RFC 3986编码逻辑
如果不想依赖System.Web,可以自己编写编码逻辑,遍历字符串并对包括*在内的保留字符进行转义。
另外,调整SQL Server CLR的PERMISSION_SET为UNSAFE并不能解决这个问题,因为该行为差异是宿主环境对API的适配导致的,和权限无关。
内容的提问来源于stack exchange,提问作者Ivan Debono
相关产品推荐
相关产品推荐

