잊지 않겠습니다.

indows에서 System의 모든 Monitoring은 WMI를 통해서 가능하다.
WMI를 이용하는 경우, Remote에서 접근이 용의하다는 장점과 Server군의 경우 다양한 속성들을 모두 Monitoring할 수 있다는 큰 장점을 가지고 있다. 또한, 기본적인 WMI의 Query를 통해서 값을 얻는 것이 아닌, .NET에서는 WMI에 대한 Event Handling이 가능하다. 

지정될 수 있는 Event는 http://msdn.microsoft.com/en-us/library/aa394583(VS.85).aspx을 참조.

모니터링 소스는 다음과 같다. 

ConnectionOptions connectionOptions = new ConnectionOptions()
     {
            Authentication = AuthenticationLevel.Default,
            Username = @"UserName",
            Password = @"Password",
            EnablePrivileges = true,
            Impersonation = ImpersonationLevel.Impersonate
      };
            
ManagementScope scope = new ManagementScope(@"\\hyperv\root\cimv2", connectionOptions);
scope.Connect();

//__InstanceCreationEvent : Wmi instance create event
//__InstanceModificationEvent : Wmi instance value modified event
//__InstanceDeletionEvent : Wmi instance delete event
//__InstanceOperationEvent : Wmi instance method call event

WqlEventQuery wQuery = new WqlEventQuery("Select * From __InstanceModificationEvent Within 1 " + "Where TargetInstance ISA 'Win32_PerfFormattedData_Tcpip_NetworkInterface'");

ManagementEventWatcher watcher = new ManagementEventWatcher(scope, wQuery);
watcher.EventArrived += new EventArrivedEventHandler(DisplayWatcherEvent);
watcher.Start();

Console.ReadLine();
            
watcher.Stop();

일반적인 Monitoring Handling과 동일하다. 특징이 나타나는 곳은 오히려 Event 처리기쪽이 더 특징이 나타난다.

private static void DisplayWatcherEvent(object sender, EventArrivedEventArgs e)
{
    foreach(var property in e.NewEvent.Properties)
    {
        if(property.Name == "TargetInstance")
        {
            ManagementBaseObject managementObject = property.Value as ManagementBaseObject;
            if (managementObject == null)
            {
                Console.WriteLine("Data convert is null");
            }
            else
            {
                var bytesPerSec = managementObject.Properties["BytesTotalPersec"].Value;
                var bytesReceivedPersec = managementObject.Properties["BytesReceivedPersec"].Value;
                var bytesSentPersec = managementObject.Properties["BytesSentPersec"].Value;
                string name = managementObject.Properties["Name"].Value.ToString();

                Console.WriteLine("{0}\t{1}\t{2}\t{3}", 
                    name.Substring(0, 4), bytesPerSec, bytesReceivedPersec, bytesSentPersec);
            }
        }
    }
}
특징으로 보이는 것이 EventArrivedEventArgs에서 Property의 Value형태로 WMI Instance의 값이 전달된다는 점이다. 그리고, Performance Counter의 경우에는 이전값, 현재값이 Property의 Name으로 전달되기 때문에 Diff. Monitoring에도 용의하다. 


Posted by Y2K
,

MS SQL Query Script

.NET Framework 2009. 7. 13. 15:37

[System.Reflection.Assembly]::LoadWithPartialName("System")
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Reflection.Assembly]::LoadWithPartialName("System.Data")

$fileContexts = [System.IO.File]::ReadAllLines("c:\mailStore.txt")
$connection = New-Object System.Data.SqlClient.SqlConnection("==THIS IS CONNECTION STRING==");

foreach($fileContext in $fileContexts) {
    $samAccount = $fileContext.Replace("name: ", "").Replace("@mailpush.co.kr", "")
       
    $connection.Open()
    $command = New-Object System.Data.SqlClient.SqlCommand;
    $command.Connection = $connection
    $command.CommandText = "SELECT PhoneNumber, Email From Product WHERE LogonName = '" + $samAccount + "'" + " and ProductStateId = 1"
    $reader = $command.ExecuteReader()

    while($reader.Read())
    {
        $reader.GetSqlString(0).ToString() + "`t" + $reader.GetSqlString(1).ToString() >> c:\output1.txt
    }
    $reader.Close()
    $connection.Close()   
}
[System.Windows.Forms.MessageBox]::Show("Complete!")
notepad.exe "c:\output1.txt"


