Неверная Оценка Длины Строки

мой коллега и я отлаживаем проблему в службе 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 для , где поведение происходит:

.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 CS00,
    [9] char[] CS01,
    [10] string[] CS02)
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 CS00
L_0022: ldloc.s CS00
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

Update #3: мы попытались изменить имя локальной переменной, и она проходит проверку null и проверку длины, но не удается, когда мы вызываем 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 ответов


У меня есть 2 предложения

  1. используйте ILDASM, чтобы взглянуть на Il, который генерируется, возможно, опубликуйте IL здесь, чтобы сообщество могло взглянуть

  2. измените имя аргумента "AppName" на что-то совсем другое "xxxAppName", например.

Я знаю, что пункт 2 может показаться бессмысленным, но в прошлом я сталкивался с кажущимися необъяснимыми ситуациями, только чтобы обнаружить, что что-то не было скомпилирован или произошел конфликт области, в то время как отладчик показывает, что вы ожидаете. И, не помешает попробовать:)


к сожалению, ваши примеры не показывают, где и как это не вызывается конструктор, то есть. где объект типа AppActiveDirectoryDomain инстанцируется. (Не то, чтобы это имело значение, учитывая последний пример кода, который вы предоставили.)

это, как говорится, я сталкивался с подобными нелогичными проблемами в Visual Studio раньше, один раз, когда играл с контрактами кода (который переписывает инструкции CIL, выпущенные из компилятора), а в другой раз по случайной причине. Я так и не нашел истинная проблема, я помню, что изменил какой-то код в совершенно другом месте, и внезапно проблема была решена.

Я подозреваю, что иногда отладчик каким-то образом выходит из синхронизации с фактическим состоянием программы.

несколько вопросов:

  • используете ли вы какие-либо инструменты, которые перезаписывают код CIL (=MSIL) после запуска компилятора? (например, кодовые контракты или PostSharp)

  • может быть, что ваш файлы символов отладчика или база данных программы не синхронизирована со скомпилированным кодом? Вы выполнили проект очистки?

вы можете попробовать следующее:

  • слова if ("AOD".Length == 0) throw new ArgumentNullException(...); только бросить внутри этого конкретного конструктора? Или проблема сохраняется, если вы переместите этот оператор в функцию вызывающего абонента? Он все еще сохраняется, если вы переместите его, например, в Main() способ?

  • попробовать свои код с разные отладчик (ссылки на другой вопрос о StackOverflow об отладчиках MSIL), если у вас есть один доступный.


Это оказалось 64-битной проблемой. Или, по крайней мере, это только проблема с 64-разрядными. В IIS 7.0 на 64-разрядной ОС все веб-сайты по умолчанию размещаются в 64-разрядных процессах. Если мы установим службу для размещения в 32-разрядном процессе, проблема исчезнет.