C# & VB.NET2009.01.19 00:20

지난 번 Comb Sort를 소개했던 포스팅에서 말씀 드렸듯이, Bubble Sort, Comb Sort, 그리고 닷넷의 기본 소팅 알고리즘인 Quick Sort의 성능을 비교해보았습니다.

테스트 소스는 지난 번 소스에 Quick Sort를 호출하는 부분을 추가한 것 뿐입니다. 그리고 Quick Sort도 따로 구현한 것이 아니라 닷넷의 System.Array.Sort()를 호출하는 방식으로 했습니다.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SortingSample
{
   
class Program
   
{
       
static void Main(string[] args)
       
{
           
int dataCount = Convert.ToInt32 (args[0]);
           
string[] BubbleUnsorted = new string[dataCount];
           
string[] CombUnsorted = new string[dataCount];
           
string[] QuickUnsorted = new string[dataCount];
           
string[] BubbleSorted = new string[dataCount];
           
string[] CombSorted = new string[dataCount];
           
string[] QuickSorted = new string[dataCount];
           
Random RandObj = new Random();
           
for (int idx = 0; idx < dataCount; idx++)
           
{
               
BubbleUnsorted[idx] = RandObj.Next().ToString();
               
CombUnsorted[idx] = RandObj.Next().ToString();
               
QuickUnsorted[idx] = RandObj.Next().ToString();
           
}

           
BubbleSorted = BubbleSort(BubbleUnsorted);
           
CombSorted = CombSort(CombUnsorted);
           
QuickSorted = QuickSort(QuickUnsorted);
       
}

       
public static string[] QuickSort(string[] unsorted)
       
{
           
long begin = System.DateTime.Now.Ticks;
            
           
System.Array.Sort(unsorted);

           
long end = System.DateTime.Now.Ticks;
           
long duration = (end - begin)/10000;
           
Console.WriteLine("Quick Sort Data Count " + Convert.ToString(unsorted.Length) + " " + duration.ToString() + " milliseconds elapsed");

           
return unsorted;
       
}

       
public static string[] BubbleSort(string[] unsorted)
       
{            
           
bool swap;
           
long begin = System.DateTime.Now.Ticks;
           
do
           
{
               
swap = false;
               
for (int i = 1; i < unsorted.Length; i++)
               
{
                   
if (Convert.ToInt64(unsorted[i - 1]) > Convert.ToInt64(unsorted[i]))
                   
{
                       
string tmp = unsorted[i - 1];
                       
unsorted[i - 1] = unsorted[i];
                       
unsorted[i] = tmp;
                       
swap = true;
                   
}              
               
}
                
           
} while (swap);
           
long end = System.DateTime.Now.Ticks;
           
long duration = (end - begin)/10000;
           
Console.WriteLine("Bubble Sort Data Count " + Convert.ToString(unsorted.Length) + " " + duration.ToString() + " milliseconds elapsed");
           
return unsorted;
       
}

       
public static string[] CombSort(string[] unsorted)
       
{
           
int gap = unsorted.Length;
           
int swap;

           
long begin = System.DateTime.Now.Ticks;

           
do
           
{
               
if (gap > 1)
               
{
                   
gap = (gap * 10) / 13;
                   
if (gap == 9 || gap == 10)
                   
{
                       
gap = 11;
                   
}
               
}

               
swap = 0;

               
for (int i = 0; i + gap <= unsorted.Length-1; i++)
               
{
                   
if (Convert.ToInt64(unsorted[i]) > Convert.ToInt64(unsorted[i+gap]))
                   
{
                       
string tmp = unsorted[i];
                       
unsorted[i] = unsorted[i+gap];
                       
unsorted[i+gap] = tmp;
                       
swap = 1;
                   
}                  
               
}

           
} while (gap > 1 || swap == 1);

           
long end = System.DateTime.Now.Ticks;
           
long duration = (end - begin) / 10000;
           
Console.WriteLine("Comb Sort Data Count " + Convert.ToString(unsorted.Length) + " " + duration.ToString() + " milliseconds elapsed");
           
return unsorted;
       
}
   
}
}

Colorized by: CarlosAg.CodeColorizer

 

배열의 개수를 파라미터로 넘길 수 있도록 코딩 했습니다. 그래서 테스트는 10개, 100개, 1000개 이렇게 10배씩 늘려나가는 방식으로 진행했고, 3번 해서 그 평균을 구했습니다. 결과는 이렇습니다. (단위는 millisecond 즉, 100분의 1초입니다)

  Bubble Sort Comb Sort Quick Sort