재미있는 것은 .NET쪽 코드랑 별 다를 것이 없는 코드를 내가 작성하고 있다는 것이다. -_-


Posted by Y2K
,
RSS Feed Script
([xml](new-object System.Net.WebClient).DownloadString("http://blogs.msdn.com/powershell/rss.aspx")).rss.channel.item | format-table title,link


FAST Windows Form
[void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
$form = new-object Windows.Forms.Form
$form.Text = "My First Form"
$button = new-object Windows.Forms.Button $button.text="Push Me!"
$button.Dock="fill"
$button.add_click({$form.close()})
$form.controls.add($button)
$form.Add_Shown({$form.Activate()})
$form.ShowDialog()

:여기서 중요한 코드는 첫줄. Assembly의 동적 Loading이 저렇게 쉽게 가능하다는 것이 가장 멋진 일이다.

ERROR LOG FINDER
dir $env:windir\*.log | select-string -list error | format-table path,linenumber –autosize
Posted by Y2K
,

Singletone Pattern

.NET Framework 2009. 3. 31. 03:04
예전에 Design Pattern에서 언급되던 Singletone pattern에서 다른 언어들과 .NET에서 구현상의 큰 차이점이 발견되어서 적어두기. 

1. 다른 언어들.
    public sealed class SingletonOld
    {
        private static Object lockObj = new Object();
        private static SingletonOld singleObject;

        private SingletonOld()
        {
        }

        public static SingletonOld Value
        {
            get 
            {
                if(singleObject == null)
                {
                    lock(lockObj)
                    {
                        singleObject = new SingletonOld();
                    }
                }
                return singleObject;
            }
        }
    }


2. .NET
    public sealed class SIngletonNew
    {
        private SIngletonNew()
        {

        }
        private static SIngletonNew singleObject = new SIngletonNew();

        public static SIngletonNew Value
        {
            get { return singleObject; }
        }
    }

가장 큰 차이는 변수의 선언과 동시에 값의 할당. CLR에서는 변수의 선언과 동시에 값을 할당시켜주는 경우에 생성자의 inline code로 만들어서 넣어주기 때문에 가장 빠르고 static의 경우에는 Single Thread의 접근을 완벽하게 보장해준다. 그러나 예전의 방법대로 구현하게 되면 Thread의 동기화 lock에 의해서 효율성을 떨어뜨리는 구현이 된다. (불행하게도 Design Pattern 책에는 대부분 첫번째 방법으로 되어있다.;; 두번째 방법 비슷하게 private 의 생성자 구현을 만들어두고 이렇게 만들면 안되고 첫번째 방법으로 Thread의 lock을 유지시켜야지 된다는 친절한 설명이 있는 책도 있다.;; )




Posted by Y2K
,
1. FCL과 C# 기본 형식 value type에서 FCL을 사용 
ex : 
 C# 기본 형식 > byte , FCL > System.Byte
-> 조금은 생뚱맞아보이는 방법이긴 하지만, 각 언어들에서 정확한 데이터 형식에 mapping 되는 것을 도와줄 수 있다. 특히 int 값에 대해서 Int32, Int64, Int16 과 같이 다양한 데이터 크기가 있을때, 이에 대한 형식 mapping에서 에러가 발생할 수 있다.
unmanaged code를 사용하는 경우, 이와 같은 일들은 빈번하게 발생 될 수 있기 때문에, 전 code를 FCL로 사용하는 것이 좋다. 

-> 참조 형식과 값 형식에 대해서 명확한 구분이 가능하다. string과 String의 경우에 같은 형식이지만 visual studio에서 색상 설정에 따라서 다르게 보인다. 이는 reference type과 value type을 명확히 구분이 가능하도록 visual studio에서 설정되어있기 때문이다. 그렇지만, C# 기본 형식으로 표기를 할 경우에는 value type인 int와 reference type인 string의 표기가 같게 된다. 

2. Value type과 reference type의 사용에 있어 주의 
-> 기본으로 돌아가서, value type은 stack, reference type은 heap에 생성된다. data의 memory 위치에 따라서 GC의 동작 및 GC 수집의 횟수에 영향을 미치게 된다. 

3. \r\n 을 사용하는 것보다는 Environment.NewLine을 사용하라. 
-> Mono를 비롯하여 CLR의 다른 OS로의 포팅이 계속해서 지원되고 있다. 
: 언제나 다 되려나... 싶긴 하다만.;


FCL 부분의 경우에는 많은 논란이 있을 것 같은 부분이다. 일반적으로 사람들이 사용하는 코드와는 많은 차이를 줄 수 있으니까. 그렇지만, 직접 사용해본 결과로는 보다 더 코드를 알아보기에 편한 느낌이 든다. 무엇보다 Value type과 Reference type간의 눈으로 보이는 차이는, 형식의 선언에서 한번 더 생각해보는 계기를 가지고 오는 것 같다. 
Posted by Y2K
,

CLR via C#

.NET Framework 2009. 3. 24. 01:10
.NET을 사용해서 개발한지 4년정도가 되어가는 때에 딱 적당하게 찾아서 보고 있는 책이라는 느낌이 든다. 
이 책은 기본적으로 .NET을 사용하고 있는 개발자를 대상으로 하고 있는 책으로 대부분의 책에서 나오는 Hello World와 같은 실행되는 코드는 전혀 나오지를 않는다. 

한 언어 또는 Framework를 다루는 책중에서 이정도까지 코드가 나오지 않는 책이 있었는지.. 라는 생각이 무척 많이 들게 하는 책으로 .NET Framework의 밑바닥에서 어떤 일들이 일어나는지.. method로 정의가 될때와 property로 정의될때 JIT의 compile이 어떤 식으로 구현이 되는지와 event의 등록 및 해재가 일어날때, CLR에서 어떻게 처리가 되고 있는지에 대한 그 전에는 단지 '사용하고 있었던' 코드에 대한 밑바닥 지식을 제공한다. 

method를 만들고, property를 만들때 각각 어떤 상황에서 어떤 방법을 사용하면 좋을지에 대한 고민을 한번 심각하게 하게 만들고, 내가 가진 coding 습관중에서 몇가지를 바꿔야지 될 것들이 보인다. 조금은 특이할지 모르겠지만 이 책에서 이야기 하는 논리에 상당히 설득을 당한 상태이기도 하고. 약간... 아니 많은 코딩 습관에 대해서 다시 한번 질문을 던져주는 책이 되는 것 같다. 

그리고, 가장 중요한 것. value와 reference에 대한 고민을 한번 더 나한테 던지고 있다. 어떤 상황에서 어떤 type을 사용하는 것이 가장 좋은가. 라는 고민이 계속해서 생기게 된다. 과연 내가 개발을 할 때, 적정한 상황에서 적정한 type을 이용하고 있는 것일까? 라는 고민과 좀더 나은 방법으로 개발할 수 있는 방법은 무엇일까? 라는 고민들이 계속해서 내 머리속을 스쳐지나가고 있다. 

어떻게 하면 좋은 프로그램을 만들수 있을까? 라는 끝없는 고민을 던져 주면서, .NET Framework의 개발 이론에서 이런 부분이 있어서 이렇게 되었구나.. 하는 깨달음을 주는 책. 정독으로 읽어도 읽어도 계속해서 놓친 점이 나오고 있다. 

지금까지 읽었던 .NET 책중에서 최고라고 칠 수 있고, 내가 다른 사람들에게 추천을 한다면 .NET Gotcha를 읽어본 사람이 읽어볼 책으로 추천하고 싶다. 이 책은 물고기 잡는 법을 가르쳐주지를 않는다. 이 책은 물고기에 대해서 가르쳐주는 책이다. 
Posted by Y2K
,
CLR via C# 책에서 일반적인 통념을 부정하는 견해가 있어서 여기에서 간단히 소개. 

1. 컴파일 시에 JIT 컴파일러는 실행환경의 CPU type을 알 수 있기 때문에, 최적화된 지시어를 이용해서 Native code를 생성함으로써 성능의 향상이 가능

2. JIT 컴파일러는 특정 상황의 테스트값 혹은 논리 연산의 결과를 실행 전에 알아내서 좀 더 빠른 Native code의 생성이 가능하다. 

3. CLR은 appliaction의 실행 패턴을 Profile함으로써, 실행중인 IL code를 native code로 다시 컴파일 할 수 있다.

이상의 이유로.. managed code가 unmanaged code보다 성능이 우수하다.


  약간은 생뚱맞기도 하고, 절대로 공감할 수 없다는 사람들이 엄청나게 덤벼들 것이 뻔한 상황이지만.. 개인적으로 전에 C++로 작업하던 환경과 지금 C#으로 작업하는 환경에서 겪어본 상황을 생각하면 은근히 이 말이 맞다는 생각이 든다. 일단... 첫 실행 시간. JIT에 의해서 native code가 생성되는 그때는 절대적으로 unmanaged code가 성능이 더 우수하다. 그렇지만, JIT에 의해서 native code가 생성된 이후라면.. 이미 사용된 assembly의 내용을 재이용하는 상황에서는.. 속도가 비슷하거나, 내가 짠 C++코드보다 빨랐었던 경험이 분명히 있었다. -_-;; 
(내 코드가 문제였을거야.. 라는 생각도 하지만.;)

  .NET으로 만든 코드에 대한 자신감을 좀 더 갖고 이야기를 해도 괜찮을 것 같다. 잘 생각해보면.. 그렇게 성능이 중요하면 assembly로 짜라. 라는 말이 가장 막강하긴 하지만. ^^
Posted by Y2K
,
  ASP .NET에서의 Session의 생명주기는 In-of-Process 단위로 움직이게 된다. 그런데, 이 Session의 처리주기가 In-of-Process 단위로 움직이는 경우에 IIS 6에서 사용되는 process recycling에 의해서 session이 끊기게 된다. Session을 이용한 상태의 저장시에 치명적인 오류를 가지게 되는데. 이러한 에러상황을 피하기 위해서는 다음과 같은 방법들이 사용 가능하다. 


1. IIS의 process recycling을 중지 시킨다.

1) 인터넷 정보 서비스 관리자를 띄운다 
2) 응용 프로그램 풀을 선택하고 새로만들기-응용프로그램 풀을 선택하여 새로운 응용 프로그램 풀을 만들어 준다. 
3) 새 응용프로그램의 등록정보를 열고 재생 탭의 항목을 모두 언체크 한다. 
4) 성능 탭의 웹 가든을 1로 맞춰준다 
5) 인터넷 정보 서비스 관리자에서 세션오류가 난 사이트의 등록정보를 연다 
6) 홈 디렉터리 탭의 응용 프로그램 설정 부분에 있는 응용 프로그램 풀을 2번 과정에서 만든 풀을 선택해준다. 

