2010-04-30 5 views
7

동료와 저는 문자열 길이가 올바르게 평가되지 않는 곳에서 작업중인 WCF 서비스에서 문제를 디버깅하고 있습니다. 우리가 시도 할 때 우리는 string.IsNullOrEmpty는 수신 된 어떤 값을 확인하기 위해 .NET 소스 코드를 한 단계하려고문자열 길이가 잘못 계산되었습니다.

// 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"); 
    } 
} 

하지만, IDE는이 메시지를 인쇄 : 그는 단위 테스트 자신의 WCF 서비스의 방법이 방법을 실행 '로컬 또는 인수'value '값을이 명령 포인터에서 사용할 수 없으므로 가져올 수 없습니다. 아마도 최적화 된 것이므로 가능합니다.' (관련된 프로젝트 중 어느 것도 최적화가 활성화되어 있지 않습니다.) 그래서 우리는 길이 검사 직전에 메소드 자체의 변수 값을 명시 적으로 설정하기로 결정했습니다.하지만 도움이되지 않았습니다.

// 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"); 
    } 
} 

우리는 정말이 머리카락을 내고 있습니다. 다른 사람이 이와 같은 행동을 경험 했습니까? 디버깅에 대한 팁? string.IsNullOrEmpty 호출

.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 :

.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 
} 

편집 :


여기에 행동이 발생하는 인 AppActiveDirectoryDomain 객체에 대한 MSIL을의

또한 http://imgur.com/xQm4J.png

후 명시 적 선언, 문자열의 길이를 검사 할 때 예외를 나타내는 제 스크린이 발생되고 : 여기

51,515,이 경우 ArgumentNullException가 발생되는 순간의 '시계'창에서 변수의 스크린 샷이다 위의 5 줄 : http://imgur.com/lSrk9.png

업데이트 # 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은 호출에 대한 매개 변수입니다. 이러한 매개 변수를 무시하고 새 문자열을 사용하더라도 오류가 발생합니다.


+1

던져진 예외에 중단 점을 넣고 시계에'AppName'과'AppName.Length'를 추가하면 무엇을 보여줄까요? –

+0

그들은 'AppName == "AOD"와 "AppName.Length == 3"을 보여 주므로 올바르게 평가됩니다. 내 질문의 맨 아래에 스크린 샷을 첨부했습니다. –

+1

테스트를 모호하지 않게 만들 수 있습니다 :'if ("AOD".Length == 0) throw ...'. 그러면 변수의'AppName'이 문제의 출처가 될 수 있습니다. 예외가 계속 던져지면 예외를 수행 할 수 없습니다. – stakx

답변

0

이것은 64 비트 문제로 밝혀졌습니다. 아니면 적어도 64 비트 실행 문제 일뿐입니다. 64 비트 OS의 IIS 7.0에서는 모든 웹 사이트가 기본적으로 64 비트 프로세스로 호스팅됩니다. 32 비트 프로세스에서 서비스를 호스팅하도록 설정하면 문제가 해결됩니다.

1

불행히도 코드 예제에는 실패한 생성자가 호출 된 위치와 방법이 표시되지 않습니다. 여기서 유형 AppActiveDirectoryDomain의 오브젝트가 인스턴스화됩니다. (당신이 제공 한 마지막 코드 예제를 고려할 때 중요하지 않습니다.)

이전에 비주얼 스튜디오에서 비슷한 비 논리적 인 문제를 겪었습니다. 한번은 코드 계약을 가지고 놀았습니다. 컴파일러에서 생성 된 CIL 명령어) 및 임의의 이유로 다른 시간. 나는 진정한 문제를 발견하지 못했고, 완전히 다른 장소에서 일부 코드를 변경 한 것을 기억하고 갑자기이 문제가 해결되었습니다.

때로는 디버거가 어떻게 든 실제 프로그램 상태와 동기화되지 않을 것으로 생각됩니다.

몇 가지 질문 :

  • 는 다시 쓰기 컴파일러를 실행 한 후 CIL (= MSIL) 코드를 어떤 도구를 사용하십니까? (예 : 코드 계약 또는 PostSharp)

  • 디버거 기호 파일 또는 프로그램 데이터베이스가 컴파일 된 코드와 동기화되지 않았습니까? 프로젝트 정리를 수행 했습니까?

    • 가 문 if ("AOD".Length == 0) throw new ArgumentNullException(...);은 특정 생성자 내부에 던져 않습니다

    이 다음에 시도 할 수? 또는 호출자 함수로 해당 문을 이동하면 문제가 지속됩니까? 예를 들어 이동하면 계속 유지됩니까? Main() 방법으로? (MSIL은을으로 디버거에 대해 StackOverflow의 다른 질문에 링크)를 사용할 일이 있으면

  • different debugger와 코드를보십시오.

+0

제 질문에 대한 답변을 추가했습니다. –

2

나는이 개 제안

커뮤니티를 살펴에게

  • 변경을 할 수 있습니다

    1. 사용 ILDASM 가능성이 생성되고있는 IL 살펴보고 여기 IL을 게시 할 수 있습니다 'AppName'인수의 이름이 매우 다른 'xxxAppName'과 같은 것입니다. 디버거가 예상 보여줍니다 동안 만 일이 컴파일되지 않았거나 범위 충돌이 있다는 것을 발견, 겉으로는 설명 할 수없는 상황을 건너

    나는 지점이 무의미 보일 수 있습니다 알고 있지만, 나는 과거에 . 그리고 시도해도 좋을 것입니다.

  • +0

    로컬 변수에 다른 이름을 사용하려고 시도했지만, 길이 검사와 마찬가지로 수동 null 체크가 성공했지만'string.IsNullOrEmpty'에서 실패합니다. 게시중인 세 번째 스크린 샷 링크를 참조하십시오. –

    +0

    나는 IL을 게시했다. 그것은 우리 중 누구에게 비린 해 보이지 않지만 우리 중 누구도 일리노이 전문가는 아닙니다. –

    +0

    @Justin, 일리노이 괜찮아 보이는 ... 당신은 디버그 창 (Diagnostics.Debug.WriteLine)에 몇 가지 메시지를 쓸 수 있습니다. 우리는 디버거가보고있는 것을 보았지만 실행중인 코드가 무엇을보고 있는지 알 수 있습니다. –

    관련 문제