10 5 0 2
100 11 1 2
1000 804 18 5
10000 83904 282 42

확실히 Bubble Sort는 매우 매우 느립니다. ^^;; 그리고 Comb Sort는 100개 이하에서는 오히려 Quick Sort보다도 빠른데, 1000개 정도부터는 Quick Sort의 상대가 되질 않네요.

그래서 따로 Comb Sort 와 Quick Sort 만을 따로 비교를 해보았습니다. 이 두 가지 Sorting은 100000개와 1000000개도 테스트할 수 있었습니다. (Bubble Sort로는 도저히 이 숫자는 할 수가 없더군요)

 

  Comb Sort Quick Sort
10 0 2
100 1 2
1000 18 5
10000 282 42
100000 3831 526
1000000 49382 6418

그래도 빠르다고 생각했던 Comb Sort도 100000개 이상부터는 Quick Sort와 비교가 불가능한 성능을 보여줍니다. 정말 Quick Sort가 짱 이네요 ^^

 

Quick Sort에 대해서 자세히 알고 싶은 분들은 WikipediaQuick Sort 항목을 참조하시길 바랍니다. 오른 편에 있는 그림이 정말 Quick Sort의 모든 것을 보여주네요.

그리고 Reflector로 당연히 닷넷의 소스도 확인할 수가 있습니다. 아래 그림과 소스처럼 말이죠. ^^

internal SorterObjectArray(object[] keys, object[] items, IComparer comparer)
{
   
if (comparer == null)
   
{
       
comparer = Comparer.Default;
   
}
   
this.keys = keys;
   
this.items = items;
   
this.comparer = comparer;
}

internal void SwapIfGreaterWithItems(int a, int b)
{
   
if (a != b)
   
{
       
try
       
{
           
if (this.comparer.Compare(this.keys[a], this.keys[b]) > 0)
           
{
               
object obj2 = this.keys[a];
               
this.keys[a] = this.keys[b];
               
this.keys[b] = obj2;
               
if (this.items != null)
               
{
                   
object obj3 = this.items[a];
                   
this.items[a] = this.items[b];
                   
this.items[b] = obj3;
               
}
           
}
       
}
       
catch (IndexOutOfRangeException)
       
{
           
throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", new object[] { this.keys[b], this.keys[b].GetType().Name, this.comparer }));
       
}
       
catch (Exception exception)
       
{
           
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), exception);
       
}
   
}
}

internal void QuickSort(int left, int right)
{
   
do
   
{
       
int low = left;
       
int hi = right;
       
int median = Array.GetMedian(low, hi);
       
this.SwapIfGreaterWithItems(low, median);
       
this.SwapIfGreaterWithItems(low, hi);
       
this.SwapIfGreaterWithItems(median, hi);
       
object y = this.keys[median];
       
do
       
{
           
try
           
{
               
while (this.comparer.Compare(this.keys[low], y) < 0)
               
{
                   
low++;
               
}
               
while (this.comparer.Compare(y, this.keys[hi]) < 0)
               
{
                   
hi--;
               
}
           
}
           
catch (IndexOutOfRangeException)
           
{
               
throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", new object[] { y, y.GetType().Name, this.comparer }));
           
}
           
catch (Exception exception)
           
{
               
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), exception);
           
}
           
catch
           
{
               
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"));
           
}
           
if (low > hi)
           
{
               
break;
           
}
           
if (low < hi)
           
{
               
object obj3 = this.keys[low];
               
this.keys[low] = this.keys[hi];
               
this.keys[hi] = obj3;
               
if (this.items != null)
               
{
                   
object obj4 = this.items[low];
                   
this.items[low] = this.items[hi];
                   
this.items[hi] = obj4;
               
}
           
}
           
low++;
           
hi--;
       
}
       
while (low <= hi);
       
if ((hi - left) <= (right - low))
       
{
           
if (left < hi)
           
{
               
this.QuickSort(left, hi);
           
}
           
left = low;
       
}
       
else
       
{
           
if (low < right)
           
{
               
this.QuickSort(low, right);
           
}
           
right = hi;
       
}
   
}
   
while (left < right);
}}

 

Posted by kkongchi
C# & VB.NET2008.12.26 22:22

 