이 과정을 거치면 IIS 6에서도 세션 사용이 가능하다. 하지만 IIS 6의 강점인 자동 리사이클링이 동작하지 않게 세팅하는 것이므로 적용을 최소화 할 수 있도록 한다. 


2. Session 관리 방법을 변경한다. 

ASP.NET에서는 다양한 Session의 관리 방법을 제공한다. 기본적으로 제공되는 In-of-Process 단위의 Session 뿐 아니라, Out-of-Process 단위의 Session 역시 제공한다. Out-of-Process 단위의 Session의 사용은 ASP .NET State Service를 사용하는 방법과 MS-SQL을 이용한 Session의 저장 방법이 있다. 

1) ASP .NET Session State Service 
a. Windows Service에서 ASP .NET Session State Service를 활성화시킨다. (기본적으로 사용하지 않음으로 stop 되어있는 서비스이다.) 

b. web.config에 다음과 같은 항목을 추가한다. 
<sessionState mode="StateServer" stateConnectionString="tcpip=localhost:42424">
</sessionState>

* 주의할점은 dual core process의 경우에는 session과 working process간에 dead-lock이 일어날 수 있다. 이 경우에는 webgarden 속성이 반드시 false여야지 된다. 이에 대한 자세한 내용은 이곳에서..

2) MS-SQL을 이용한 Session 저장
DB를 이용한 Session의 저장 역시 가능하다. DB를 이용하게 되면 일단 속도는 떨어질 수 있지만, 다른 어떤 방법보다 안전한 Session의 이용이 가능하게 된다. (SQL Agent를 이용하기 때문에 SQL Express 버젼에서는 사용이 애매해진다. 시간이 오래된 Session의 자동정리 등 기능을 많이 사용할 수 없게 된다.)

