Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
부모글 보이기/감추기
(연관된 글이 1개 있습니다.)
3.2 PDB 파일에 따른 Debug 정보 - .NET 2.0 Web Application Project + Library 유형의 프로젝트

C# 라이브러리 유형의 "BaseLibrary" 프로젝트는 이전 토픽에서 설명했던 프로젝트를 그대로 사용합니다. .NET 2.0 Web Application Model Project 유형은 VS.NET 2005에 기본 웹 사이트 프로젝트 모델이 아닌 새로 나온 유형의 프로젝트입니다.
이에 대해서는 다음의 토픽에서 설명해 놓았으므로 참조하시기 바랍니다.

https://www.sysnet.pe.kr/2/0/288

Web Application 프로젝트의 이름은 "WebApplication1"입니다. Default.aspx/Default.aspx.cs 파일을 포함하고 있으며 내용은 다음과 같습니다.

        private void Form1_Load(object sender, EventArgs e)
        {
            BaseLibrary.ThrowClass throwClass = new BaseLibrary.ThrowClass();
            throwClass.TestMethod();
        }

이번에도 역시 환경을 어떻게 구성하는지에 따라서 우리가 얼마나 유용한 오류 정보를 얻을 수 있는지 알아볼 텐데요. 실제 서비스를 하는 경우를 가정하고 예를 들어보겠습니다. 즉, 사용자가 웹 프로젝트를 돌아다니다가 보는 오류가 난 화면이 아닌 이벤트 뷰어에 남겨진 내용을 기준으로 살펴보겠습니다.

첫 번째로 BaseLibrary.pdb / WebApplication1.pdb 파일이 bin 폴더에 함께 있는 경우에 예외가 발생하면 다음과 같은 내용의 이벤트 로그가 남겨집니다. 그중에서 Stack Trace 부분만을 살펴보겠습니다.

Stack trace:    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.Open(String path, FileMode mode)
   at BaseLibrary.ThrowClass.TestMethod() in D:\temp2\PdbSample\BaseLibrary\ThrowClass.cs:line 14
   at WebApplication1._Default.Page_Load(Object sender, EventArgs e) in D:\temp2\PdbSample\AspNet\WebApplicationModel\WebApplication1\Default.aspx.cs:line 19
   at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
   at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
   at System.Web.UI.Control.OnLoad(EventArgs e)
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

WinForm Application의 예를 보신 분들이라면 결과를 예측하실 수 있으셨을 텐데요. 그때와 마찬가지로, 해당 오류가 발생한 모듈과 관련해서 PDB 파일이 존재하면 구체적인 소스 파일과 라인 번호를 얻어낼 수 있습니다. 또한 릴리스 빌드에서도 "pdb-only" 유형의 PDB 파일을 생성하는 것도 동일합니다. 일단, 기본적인 사항들은 WinForm에서의 PDB 역할을 살펴보았던 것과 동일합니다.

그런데, ^^ 한 가지 더 고려할 것이 있지요. 바로, web.config에 있는 compilation[@debug] ="true" 또는 "false"는 어떤 영향을 미칠지에 대해서입니다.

아시는 것처럼, Web Application은 첫 번째로 프로젝트 빌드를 하면 Code Behind 파일의 코드 파일들이 컴파일 되어 /bin 폴더에 위치하게 됩니다. 이후에 사용자들이 실제로 aspx 페이지를 방문하게 되면서 웹 사이트의 /bin 파일들은 shadow-copy가 이뤄지게 됩니다. 이번 예제에서처럼 웹 응용 프로그램의 이름이 "WebApplication1"인 경우에는 다음과 같은 폴더에 shadow copy가 이루어집니다.

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\webapplication1

aspx는 /bin 폴더에 있는 DLL에 포함된 code behind 클래스들로부터 실행 시에 상속을 받아서 동적으로 컴파일 되어집니다. 바로 이때의 컴파일을 "debug" 모드로 할 것인지, "release" 모드로 할 것인지를 결정하는 것이 web.config의 compilation[@debug] 값입니다. 예제 WebApplication1 프로젝트를 빌드해서 네비게이션을 하게 되면, 다음과 같은 파일들이 ASP.NET 임시 폴더에 생성된 것을 확인할 수 있습니다.

App_Web_dquidpq_0.cs
App_Web_dquidpq_1.cs
App_Web_dquidpq_.dll ( release 빌드 시에는 dll만 생성됨 )
App_Web_dquidpq_.pdb

보시는 것처럼, compilation[@debug] ="true"인 경우에는, PDB 파일과 cs 소스 파일까지 생성된 것을 볼 수 있습니다. 하지만, 그 값을 "false"로 지정하게 되면, pdb 및 소스 파일은 생성되지 않고 DLL 파일만 생성되게 됩니다. debug 빌드 시에 cs 소스 파일을 유지하는 이유는 PDB 파일 내부에 소스 파일의 위치 정보까지 포함하고 있기 때문에 가용한 경우 cs 파일까지 있다면 더욱 확실한 디버그를 할 수 있습니다.