* 아래 덧글에서 보실 수 있듯이, exedra님 지적 때문에 일부 소스와 비교 데이터가 수정되었습니다. (2008-01-14)

 

회사 솔루션 코드 중에 VB로 된 Comb Sort 코드가 있길래, C#으로 재 작성해보았습니다.

그러면서 가장 기본적인 Bubble Sort와 성능 차이가 얼마나 되나 비교도 해 봤습니다.

Comb Sort의 내용에 대해서는 Wikipedia의 Comb_sort 항목을 참조하시면 됩니다.

 

코드는 아래와 같습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SortingSample
{
   
class Program
   
{
       
static void Main(string[] args)
       
{
           
int dataCount = Convert.ToInt32 (args[0]);
           
string[] BubbleUnsorted = new string[dataCount];
           
string[] CombUnsorted = new string[dataCount];

           
string[] BubbleSorted = new string[dataCount];
           
string[] CombSorted = new string[dataCount];

           
Random RandObj = new Random();
           
for (int idx = 0; idx < dataCount; idx++)
           
{
               
BubbleUnsorted[idx] = RandObj.Next().ToString();
               
CombUnsorted[idx] = RandObj.Next().ToString();
           
}

           
BubbleSorted = BubbleSort(BubbleUnsorted);
           
CombSorted = CombSort(CombUnsorted);
       
}
        
       
public static string[] BubbleSort(string[] unsorted)
       
{            
           
bool swap;
           
long begin = System.DateTime.Now.Ticks;
           
do
           
{
               
swap = false;
               
for (int i = 1; i < unsorted.Length; i++)
               
{
                   
if (Convert.ToInt64(unsorted[i - 1]) > Convert.ToInt64(unsorted[i]))
                   
{
                       
string tmp = unsorted[i - 1];
                       
unsorted[i - 1] = unsorted[i];
                       
unsorted[i] = tmp;
                       
swap = true;
                   
}              
               
}
                
           
} while (swap);
           
long end = System.DateTime.Now.Ticks;
           
long duration = (end - begin)/10000;
           
Console.WriteLine("Bubble Sort Data Count " + Convert.ToString(unsorted.Length) + " " + duration.ToString() + " milliseconds elapsed");
           
return unsorted;
       
}
        
       
public static string[] CombSort(string[] unsorted)
       
{
           
int gap = unsorted.Length;
           
int swap;

           
long begin = System.DateTime.Now.Ticks;

           
do
           
{
               
if (gap > 1)
               
{
                    
                   
gap = (gap * 10) / 13;
                   
if (gap == 9 || gap == 10)
                   
{
                       
gap = 11;
                   
}
               
}

               
swap = 0;

               
for (int i = 0; i + gap <= unsorted.Length-1; i++)
               
{
                   
if (Convert.ToInt64(unsorted[i]) > Convert.ToInt64(unsorted[i+gap]))
                   
{
                       
string tmp = unsorted[i];
                       
unsorted[i] = unsorted[i+gap];
                       
unsorted[i+gap] = tmp;
                       
swap = 1;
                   
}                  
               
}

           
} while (gap > 1 || swap == 1);

           
long end = System.DateTime.Now.Ticks;
           
long duration = (end - begin) / 10000;
           
Console.WriteLine("Comb Sort Data Count " + Convert.ToString(unsorted.Length) + " " + duration.ToString() + " milliseconds elapsed");
           
return unsorted;
       
}
   
}
}

Colorized by: CarlosAg.CodeColorizer

 

1000건을 Sorting했을 때 결과는 이렇습니다.

BubblevsComb

차이가 매우 크다는 것을 보실 수 있습니다. Comb Sort가 꽤 빠른 Sorting 알고리즘이라는 것을 알 수가 있습니다. 다음 번에 기회가 나면, .NET의 기본 Sort 알고리즘인 Quick Sort와 한 번 비교해보도록 하겠습니다.

 

Tistory 태그: ,,,
Posted by kkongchi
C# & VB.NET2008.03.13 13:14

가끔 우리 솔루션에서는 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객체가 프로세스를 넘어가는 시나리오가 있다면, 이 문제를 조심해야 할 것이다.
Posted by kkongchi
C# & VB.NET2008.03.09 21:01
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");
   
}
}
Posted by kkongchi
C# & VB.NET2007.10.17 21:24

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

 

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

 

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

 

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

 

