My colleague and I are debugging a problem in the WCF service in which it works, where the string length is not evaluated correctly. He uses this method for the unit test method in his WCF service:
// 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"); } }
We tried to enter the .NET source code to find out what string.IsNullOrEmpty was received, but the IDE printed this message when we tried to evaluate the variable: "It is impossible to get the value of the local value or the argument" how "is not available in this instruction, maybe because it has been optimized. " (None of the projects involved included optimization). So, we decided to try to explicitly set the variable value inside the method itself just before checking the length, but this did not help.
// 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"); } }
We really pull our hair on it. Has anyone else experienced this behavior? Any tips on debugging it?
Here's the MSIL for the AppActiveDirectoryDomain object where the behavior occurs:
.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
And MSIL to call string.IsNullOrEmpty :
.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 }
Edit:
Here is a screenshot of the variable in the Watch window at the time of throwing ArgumentNullException: http://imgur.com/xQm4J. PNG
In addition, a second screenshot showing the exception that occurs when checking the length of a string after explicitly declaring 5 lines above: http://imgur.com/lSrk9.png
Update # 3: We tried to change the name of the local variable and skipped the zero check and length check, but failed when we call string.IsNullOrEmpty . See this screenshot: http://imgur.com/Z57AA.png .
Answers:
We do not use any tools that could change MSIL. We performed a cleanup and manually deleted all the files from the assembly directories and forcefully restored ... the same result.
The following statement evaluates to true and is included in the if block: if (string.IsNullOrEmpty("AOD")) { /* */ } .
The constructor is called like this:
try { using (AppActiveDirectoryDomain domain = new AppActiveDirectoryDomain(AppName, DomainName)) { } }
This is directly in the WCF service itself; AppName and DomainName are call parameters. Even bypassing these parameters and using new lines, we still get errors.