Mi compañero de trabajo y yo estamos solucionando un problema en un servicio de WCF en el que está trabajando cuando la longitud de una cadena no se evalúa correctamente. Él se está ejecutando este método de unidad de prueba un método en su servicio WCF:Longitud de cadena evaluando incorrectamente
// 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");
}
}
Tratamos de entrar en el código fuente de .NET para ver qué valor string.IsNullOrEmpty
estaba recibiendo, pero el IDE impreso este mensaje cuando intentamos evalúe la variable: 'No se puede obtener el valor del' valor 'local o de argumento, ya que no está disponible en este puntero de instrucción, posiblemente porque se ha optimizado fuera de lugar'. (Ninguno de los proyectos involucrados tiene optimizaciones habilitadas). Entonces, decidimos intentar establecer explícitamente el valor de la variable dentro del método mismo, inmediatamente antes de la verificación de la longitud, pero eso no ayudó.
// 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");
}
}
Estamos realmente tirando de nuestros pelos en este caso. ¿Alguien más ha experimentado un comportamiento como este? ¿Alguna sugerencia para depurarlo?
Aquí está el MSIL para el objeto AppActiveDirectoryDomain
, donde el comportamiento que está ocurriendo:
.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
Y el MSIL para la llamada 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
}
Editar:
Aquí está una captura de pantalla de la variable en la ventana de 'reloj' en el momento en que se lanza el ArgumentNullException: http://imgur.com/xQm4J.png
Además, una segunda pantalla que muestra la excepción que se produce cuando el control de la longitud de la cadena, después de declarar de manera explícita 5 líneas arriba: http://imgur.com/lSrk9.png
Actualización # 3: Intentamos cambiar el nombre de la variable local y pasa la comprobación nula y la verificación de longitud, pero falla cuando llamamos al string.IsNullOrEmpty
. Ver esta captura de pantalla: http://imgur.com/Z57AA.png.
respuestas:
no usamos ninguna herramienta que modificarían el MSIL. Hemos realizado una limpieza y también hemos eliminado manualmente todos los archivos de los directorios de compilación y hemos forzado una reconstrucción ... el mismo resultado.
La siguiente declaración se evalúa como verdadera y entra en el bloque if:
if (string.IsNullOrEmpty("AOD")) { /* */ }
.El constructor se llama así:
try { using (AppActiveDirectoryDomain domain = new AppActiveDirectoryDomain(AppName, DomainName)) { } }
Esta es inmediatamente dentro del método de servicio WCF sí mismo; AppName y DomainName son parámetros de la llamada. Incluso pasando por alto estos parámetros y utilizando nuevas cadenas, seguimos recibiendo los errores.
Si coloca un punto de interrupción en la excepción que arroja, y agrega 'AppName' y' AppName.Length' a los relojes, ¿qué muestran? –
Muestran 'AppName == "AOD"' y 'AppName.Length == 3', por lo que se evalúan correctamente. He adjuntado una captura de pantalla al final de mi pregunta. –
Puede hacer que la prueba sea aún menos ambigua: 'if (" AOD ".Length == 0) throw ...'. Esto descartaría la variable 'AppName' como fuente de sus problemas. Si aún se lanza la excepción, puede que no haya nada que puedas hacer al respecto. – stakx