태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.



Google
 

가끔 우리 솔루션에서는 System.Runtime.Serialization.SerializationException이 발생한다. 문제가 발생한 상황이니까 예외가 던져지는 것은 당연하다. 하지만 문제는 실제 에러는 SerializationException이 아니라는 것이었다. 그리고 SerializationException은 다들 알다시피 객체가 Serialization/Deserialization하는 과정에서 나는 문제인데, 이 에러가 날만한 시나리오를 딱히 생각해낼 수는 없었다.

Stacktrace를 보니 이 예외는 솔루션 내부의 로깅 컴포넌트에서 던져지고 있었다. 로깅 컴포넌트는 에러나 문제가 발생했을 때 그 정보를 파일에 기록하는 역할을 하는 COM+ 서버 타입 컴포넌트였다. 문제가 생긴 함수는 다음과 같았다.

Public Function WriteException(ByVal userName as string, ByVal exception as System.Exception) as string

 
이 함수는 Exception객체를 받아서 그 예외 정보를 포맷한 뒤 파일에 쓰는 함수였다. 여기서 문제가 될만한 부분은 인자로 System.Exception 객체를 받는 부분뿐이었는데, 로깅 컴포넌트가 COM+ 서버 타입이기 때문에 Exception객체가 프로세스간 이동을 하기 때문이었다. 하지만 System.Exception 객체가 Serialization 과정에서 문제가 생긴다는 것은 사실 상상하기가 힘들었는데..
 
암튼 조사 끝에 이유를 알아내었다. 문제가 생긴 객체는 모두 System.Web.HttpException이었다. 그리고 이 System.Web.HttpException이 무슨 이유인지는 몰라도, .NET Framework 1.1에서는 Serializable로 마킹이 되어 있지 않다는 사실을 알게 되었다. 즉 Logging컴포넌트에서 HttpException을 인자로 받았는데, 이게 COM+ 서버 타입이라 프로세스 이동을 하려면 Serialization과정을 거치다가.. Serializable 마킹이 안 되어 있어서 Serialization작업을 못한 것이다. 그래서 SerializationException도 났던 것이고..
 
.NET 1.1과 2.0의 System.Web.HttpException을 Reflector로 열어보면 다음과 같다.
 
1.1의 경우
DotNet1HttpException
 
2.0의 경우
DotNet2HttpException
 
.NET Framework 2.0에서는 Serializable 어트리뷰트가 있지만, .NET Framework 1.1에서는 없는 것을 볼 수 있다. 왜 1.1에서 없는지는 속시원한 설명을 제대로 찾지 못했다. 현재로서는 버그가 아닐까 추측만 될 뿐이다. 그리고 2.0이상부터는 이런 문제가 없는 것 같다.
 
우리 솔루션은 로깅 컴포넌트의 COM+ 유형을 Server Type에서 Library Type 으로 바꾸어서 해결했다. Library Type이라면 프로세스가 다르지 않을테고 프로세스간 객체 이동도 없을 것이니, 이 문제를 신경쓰지 않아도 되는 것이다.
 
다른 곳에도 이 케이스처럼 Exception객체가 프로세스를 넘어가는 시나리오가 있다면, 이 문제를 조심해야 할 것이다.
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
top

Trackback Address :: http://lazydeveloper.net/trackback/2567077 관련글 쓰기

Write a comment


Tistory 태그: ,

메서드를 작성할 때에, Argument가 다 정상적으로 들어올거라고 가정해서는 절대로 안 된다. 반드시 다음과 같이 Validation 코드를 작성해서, 메서드의 가장 위에 둘 필요가 있다.


1. Argument 가 null인지 검사해서, null이라면 NullArgumentException을 던져야 한다. 아래 코드는 .NET Framework의 System.Windows.Annotations.Annotation 클래스의 WriteXml메서드의 가장 윗부분 코드이다.


public void WriteXml(XmlWriter writer)
{
   
if (writer == null)
   
{
       
throw new ArgumentNullException("writer");
   
}
}
 

2. 각 argument값 자체의 이상 유무를 검사한다.
기본적인 string 이라면, 전에 올렸던 글처럼 IsNullOrEmpty 메서드를 써서 검사하고, 다른 type이라면.. -_-;; 다양한 것을 다 여기서 다루기는 힘드므로.. 일단 적절하게 검사한다.  아래 예제는 위에서도 사용한 System.Windows.Annotations.Annotation 클래스의 WriteXml메서드의 일부분인데, 넘어온 XML의 내부 스트링들을 IsNullOrEmpty메서드로 검사해서, 없을 경우 채워넣는 코드이다.


  if (string.IsNullOrEmpty(writer.LookupPrefix("http://schemas.microsoft.com/windows/annotations/2003/11/core")))
   
