字符串长度评估错误
我的同事和我正在调试他正在处理的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时'Watch'窗口中变量的屏幕截图: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是调用的参数。 即使绕过这些参数并使用新的字符串,我们仍然会得到错误。
我有2个建议
使用ILDASM来查看正在生成的IL,可能在此发布IL,以便社区可以看一看
例如,将参数'AppName'的名称更改为非常不同的'xxxAppName'。
我知道第2点似乎毫无意义,但我过去遇到了看似无法解释的情况,只是发现某些东西没有被编译或者存在范围冲突,而调试器显示了您的期望。 而且,它不会伤害尝试:)
不幸的是,你的代码示例并不显示调用失败的构造函数的位置和方式,即。 其中实例化AppActiveDirectoryDomain
类型的对象。 (根据您提供的最后一个代码示例,这并不重要。)
话虽如此,我曾经在Visual Studio中遇到过类似的非逻辑问题,曾经在代码合同(它重新编写从编译器发出的CIL指令)和另一次出现随机原因时使用。 我从来没有发现真正的问题,我记得在一个完全不同的地方改变了一些代码,突然间,问题解决了。
我怀疑有时调试器会以某种方式与实际程序的状态不同步。
一些问题:
编译器运行后,您是否使用了重写CIL(= MSIL)代码的工具? (例如代码合同或PostSharp)
难道你的调试器符号文件或程序数据库与编译的代码不同步吗? 你有没有进行项目清理?
接下来你可以试试这个:
语句if ("AOD".Length == 0) throw new ArgumentNullException(...);
只抛出特定的构造函数? 或者,如果将该语句移到调用者函数,问题是否会持续存在? 如果将它移动到Main()
方法,它是否仍然存在?
如果您有一个可用的调试器,请尝试使用其他调试器的代码(有关MSIL调试器的关于StackOverflow的其他问题的链接)。
这原来是一个64位问题。 或者至少它只是一个运行64位的问题。 在64位操作系统上的IIS 7.0中,默认情况下,所有网站都托管在64位进程中。 如果我们将服务设置为32位进程,问题就会消失。
链接地址: http://www.djcxy.com/p/917.html