a. command를 이용해서 ASP .NET Session Database 작성
aspnet_regsql.exe -S <machine> -E -ssadd -sstype p

b. web.config에 다음과 같은 항목을 추가한다.
<sessionState mode="SQLServer" sqlConnectionString="server=localhost; uid=*******; pwd=********* ">
</sessionState>

* 주의할 점은 반드시 Serialize 되는 항목만 Session에 저장 가능하다. 


Posted by Y2K
,
먼저, AppDomain을 이용한 개발을 하는 가장 큰 장점은 Process보다 더 가벼운 단위로의 동작이 가능하고, Programming 적으로 동작이 가능하다는 장점을 가지고 있다. 그렇지만, 이러한 동작 및 Resource의 제어를 하기 위해서 모든 AppDomain를 제어하고, Process당 하나만 존재하는 진정한 Singleton object가 필요하게 된다.

이 Singleton object를 만들기 위한 컨셉은 다음과 같다.

Singleton object가 동작할 working AppDomain의 지정


using System;
using System.Runtime.InteropServices;

namespace ProxyServerForMsn.AppDomainManager
{
    public class CrossAppDomainSingleton<T> : MarshalByRefObject where T : new()
    {
        private const string AppDomainName = "Singleton AppDomain";
        // Singleton Working AppDomain 지정
        private static T instance;