{
       
writer.WriteAttributeString("xmlns", "anc", null, "http://schemas.microsoft.com/windows/annotations/2003/11/core");
   
}
   
if (string.IsNullOrEmpty(writer.LookupPrefix("http://schemas.microsoft.com/windows/annotations/2003/11/base")))
   
{
       
writer.WriteAttributeString("xmlns", "anb", null, "http://schemas.microsoft.com/windows/annotations/2003/11/base");
   
}
}
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
top

Trackback Address :: http://lazydeveloper.net/trackback/2567076 관련글 쓰기

Write a comment


C#에서 문자열 내부에 "를 쓸때는 Escape 문자인 \를 써서 표현을 해야 한다. 아래와 같이

 

string s = "\"Lazy\" \"Developer\"";

 

이 경우 실제 문자열은  "Lazy" "Developer" 이렇게 인식을 하게 되는 것이다.

 

VB.NET에서는 "를 써서 똑같은 효과를 볼 수 있다.

 

Dim str As String = """Lazy"" ""Developer"""
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
top

Trackback Address :: http://lazydeveloper.net/trackback/2567068 관련글 쓰기

Write a comment


어떤 메소드의 호출자 정보를 알고 싶을 때가 있다. 문제가 발생했는데 디버깅하기가 힘들 때, 이런 호출자 정보들을 로그 등에 기록해둔다면, 문제 해결에 유용하게 쓰일 수 있는 단서가 될 것이다.

System.Diagnostics.StackFrame, System.Diagnostics.StackTrace 객체를 사용해서 호출자 정보를 얻을 수가 있다.

string stackTraceString = null;

System.Diagnostics.StackTrace objStackTrace = new System.Diagnostics.StackTrace(new System.Diagnostics.StackFrame(1));

stackTraceString = objStackTrace.ToString();

return stackTraceString;


마지막에 return되는 값은 다음과 같이 생겼다. 이것이 바로 현재 메소드를 호출한 Caller Method이다.

   at StackFrameTest.Class3.class3Method(String param)



* StackFrame 클래스를 생성할 때 주는 파라미터 - Integer - 를 조정해서, 각 호출 스택 상의 레벨을 모두 추적할 수도 있다.
* 간단하게 ToString()을 하면 저렇게 나오게 되지만, StackFrame 객체에는 GetFileName,
GetFileLineNumber 등의 더 자세한 정보를 알 수 있는 메소드들도 있다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
top

Trackback Address :: http://lazydeveloper.net/trackback/2567048 관련글 쓰기

  1. BlogIcon 카니스 2007/02/26 12:21 댓글주소 | 수정/삭제 | 댓글

    Java쪽에서도 Log를 남기는 컴포넌트가 있지요. 예를들어
    log.debug("aa";); 라고 남긴다면, 해당 클래스및 메소드 위치, row 위치, 메시지등이
    기록에 남습니다.
    로그라.. 필수죠. 개발자에겐. ^^

    • BlogIcon kkongchi 2007/02/27 13:25 댓글주소 | 수정/삭제

      그렇죠..로그는 필수...하지만 비주얼 스튜디오같은 IDE를 써서 디버깅하지 못할 경우가 간혹 있을 수가 있으니까..

  2. BlogIcon 미친병아리 2007/03/26 00:26 댓글주소 | 수정/삭제 | 댓글

    유용한 팁들이 많네요..

Write a comment



현재, 몸담고 있는 회사의 솔루션 코드를 보다가 이런 것을 발견했다.

Imports System.Threading

Public Class Metadata
    Private myMetadata As New InsightMetadata

    Private Shared _singleton As Metadata
    Private Shared myInstanceMutex As New Mutex


    Private Sub New()
    End Sub

    Public Shared Function GetInstance() As Metadata

        myInstanceMutex.WaitOne()

        Try
            If _singleton Is Nothing Then
                _singleton = New Metadata
            End If

        Finally
            myInstanceMutex.ReleaseMutex()
        End Try

        Return _singleton

    End Function

    Public ReadOnly Property Appset(ByVal appsetID As String, ByVal app As String, ByVal userName As String, ByVal context As String, ByVal security As String) As Appset
        Get
            If (IsNothing(myMetadata.Appset(appsetID))) Then
                load(appsetID, app, userName, context, security)
            End If

            Return myMetadata.Appset(appsetID)
        End Get
    End Property

    Public Overloads Sub refresh(ByVal appset As String, ByVal app As String, ByVal userName As String, ByVal context As String, ByVal security As String)
        load(appset, app, userName, context, security)
    End Sub

    Private Function load(ByVal appsetID As String, ByVal app As String, ByVal userName As String, ByVal context As String, ByVal security As String) As Appset
        ...
    End Function