그럼, 이제 compilation[@debug] = "false" 값으로 놓고 default.aspx를 방문해 볼까요? 그럼, 이제 다음과 같은 이벤트 로그 오류 정보를 얻을 수 있습니다.

Stack trace:    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, 
      FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.Open(String path, FileMode mode)
   at BaseLibrary.ThrowClass.TestMethod() in D:\temp2\PdbSample\BaseLibrary\ThrowClass.cs:line 14
   at WebApplication1._Default.Page_Load(Object sender, EventArgs e) in D:\temp2\PdbSample\AspNet\WebApplicationModel\WebApplication1\Default.aspx.cs:line 19
   at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
   at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
   at System.Web.UI.Control.OnLoad(EventArgs e)
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

보시는 것처럼, 달라진 것은 없습니다. 그렇습니다. default.aspx/cs 파일과 같은 응용 프로그램 구성이라면 굳이 compilation[@debug] 값을 "true"로 설정해 놓으실 필요는 없습니다. 그럼, 과연 이 옵션은 언제 필요할까요? ^^

asp.net의 코드는 code behind 파일에만 있는 것은 아니죠. 바로 aspx 파일 자체에 코드가 포함되어 있는 경우에는 compilation[@debug] 값을 "true"로 해놓는 것이 의미가 있어집니다.
차이를 확인하기 위해서, default.aspx의 html에 다음과 같이 코드를 추가해 보겠습니다.

----- default.aspx.cs -------
    public partial class _Default : System.Web.UI.Page
    {
        public BaseLibrary.ThrowClass throwClass = new BaseLibrary.ThrowClass();
    }

----- default.aspx -------
<head runat="server">
    <title>Untitled Page : <% throwClass.TestMethod(); %></title>
</head>

아래의 이벤트 로그는 compilation[@debug] = "true"인 경우입니다.

Stack trace:    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, 
        FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.Open(String path, FileMode mode)
   at BaseLibrary.ThrowClass.TestMethod() in D:\temp2\PdbSample\BaseLibrary\ThrowClass.cs:line 14
   at ASP.default_aspx.__Render__control3(HtmlTextWriter __w, Control parameterContainer) in d:\temp2\PdbSample\AspNet\WebApplicationModel\WebApplication1\Default.aspx:line 7
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
   at System.Web.UI.HtmlControls.HtmlTitle.Render(HtmlTextWriter writer)
   [이하 생략....]

아래의 이벤트 로그는 compilation[@debug] = "false"인 경우입니다.

Stack trace:    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, 
         FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at System.IO.File.Open(String path, FileMode mode)
   at BaseLibrary.ThrowClass.TestMethod() in D:\temp2\PdbSample\BaseLibrary\ThrowClass.cs:line 14
   at ASP.default_aspx.__Render__control3(HtmlTextWriter __w, Control parameterContainer)
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
   at System.Web.UI.HtmlControls.HtmlTitle.Render(HtmlTextWriter writer)
   [이하 생략....]