        public static void ListupAppDomains()
        {
            IntPtr enumHandle = IntPtr.Zero;
            mscoree.CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
            try
            {
                host.EnumDomains(out enumHandle);

                object domain = null;
                while(true)
                {
                    host.NextDomain(enumHandle, out domain);
                    if(domain == null)
                    {
                        break;
                    }
                    AppDomain appDomain = domain as AppDomain;
                    if(appDomain != null)
                    {
                        Console.WriteLine(appDomain.FriendlyName);   
                    }
                }
            }
            finally
            {
                host.CloseEnum(enumHandle);
                Marshal.ReleaseComObject(host);
                host = null;
            }
        }

        private static AppDomain GetAppDomain(string friendlyName)
        {
            IntPtr enumHandle = IntPtr.Zero;
            mscoree.CorRuntimeHostClass host = new mscoree.CorRuntimeHostClass();
            try
            {
                host.EnumDomains(out enumHandle);

                object domain = null;
                while(true)
                {
                    host.NextDomain(enumHandle, out domain);
                    if(domain == null)
                    {
                        break;
                    }
                    AppDomain appDomain = (AppDomain)domain;
                    if(appDomain.FriendlyName.Equals(friendlyName))
                    {
                        return appDomain;
                    }
                }
            }
            finally
            {
                host.CloseEnum(enumHandle);
                Marshal.ReleaseComObject(host);
                host = null;
            }
            return null;
        }

        public static T Instance
        {
            get
            {
                if (null == instance)
                {
                    AppDomain appDomain = GetAppDomain(AppDomainName);
                    if (null == appDomain)
                    {
                        appDomain = AppDomain.CreateDomain(AppDomainName);
                    }
                    Type type = typeof (T);
                    T createInstance = (T) appDomain.GetData(type.FullName);
                    if (null == createInstance)
                    {
                        createInstance =
                            (T) appDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
                        appDomain.SetData(type.FullName, createInstance);
                    }
                    instance = createInstance;
                }
                return instance;
            }
        }
    }
}