End Class

이 코드는 클래스 이름으로도 대충 짐작이 가듯이 전체 프로그램의 공용 Meta 데이터들을 저장해 놓는 모듈이다. 이런 메타 데이터들은 많은 모듈에서 사용하면서도 프로그램이 구동 중일 때는 거의 바뀌지 않는다는 속성이 있다. 그래서 이런 메타데이터는 메모리에 하나 올려놓고, 그것을 모두 사용하면 가장 좋을 것이다. 매번 읽어오지도 않고, 각 모듈에서 각각 호출하지도 않게 하는 최선의 방법일테니까 말이다.

싱글턴 패턴

이렇게 메모리에 딱 하나의 인스턴스를 올려놓을 필요가 있을 때 쓰는 것이 바로 "Singleton" 패턴이다. "Design Patterns"에 나오는 정의를 보자면 "ensure a class has only one instance, and provide a global point of access to it""한 클래스가 단지 하나의 인스턴스만을 가지게 하고, 그것에 액세스할 수 있는 글로벌한 포인트를 제공하는 것"이라고 되어 있다. 아래 위키 백과 페이지를 참조하면 더 자세하게 알 수 있다.

싱글턴 패턴 - 위키 백과

싱글턴 쓰임새

싱글턴 패턴은 쓰임새가 그렇게 다양하진 않다. 주로 위의 코드와 같은 메타 데이터, 혹은 파일 로깅 등의 공용 모듈에서 사용된다. (물론 위의 조건 - 하나의 인스턴스, 글로벌한 액세스 - 을 충족시킨다면 그 쓰임새 자체는 제한이 없다) 하지만 아래 글에서 볼 수 있듯이 이 Singleton 클래스는 다른 클래스들과 단단하게 결합되는(tightly-coupled) 경향이 있고, 이는 Unit Test를 어렵게 하고 전체적으로 각 모듈의 독립성을 저해하는 요소로 작용할 수도 있다. 아래와 같은 글들을 참고할 만 하다. (물론 주의깊게 읽어야 할 것이다. 단지 주장일 뿐이니)

IBM Developerworks: Use Your Singleton Wisely
PrestonLee.com: Singletons causes cancer

권장하는 닷넷 코드

MSDN: Exploring the Singleton Design Pattern

Implementing the Singleton Pattern in C#

MSDN의 Article도 괜찮긴 하지만, 2번째 글은 그야말로 총정리다. C#에서 가능한 모든 경우의 Singleton 구현에 대해서 모두 그 장단점을 서술해놓고 있다. 2번째 글을 보면 이 글의 처음에 나온 코드는 (MSDN 글을 봐도 그렇다) 그다지 좋지 못한 예라는 것을 알 수 있다..^^ 그래서 나도 현재 코드를 바꾸고 있는 중이다. 2번째 글의 네번째 버전으로(아래와 같이) 바꿀 예정이다. MSDN Article에 있는 코드와도 거의 같다고 보면 된다.

public sealed class Singleton
{
static readonly Singleton instance=new Singleton();

// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton()
{
}

Singleton()
{
}

public static Singleton Instance
{
get
{
return instance;
}
}
}

이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
top

Trackback Address :: http://lazydeveloper.net/trackback/2567037 관련글 쓰기

  1. BlogIcon 카니스 2007/02/14 10:06 댓글주소 | 수정/삭제 | 댓글

    자바랑 C#은 역시 비슷 .^^

    • BlogIcon kkongchi 2007/02/14 11:18 댓글주소 | 수정/삭제

      ^^ 그렇죠.. 일단 C#은 자바를 베낀 것이 아닌가 싶을 정도로 비슷하니까요..근데 요즘은 서로서로 베끼고 있더군요..-_-;;

Write a comment


아직 여기 Tistory는 API를 제공하지 않지만, 대부분의 블로그 서비스는 블로그 API를 제공한다. 이런 API를 써서 꼭 블로그에 접속하지 않고도 블로그의 포스트 리스트를 가져온다거나, 블로그를 작성하거나 할 수 있다. (이를테면 MS Word 2007에서는 Blogger, MSN Space 등의 블로그에 Post할 수 있는 메뉴를 제공한다) 이런 API 중에서 대표적인 것이 Blogger ATOM APIRFC MetaWebLog API이다.