Dim str As String = """Lazy"" ""Developer"""
Posted by kkongchi
C# & VB.NET2007.02.26 11:48
어떤 메소드의 호출자 정보를 알고 싶을 때가 있다. 문제가 발생했는데 디버깅하기가 힘들 때, 이런 호출자 정보들을 로그 등에 기록해둔다면, 문제 해결에 유용하게 쓰일 수 있는 단서가 될 것이다.

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 등의 더 자세한 정보를 알 수 있는 메소드들도 있다.

Posted by kkongchi
C# & VB.NET2007.02.12 15:33

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

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

Posted by kkongchi
C# & VB.NET2006.09.30 18:32
아직 여기 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>
Posted by kkongchi
C# & VB.NET2006.09.09 00:00
 

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


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

{

}


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


if(!String.IsNullOrEmpty(str)

{

}


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


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

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

{
}

Posted by kkongchi
TAG C# 2.0
C# & VB.NET2006.07.15 01:19

LogonUser 함수는 Windows API의 일부이지만, .NET에서 Impersonation을 코드로 구현할 때 쓰이기도 한다.
How to implement impersonation in an ASP.NET application(http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158) 문서를 보면 그 자세한 방법을 알 수 있다.


그런데 이 함수의 스펙을 보면, LogonType이라는 파라미터가 있는 것을 알 수 있다. 이 파라미터는 로그온 유형을 정의하는데, 일반적으로 .NET에서 Impersonation 용도로 사용할 때에는 Interactive 모드를 사용하게 된다. 하지만 실제로는 이 것 말고도 몇 가지 유형이 더 있다. 다음은 이 파라미터에서 선택할 수 있는 모든 유형에 대한 설명이다. (MSDN 영문 문서를 번역한 것으로, 오역이 있다면 알려주시길 부탁드린다)


LOGON32_LOGON_BATCH - 이 유형은 사용자를 대신해서 프로세스를 처리하는 배치 서버를 위해서 만들어졌다. 또 이 유형은 많은 plaintext 인증시도를 하는 고성능 서버가 사용하기 위해서 만들어 진 것으로, 메일 서버나 웹 서버가 바로 그 예이다. LogonUser 함수는 이 경우에 사용자의 Credential을 캐싱하지 않는다.


LOGON32_LOGON_INTERACTIVE - 이 유형은 컴퓨터를 이용해서 상호작용하는 - 예를 들면 터미널 서버, 원격 셸, 혹은 유사한 프로세스 - 사용자를 위해서 만들어진 것이다. 이 유형은 접속이 끊어졌을 때의 오퍼레이션을 위해서 로그온 정보를 캐싱하기 때문에 부가적인 비용이 소요된다. 그렇기 때문에, 메일 서버와 같은 클라이언트/서버 애플리케이션에는 부적당하다.


LOGON32_LOGON_NETWORK - 이 유형은 plaintext 패스워드로 인증하는 고성능 서버를 위해서 만들어졌다. LogonUser 함수는 이 경우에 Credential을 캐시하지 않는다.


LOGON32_LOGON_NETWORK_CLEARTEXT - 이 유형은 Impersonating하는 동안 다른 서버로 또 연결할 수 있도록, 인증 패키지에 이름과 패스워드를 저장한다. 서버는 클라이언트로부터 plaintext credential을 받을 수 있고, LogonUser 함수를 호출해서, 네트워크에 있는 다른 서버로 접속할 수 있는지 확인하고, 다른 서버와 계속 통신할 수 있다. (NT에서는 지원하지 않는다)


LOGON32_LOGON_NEW_CREDENTIALS - 이 유형은 호출자가 현재의 토큰을 복제해서 외부로 나가는 연결에 대해서 새로운 credential을 지정하게 해준다. 새로운 로그온 세션은 같은 로컬 식별자를 가지지만, 외부 연결에서는 다른 Credential을 가지게 된다. 이 유형은 LOGON32_PROVIDER_WINNT50 프로바이더를 지정했을 때만 지원된다. (NT에서는 지원하지 않는다)


LOGON32_LOGON_SERVICE - 서비스 타입 로그온을 가리킨다. 계정은 반드시 서비스 권한이 활성화되어 있어야 한다.


LOGON32_LOGON_UNLOCK - 이 유형은 GINA(Graphical Identification and Authentication) DLL - Window인증창을 생각하면 된다 - 이 사용한다. 이 유형의 로그인은 워크스테이션이 잠금해제되었다는 유니크한 감사 레코드를 생성한다.

Posted by kkongchi

티스토리 툴바