18

在开发机器上安装 VS2012 Premium 后,单元测试失败,因此开发人员修复了该问题。当更改被推送到 TeamCity 时,单元测试失败了。除了解决方案文件正在升级以兼容VS2012之外,该项目没有变化。它仍然针对 .net 框架 4.0

我已将问题隔离为调用Uri.ToString. 以下代码复制了该行为。

Imports NUnit.Framework

<TestFixture()>
Public Class UriTest

   <Test()>
    Public Sub UriToStringUrlDecodes()
       Dim uri = New Uri("http://www.example.org/test?helloworld=foo%B6bar")

       Assert.AreEqual("http://www.example.org/test?helloworld=foo¶bar", uri.ToString())
    End Sub

End Class

在没有安装 VS2012 的机器上在 VS2010 中运行它成功,在安装了 VS2012 的机器上在 VS2010 中运行它失败。两者都使用来自 NuGet 的最新版本的 NCrunch 和 NUnit。

没有安装VS2012的机器

安装VS2012的机器

来自失败断言的消息是

  Expected string length 46 but was 48. Strings differ at index 42.
  Expected: "http://www.example.org/test?helloworld=foo¶bar"
  But was:  "http://www.example.org/test?helloworld=foo%B6bar"
  -----------------------------------------------------^

.NET 4 和 .NET 4.5 的MSDN文档显示ToString不应编码此字符,这意味着旧的行为应该是正确的。

A String instance that contains the unescaped canonical representation of the Uri instance. All characters are unescaped except #, ?, and %.

安装 VS2012 后,该 unicode 字符被转义。

VS2012机器上System.dll文件版本为4.0.30319.17929

构建服务器上 System.dll 的文件版本为 4.0.30319.236

uri.ToString()忽略我们为什么使用,我们正在测试什么以及任何潜在的解决方法的优点。谁能解释为什么这种行为似乎已经改变,或者这是一个错误?

编辑,这里是 C# 版本

using System;
using NUnit.Framework;

namespace SystemUriCSharp 
{
    [TestFixture]
    public class UriTest
    {

        [Test]
        public void UriToStringDoesNotEscapeUnicodeCharacters()
        {
            var uri = new Uri(@"http://www.example.org/test?helloworld=foo%B6bar");

            Assert.AreEqual(@"http://www.example.org/test?helloworld=foo¶bar", uri.ToString());
        }

    }
}

进一步调查,如果我以 .NET 4.0 或 .NET 4.5 为目标,则测试失败,如果我将其切换到 .NET 3.5,则测试成功。

4

3 回答 3

8

.NET Framework 4.5 中引入了一些更改,它与 VS2012 一起安装,并且(据我所知)也是所谓的“就地升级”。这意味着它实际上升级了 .NET Framework 4。

此外,在 System.Uri 中记录了重大更改。其中一位说Unicode 规范化形式 C (NFC) 将不再在 URI 的非主机部分上执行。我不确定这是否适用于您的案例,但它可以作为您调查错误的良好起点。

于 2012-08-22T06:16:50.937 回答
6

此更改与早期 .NET 版本的问题有关,现在已更改为更符合标准。%B6是 UTF-16,但根据标准 UTF-8 应该在 Uri 中使用,这意味着它应该是%C2%B6. 所以%B6不是 UTF-8,它现在被正确地忽略而不被解码。

下面逐字引用的连接报告中的更多详细信息。

.NET 4.5 具有增强且更兼容的 RFC 3987 应用程序,它支持 URI 的 IRI 解析规则。IRI 是国际资源标识符。这允许在要解析的 URI/IRI 字符串中包含非 ASCII 字符。

在 .NET 4.5 之前,我们对 IRI 有一些不一致的处理。我们有一个默认值为 false 的 app.config 条目,您可以打开它:

它做了一些 IRI 处理/解析。但是,它有一些问题。特别是它允许不正确的百分比编码处理。根据 RFC 3987,URI/IRI 字符串中的百分比编码项应该是百分比编码的 UTF-8 八位字节。它们不会被解释为百分比编码的 UTF-16。因此,根据 UTF-8 处理“%B6”是不正确的,不会发生解码。¶ 的正确 UTF-8 编码实际上是“%C2%B6”。

如果你的字符串是这样的:

        string strUri = @"http://www.example.com/test?helloworld=foo%C2%B6bar";

然后它将在 ToString() 方法中标准化,并解码和删除百分比编码。

您能否提供有关您的应用程序需求和 ToString() 方法使用的更多信息?通常,我们推荐 Uri 对象的 AbsoluteUri 属性来满足大多数规范化需求。

如果此问题阻碍了您的应用程序开发和业务需求,请通过“netfx45compat at Microsoft dot com”电子邮件地址告知我们。

谢谢,

网络团队

于 2012-09-11T09:09:55.807 回答
0

在那种情况下,你不能那样做。主要问题是字符“¶”。

在 .Net 中,我们遇到了字符问题¶。你可以对此进行研究。

一一取uri'参数。将它们逐一添加并进行比较。也许您可以使用“¶”字符的方法来创建或替换它。

例如;

Dim uri = New Uri("http://www.example.org/test?helloworld=foo%B6bar")

Assert.AreEqual("http://www.example.org/test?helloworld=foo¶bar", uri.Host+uri.AbsolutePath+"?"+uri.Query)

那行得通

uri.AbsolutePath: /test

url.Host:http://www.example.org _

uri.Query: helloworld=foo¶bar

于 2012-08-17T12:04:40.427 回答