Blogger Atom API에 대한 문서는 다음을 참조하면 된다 ->
http://code.blogger.com/archives/atom-docs.html

다음 샘플은 Blogger Atom API를 써서 자신의 Blogger Blog 목록을 가져오는 C# 샘플이다. 설명은 코드의 주석으로...^^;;


//WebClient 클래스는 간단하게 인터넷 익스플로러라고 생각하면 된다.

//즉, 프로그램 내부에서 인터넷 페이지를 열거나 데이터를 post/get 하는 등의 일을 할 수 있는 객체이다.
//Blogger ATOM API는 XML-RPC를 사용하기 때문에 이 객체를 사용해서 데이터를 가져오거나 쓸 수 있다.
System.Net.WebClient oClient = new System.Net.WebClient();

//Content-type은 반드시 application-xml로 설정해야 한다.
oClient.Headers.Add("Content-type", "application/xml");

//ATOM API는 HTTP SSL 기본 인증을 사용한다.
//기본 인증 token은 아이디:비밀번호를 Base64로 인코딩한 값이 사용된다.
//아래 코드 중 Base64Encode라는 함수는 내 이전 글(
http://kkongchi.net/1602055)을 참조한다
oClient.Headers.Add("Authorization", "BASIC " + this.Base64Encode("YourID:YourPassword", System.Text.Encoding.UTF8));

//자신의 블로그 리스트를 읽어와서 TextBox에 넣는다.
string s = oClient.DownloadString("http://www.blogger.com/atom/");
this.textBox2.Text = s;



이 코드를 통해서 얻어진 결과는 다음과 같다..(내 ID/PW로 쿼리한 결과)

<feed xmlns="http://purl.org/atom/ns#">
<userid title="kkongchi's Blog" xmlns="https://www.blogger.com/atom/23327098" type="application/atom+xml" rel="service.feed">
<link title="kkongchi's Blog" href="http://kkongchi.blogspot.com" type="text/html" rel="alternate">
<link title="kkongchi's GOOGLE Blog" href="https://www.blogger.com/atom/28487731" type="application/atom+xml" rel="service.post">
<link title="kkongchi's GOOGLE Blog" href="https://www.blogger.com/atom/28487731" type="application/atom+xml" rel="service.feed">
<link title="kkongchi's GOOGLE Blog" href="http://kkongchigle.blogspot.com" type="text/html" rel="alternate">
</feed>
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
top

Trackback Address :: http://lazydeveloper.net/trackback/2567015 관련글 쓰기

  1. BlogIcon 황재선 2006/10/01 15:35 댓글주소 | 수정/삭제 | 댓글

    스플에 올리신 글을 보고 왔는데 이런 반가운일이 있네요. 동종업계에 종사하고, BloggerAPI까지 덤으로 얻어갑니다. 이번 DevDays2006행사에서 닷넷용 설치형 블로그를 오픈할 계획입니다. 소개해주신 내용까지도 포함해보고자 합니다. 현재에는 BloggerAPI, MetaWeblogAPI, MovableType API를 지원할 계획이고, Blogger ATOM API는 고려의 대상이었거든요. 좋은 정보 감사합니다.

    • BlogIcon kkongchi 2006/10/01 19:20 댓글주소 | 수정/삭제

      ㅎㅎㅎ

      이런 허접 글이 도움이 되셨다니 다행입니다..-_-;;

      암튼, 사실 Blogger API에 다른 기능들(글 목록 가져 오기, 글 올리기)등은 전혀 계획이 없었는데..^^;;;
      이렇게 좋은 평가해주시니 다시 또 해봐야겠군요...

      암튼 찾아주셔서 감사하고, 좋은 블로그 만드시길 바랍니다..

Write a comment


 

C# 1.X에서는 파라미터로 넘어온 문자열에 대해서 보통은 아래와 같은 방식으로 체크를 했었다.


if (str != null && str.Length != 0)

{

}


하지만, 이제 C# 2.0에서는 이렇게 길게 코딩할 필요가 없어졌다...!!!


if(!String.IsNullOrEmpty(str)

{

}


이렇게 간단하게 한 번의 메소드 호출로...해결할 있다.


그리고, 차라리 젤 위에 있는 예전 방식으로 하고, 아래 방식은 절대로 쓰지 말 것...

If(str != null && str != "")

{
}