Мой коллега и я отлаживаем проблему в службе 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");
}
}
Мы действительно выдернули наши волосы на этом. Кто-нибудь еще испытывал подобное поведение? Любые советы по его отладке?
Вот MSIL для объекта AppActiveDirectoryDomain
, где происходит поведение:
.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
И MSIL для 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:
Вот скриншот переменной в окне 'Watch' в момент возникновения исключения 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 являются параметрами для вызова. Даже обходя эти параметры и используя новые строки, мы все равно получаем ошибки.