字符串长度评估不正确

时间:2010-04-30 17:34:58

标签: c# wcf string

我的同事和我正在调试他正在处理的WCF服务中的问题,其中字符串的长度未被正确评估。他正在运行此方法来对其WCF服务中的方法进行单元测试:

// Unit test method
public void RemoveAppGroupTest()
{
    string addGroup = "TestGroup";
    string status = string.Empty;
    string message = string.Empty;

    appActiveDirectoryServicesClient.RemoveAppGroup("AOD", addGroup, ref status, ref message);
}


// Inside the WCF service
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public void RemoveAppGroup(string AppName, string GroupName, ref string Status, ref string Message)
{
    string accessOnDemandDomain = "MyDomain";

    RemoveAppGroupFromDomain(AppName, accessOnDemandDomain, GroupName, ref Status, ref Message);
}

public AppActiveDirectoryDomain(string AppName, string DomainName)
{
    if (string.IsNullOrEmpty(AppName))
    {
        throw new ArgumentNullException("AppName", "You must specify an application name");
    }
}

我们尝试进入.NET源代码以查看正在接收的值string.IsNullOrEmpty,但是当我们尝试评估变量时,IDE打印了此消息:'无法获取本地值或参数'值'因为它在这个指令指针上不可用,可能是因为它已被优化掉了。 (所涉及的项目均未启用优化)。因此,我们决定在长度检查之前尝试在方法本身内明确设置变量的值 - 但这没有帮助。

// Lets try this again.
public AppActiveDirectoryDomain(string AppName, string DomainName)
{
    // Explicitly set the value for testing purposes.
    AppName = "AOD";

    if (AppName == null)
    {
        throw new ArgumentNullException("AppName", "You must specify an application name");
    }

    if (AppName.Length == 0)
    {
        // This exception gets thrown, even though it obviously isn't a zero length string.
        throw new ArgumentNullException("AppName", "You must specify an application name");
    }
}

我们真的把头发拉出来了。有没有其他人经历过这样的行为?有关调试的提示吗?


这是AppActiveDirectoryDomain对象的MSIL,其中发生了行为:

.method public hidebysig specialname rtspecialname instance void .ctor(string AppName, string DomainName) cil managed
{
.maxstack 5
.locals init (
    [0] class [System]System.Net.NetworkCredential ldapCredentials,
    [1] string[] creds,
    [2] string userName,
    [3] class [mscorlib]System.ArgumentNullException exc,
    [4] class [System.DirectoryServices]System.DirectoryServices.ActiveDirectory.DirectoryContext directoryContext,
    [5] class [System.DirectoryServices]System.DirectoryServices.ActiveDirectory.Domain domain,
    [6] class [System.DirectoryServices.Protocols]System.DirectoryServices.Protocols.LdapException V_6,
    [7] class [mscorlib]System.Exception V_7,
    [8] bool CS$4$0000,
    [9] char[] CS$0$0001,
    [10] string[] CS$0$0002)
L_0000: ldarg.0 
L_0001: ldsfld string [mscorlib]System.String::Empty
L_0006: stfld string MyNamespace.MyClass.AppActiveDirectoryDomain::appOU
L_000b: ldarg.0 
L_000c: call instance void [mscorlib]System.Object::.ctor()
L_0011: nop 
L_0012: nop 
L_0013: ldstr "AOD"
L_0018: call bool [mscorlib]System.String::IsNullOrEmpty(string)
L_001d: ldc.i4.0 
L_001e: ceq 
L_0020: stloc.s CS$4$0000
L_0022: ldloc.s CS$4$0000
L_0024: brtrue.s L_0037
L_0026: nop 
L_0027: ldstr "AppName"
L_002c: ldstr "You must specify an application name"
L_0031: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string, string)
L_0036: throw

string.IsNullOrEmpty来电的MSIL:

.method public hidebysig static bool IsNullOrEmpty(string 'value') cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: brfalse.s L_000d
    L_0003: ldarg.0 
    L_0004: callvirt instance int32 System.String::get_Length()
    L_0009: ldc.i4.0 
    L_000a: ceq 
    L_000c: ret 
    L_000d: ldc.i4.1 
    L_000e: ret 
}

修改

以下是抛出ArgumentNullException时“监视”窗口中变量的屏幕截图:http://imgur.com/xQm4J.png

另外,第二个屏幕截图显示了在检查字符串的长度时抛出异常,在明确声明上面5行之后:http://imgur.com/lSrk9.png

更新#3:我们尝试更改局部变量的名称,并通过空检查和长度检查,但在调用string.IsNullOrEmpty时失败。请参阅此屏幕截图:http://imgur.com/Z57AA.png


对策:

  • 我们不使用任何可以修改MSIL的工具。我们已经执行了清理,并且还手动删除了构建目录中的所有文件,并强制重建...同样的结果。

  • 以下语句的计算结果为true,并输入if块:if (string.IsNullOrEmpty("AOD")) { /* */ }

  • 构造函数的调用如下:

    try { using (AppActiveDirectoryDomain domain = new AppActiveDirectoryDomain(AppName, DomainName)) { } }

这紧接在WCF服务方法本身内; AppName和DomainName是调用的参数。即使绕过这些参数并使用新字符串,我们仍然会得到错误。


3 个答案:

答案 0 :(得分:2)

我有2条建议

  1. 使用ILDASM查看正在生成的IL,可能会在此处发布IL,以便社区可以查看

  2. 例如,将参数'AppName'的名称更改为非常不同的'xxxAppName'。

  3. 我知道第2点可能看起来毫无意义,但我过去遇到过看似无法解释的情况,只是发现某些东西没有被编译或存在范围冲突,而调试器显示出您的期望。而且,尝试以下也不会有害:)

答案 1 :(得分:1)

不幸的是,您的代码示例未显示调用失败构造函数的位置和方式,即。其中实例化类型为AppActiveDirectoryDomain的对象。 (考虑到你提供的最后一个代码示例,并不重要。)

话虽这么说,我曾经在Visual Studio中遇到类似的非逻辑问题,一次是在使用Code Contracts(重写编译器发出的CIL指令)时,另一次是因为随机原因。我从来没有发现真正的问题,我记得在一个完全不同的地方改变了一些代码,突然之间,问题得到了解决。

我怀疑有时,调试器会以某种方式与实际程序的状态不同步。

有些问题:

  • 编译器运行后,您是否使用任何重写CIL(= MSIL)代码的工具? (例如Code Contracts或PostSharp)

  • 您的调试器符号文件或程序数据库是否与编译后的代码不同步?你有没有进行项目清理?

您可以尝试下一步:

  • 语句if ("AOD".Length == 0) throw new ArgumentNullException(...);是否仅仅抛出特定的构造函数?或者,如果将该语句移动到调用者函数,问题是否仍然存在?如果移动它,它是否仍然存在,例如到Main()方法?

  • 使用different debugger链接到StackOverflow上有关MSIL调试程序的其他问题的链接)尝试使用代码(如果有可用的话)。

答案 2 :(得分:0)

这结果是一个64位的问题。或者至少它只是一个运行64位的问题。在64位操作系统上的IIS 7.0中,默认情况下,所有网站都托管在64位进程中。如果我们将服务设置为以32位进程托管,则问题就会消失。