차이가 분명하지요. ^^ "true"인 경우에는 default.aspx 페이지의 어느 라인인지까지도 표시가 되어지는 반면, "false"인 경우에는 알 수 없습니다. (그런데, 어째서 여기서의 파일이 shadow-copy 임시 폴더에 있는 cs 파일이 아닌, 원래의 web site 폴더에 있는 aspx를 가리키고 있을까요? 이는 #line 지시자를 임시 폴더의 cs 파일에서 사용하고 있기 때문입니다. 이에 대해서는 나중에 기회되면 설명 드리겠습니다.)

그럼, 이것을 보고 어떻게 결론을 내리는 것이 좋을까요?

웹 애플리케이션인 경우에는 가능한 aspx 페이지에는 직접 코드를 사용하지 않는 것이 좋습니다. 만약, 사용해야 한다면 오류가 거의 발생하지 않을 코드에 대해서 해야 하거나, 부득이한 경우 처리 속도 저하를 감수하고 compilation[@debug] = "true"로 설정해서 배포를 해야 합니다. compilation[@debug] = "false"로 하는 경우라면, 위의 오류 스택에서 보는 것처럼, "ASP.className"과 같이 "ASP"로 시작한다면 aspx 페이지에서 오류가 났음을 이젠 알 수 있을 것입니다.

이러한 문제를 해결하기 위해 MS에 건의하고 싶은 것이 있다면 compilation 옵션에 "build" 속성과 "pdb" 속성을 분리해서 넣어 달라는 정도입니다. 즉, aspx에 코드를 사용하더라도 dll은 release로 빌드하지만 (C++의 경우와 비교해 보면, /Zi 옵션만으로 빌드) pdb 파일이 생성될 수 있도록 하는 조정을 할 수 있게 하면 좋겠지요. ^^ ([2006-08-10] 다시 읽어보니 ^^ 이 부분은 수정이 되어야 할 것 같습니다. "3.3 PDB 파일에 따른 Debug 정보 - .NET 2.0 Web Site Model Project"에 보면 제가 system.codedom에서 이것을 해결하는 방법을 제시했지요.)
[연관 글]






[최초 등록일: ]
[최종 수정일: 7/5/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 76  77  78  79  80  81  82  [83]  84  85  86  87  88  89  90  ...
NoWriterDateCnt.TitleFile(s)
11862정성태4/7/201920182개발 환경 구성: 437. .NET EXE의 ASLR 기능을 끄는 방법
11861정성태4/6/201919630디버깅 기술: 126. windbg - .NET x86 CLR2/CLR4 EXE의 EntryPoint
11860정성태4/5/201923504오류 유형: 527. Visual C++ 컴파일 오류 - error C2220: warning treated as error - no 'object' file generated
11859정성태4/4/201920728디버깅 기술: 125. WinDbg로 EXE의 EntryPoint에서 BP 거는 방법
11858정성태3/27/201921634VC++: 129. EXE를 LoadLibrary로 로딩해 PE 헤더에 있는 EntryPoint를 직접 호출하는 방법파일 다운로드1
11857정성태3/26/201919528VC++: 128. strncpy 사용 시 주의 사항(Linux / Windows)
11856정성태3/25/201919778VS.NET IDE: 134. 마이크로소프트의 CoreCLR 프로파일러 리눅스 예제를 Visual Studio F5 원격 디버깅하는 방법 [1]파일 다운로드1
11855정성태3/25/201921954개발 환경 구성: 436. 페이스북 HTTPS 인증을 localhost에서 테스트하는 방법
11854정성태3/25/201917608VS.NET IDE: 133. IIS Express로 호스팅하는 사이트를 https로 접근하는 방법
11853정성태3/24/201920408개발 환경 구성: 435. 존재하지 않는 IP 주소에 대한 Dns.GetHostByAddress/gethostbyaddr/GetNameInfoW 실행이 느리다면? - 두 번째 이야기 [1]
11852정성태3/20/201919622개발 환경 구성: 434. 존재하지 않는 IP 주소에 대한 Dns.GetHostByAddress/gethostbyaddr/GetNameInfoW 실행이 느리다면?파일 다운로드1
11851정성태3/19/201923374Linux: 8. C# - 리눅스 환경에서 DllImport 대신 라이브러리 동적 로드 처리 [2]
11850정성태3/18/201922433.NET Framework: 813. C# async 메서드에서 out/ref/in 유형의 인자를 사용하지 못하는 이유
11849정성태3/18/201921777.NET Framework: 812. pscp.exe 기능을 C#으로 제어하는 방법파일 다운로드1
11848정성태3/17/201918520스크립트: 14. 윈도우 CMD - 파일이 변경된 경우 파일명을 변경해 복사하고 싶다면?
11847정성태3/17/201922992Linux: 7. 리눅스 C/C++ - 공유 라이브러리 동적 로딩 후 export 함수 사용 방법파일 다운로드1
11846정성태3/15/201921643Linux: 6. getenv, setenv가 언어/운영체제마다 호환이 안 되는 문제
11845정성태3/15/201921770Linux: 5. Linux 응용 프로그램의 (C++) so 의존성 줄이기(ReleaseMinDependency) [3]
11844정성태3/14/201923099개발 환경 구성: 434. Visual Studio 2019 - 리눅스 프로젝트를 이용한 공유/실행(so/out) 프로그램 개발 환경 설정 [1]파일 다운로드1
11843정성태3/14/201918039기타: 75. MSDN 웹 사이트를 기본으로 영문 페이지로 열고 싶다면?
11842정성태3/13/201916396개발 환경 구성: 433. 마이크로소프트의 CoreCLR 프로파일러 예제를 Visual Studio CMake로 빌드하는 방법 [1]파일 다운로드1
11841정성태3/13/201916697VS.NET IDE: 132. Visual Studio 2019 - CMake의 컴파일러를 기본 g++에서 clang++로 변경
11840정성태3/13/201918321오류 유형: 526. 윈도우 10 Ubuntu App 환경에서는 USB 외장 하드 접근 불가
11839정성태3/12/201922277디버깅 기술: 124. .NET Core 웹 앱을 호스팅하는 Azure App Services의 프로세스 메모리 덤프 및 windbg 분석 개요 [3]
11838정성태3/7/201925893.NET Framework: 811. (번역글) .NET Internals Cookbook Part 1 - Exceptions, filters and corrupted processes [1]파일 다운로드1
11837정성태3/6/201939820기타: 74. 도서: 시작하세요! C# 7.3 프로그래밍 [10]
... 76  77  78  79  80  81  82  [83]  84  85  86  87  88  89  90  ...