Generic으로 만들어져있기 때문에, 사용될 constraint class의 경우에도 MarsharByObject class를 상속받거나 Serializable 속성을 가져야지 된다.

사용은 다음과 같다.

[Serializable]
public class CrossAppHello
{
public void ConsoleOut()
{
Console.WriteLine("Hello World");
}
}

class Program
{
public static void Main()
{
CrossAppDomainSingleton<CrossAppHello>.Instance.ConsoleOut();
}
}

Posted by Y2K
,
.NET에서의 Application의 구조는 Process->Application Domain->Thread->Context 로 구성이 된다.

일반적으로 개발되는 console app들은 한개의 Process를 가지고, 이는 실행 파일의 이름과 동일한 Default AppDomain을 가지게 된다. 거의 대부분의 프로그램들이 1개의 AppDomain으로 동작하게 되어서, 일반적으로 사용할때는 Process = AppDomain의 형태로 프로그램의 제작이 가능하다.

그렇지만, 1개의 Process에서 여러개의 AppDomain을 가지게 되는 프로그램들이 꼭 필요하게 되는데. 대표적인 프로그램이 IIS라고 할 수 있다. IIS의 동작은 iis_work에 대한 한개의 Process에서 각 Http Application의 접속 Connection에 따라서, 각각 AppDomain을 작성하게 되는데. Application Domain으로 동작하게 되면, 다음과 같은 장점이 있다.

1. Process 단위로 동작하는 것으로 가정하고 프로그래밍이 가능하다.
2. Process로 동작되는 것보다 시스템 리소스 소모가 작다.
3. 관리된 이름으로의 접근이 가능하다.

string appDomainName = string.Format("Server[{0:HH:mm:ss}_{1}]", DateTime.Now, DateTime.Now.Millisecond);
AppDomain appDomain = AppDomain.CreateDomain(appDomainName);
- AppDomain 생성

Console.WriteLine("Start AppDomain : {0}", appDomainName);
ProxySocketHandler proxySocketHandler = (ProxySocketHandler)appDomain.CreateInstanceAndUnwrap(
                                                                 Assembly.GetExecutingAssembly().FullName,
                                                                 "ProxyServerForMsn.SocketHandler.ProxySocketHandler");
- 생성된 AppDomain에서 Instace 생성

AppDomain 단위로 개발을 하게 되면 가장 큰 장점이라고 할 수 있는 것이.. 결국은 리소스의 관리에서 좀 더 원활한 개발을 할 수 있게 된다는 점이다. 그렇지만, AppDomain단위로 개발하는 것이 언제나 좋은 것은 아니다. 개발에서 귀찮은 점이 두가지가 생기게 된다. 하나는 static instance에 대한 사항이고, 나머지 하나는 thread safe에 대한 고려사항이다.

먼저, static instance는 모든 Process당 한개의 고정된 Instance를 보장하지 않는다. 정확히 .NET에서 static intance는 Process 당이 아닌 모든 AppDomain에 해당되는 single instance를 의미한다. 우리가 일반적으로 사용하는 application에서 이와 같은 점이 고려되지 않는 이유는 거의 대부분의 application들이 하나의 AppDomain만을 가지고 있기 때문이다. 이 점이 IIS에서 아무리 class들을 static으로 만들어도, 모든 web page나 connection에서 static instance 또는 method로 사용할 수 없는 이유가 된다.

그리고, thread safe에 대한 고려사항이다. 결론적으로 이야기 한다면, 일반적으로 thread safe를 보장하기 위해서 사용되는 lock 키워드나, ManualResetEvent, AutoResetEvent를 모두 사용하지 못한다. 이러한 방법들은 모두 한개의 AppDomain에서 동작하는 Thread들에서 서로간의 간섭을 알 수 있지, 다른 AppDomain에서의 간섭을 전혀 알지 못한다. Thread에 대한 friendly name은 내부적으로 AppDomainName과 ThreadName의 조합으로 만들어지기 때문에 이와 같은 사항을 전혀 고려할 수 없게 된다.


Posted by Y2K
,