검색결과 리스트
2007/12 에 해당되는 글 6건
- 2007.12.25 C#소스의 문서화 (3)
- 2007.12.23 [가이드]System.Transaction의 활용 (1)
- 2007.12.21 DNC Framework 작업 시작했습니다. (2)
- 2007.12.19 [문서]닷넷표준화 가이드
- 2007.12.14 모든 것은 마음먹기다. (4)
- 2007.12.06 기득권 세력에게 보내는 거위의 꿈.. (6)
C# 소스를 문서화 하기 위한 툴은 여러개 있는 것 처럼 보이지만 막상 사용하려고 하면
생각만큼 선택의 여지는 넓지 않습니다.
닷넷채널 프레임웍의 도움말을 만들기 위해서 소스상의 주석을 가지고 문서화를 할 수 있는
방법들을 찾아 보았습니다.
우선 대부분의 문서툴에서는 Visual Studio에서 지원하고 있는 xml 포멧을 사용합니다.
Visual Studio에서는 주석문으로 잘 달아놓은 것들을 XML포멧으로 출력하는 기능을 가지고 있습니다.
<그림1> 솔류션 탐색기에서 속성을 선택
<그림3>출력된 XML파일
<그림1~3>을 참조하면 Visual Studio 에서 주석문을 정리한 XML파일을 얻을 수 있습니다.
이 XML 파일을 가지고 대부분 문서를 생성할 수 있게 지원하는데
이전까지는 대표적으로 많이 사용했던 것이 바로 NDoc 입니다.
하지만 NDoc은 그 뛰어난 기능에 비해서 오픈소스 프로젝트의 한계인 참여율 저조를
극복하지 못하고 개발이 중단되었습니다. 그래서 닷넷프레임웍 2.0을 지원하지 못합니다.
그래서 두번째로 선택할 수 있는 것이 바로 Doxygen이라는 프로그램입니다.
이 프로그램은 사용하기가 생각보다 까다롭고 불편해서 일단은 사용 불가로 생각했습니다.
결국 제가 선택한 툴은 Sandcastle입니다.
강력하면서도 적절한 툴이며 프레임웍도 2.0을 잘 지원하고 있습니다.
Sandcastle는 UI가 없습니다. 그냥 명령어 기반의 프로그램입니다. 때문에 좀더 원활하게
사용하기 위해서는 Sandcastle Help File Builder가 함께 필요합니다.
사용하는 방법은 아주 쉽기 때문에 일단 패스 합니다. ^^
1차 설계때 포함시켰던 Enterprise Library를 배제하기로 결정했습니다.
Enterprise Library는 일단 그 자체만으로도 상당히 버겁고 또 사용하지 않는 다수의 Class도
함께 가지고 가야 한다는 점 그리고 프레임웍 버전업때의 자유도 등을 고려해서
이번 작업에는 적절하지 않다는 판단을 하게 되었습니다.
그리고 기본적으로 System.EnterpriseService를 사용하는 것을 표준으로 채택하려고 했으나
닷넷 프레임웍 2.0에 새로 추가된 System.Transaction을 활용하는 것도 표준으로 함께 권장한다.
System.Transaction을 우선적으로 사용하고 필요한 곳에는 System.EnterpriseService를
함께 사용할 수 있도록 했습니다.
자료들을 찾아보면 대체적으로 System.Transaction이 좀더 가볍고 유연한 방법이라고 되어 있는
것 같습니다. 아무래도 새버전에 맞쳐서 나온것 이라서 그런것인지 모르겠습니다만
아무튼 우리도 System.Transactions을 우선적으로 사용하는 것으로 결정했습니다.
또 System.Transactions의 경우 SQL Server, ADO.NET, MSMQ, MSDTC를 모두 지원하는
유연함과 강력함을 가지고 있습니다.
System.Transactions의 경우 암시적으로 특정범위안의 모든 Database Handling을 하나의
Transaction으로 묶어서 처리할 수 있는데 <리스트1>소스에서 사용법을 볼 수 있습니다.
// This function takes arguments for 2 connection strings and commands to create a transaction // involving two SQL Servers. It returns a value > 0 if the transaction is committed, 0 if the // transaction is rolled back. To test this code, you can connect to two different databases // on the same server by altering the connection string, or to another RDBMS such as Oracle // by altering the code in the connection2 code block. static public int CreateTransactionScope( string connectString1, string connectString2, string commandText1, string commandText2) { // Initialize the return value to zero and create a StringWriter to display results. int returnValue = 0; System.IO.StringWriter writer = new System.IO.StringWriter(); // Create the TransactionScope to execute the commands, guaranteeing // that both commands can commit or roll back as a single unit of work. using (TransactionScope scope = new TransactionScope()) { using (SqlConnection connection1 = new SqlConnection(connectString1)) { try { // Opening the connection automatically enlists it in the // TransactionScope as a lightweight transaction. connection1.Open(); // Create the SqlCommand object and execute the first command. SqlCommand command1 = new SqlCommand(commandText1, connection1); returnValue = command1.ExecuteNonQuery(); writer.WriteLine("Rows to be affected by command1: {0}", returnValue); // If you get here, this means that command1 succeeded. By nesting // the using block for connection2 inside that of connection1, you // conserve server and network resources as connection2 is opened // only when there is a chance that the transaction can commit. using (SqlConnection connection2 = new SqlConnection(connectString2)) try { // The transaction is escalated to a full distributed // transaction when connection2 is opened. connection2.Open(); // Execute the second command in the second database. returnValue = 0; SqlCommand command2 = new SqlCommand(commandText2, connection2); returnValue = command2.ExecuteNonQuery(); writer.WriteLine("Rows to be affected by command2: {0}", returnValue); } catch (Exception ex) { // Display information that command2 failed. writer.WriteLine("returnValue for command2: {0}", returnValue); writer.WriteLine("Exception Message2: {0}", ex.Message); } } catch (Exception ex) { // Display information that command1 failed. writer.WriteLine("returnValue for command1: {0}", returnValue); writer.WriteLine("Exception Message1: {0}", ex.Message); } } // The Complete method commits the transaction. If an exception has been thrown, // Complete is not called and the transaction is rolled back. scope.Complete(); } // The returnValue is greater than 0 if the transaction committed. if (returnValue > 0) { writer.WriteLine("Transaction was committed."); } else { // You could write additional business logic here, for example, you can notify the caller // by throwing a TransactionAbortedException, or logging the failure. writer.WriteLine("Transaction rolled back."); } // Display messages. Console.WriteLine(writer.ToString()); return returnValue; } <리스트1> 트랜젹션 범위를 사용하여 암시적 트랜잭션을 구현하는 예
새로운 TransactionScope 객체를 만들면 Transaction Scope가 시작됩니다. 위에서 볼 수 있는데로
using문장을 이용해서 사용범위를 한정해 주는게 좋습니다.
Transaction을 확정하기 위해서는 TransactionSope객체의 Complete()호출해야 합니다.
Complete()을 호출하지 않으면 Transaction이 완료되지 않고 Rollback되어 버립니다.
using문장을 이용해서 TransactionScope를 설정할 경우에 어떤 예외가 발생하면
TranscationScope의 Dispose()가 호출됩니다. TransactionScope의 경우 Dispose()가 호출되면
Transaction의 끝으로 간주해서 해당 Tracation의 상태에 따라서 확정이나 취소를 선택하게 됩니다.
void RootMethod() { using(TransactionScope scope = new TransactionScope()) { /* Perform transactional work here */ SomeMethod(); scope.Complete(); } } void SomeMethod() { using(TransactionScope scope = new TransactionScope()) { /* Perform transactional work here */ scope.Complete(); } }<리스트2> 트랜젝션이 중첩
<리스트2>에서 처럼 Transcation을 중첩할 수도 있습니다.
이렇게 중첩했을 경우에는 모든 Transcation이 확정되지 않으면 일괄 취소됩니다.
TrancationOption을 사용했을 경우에는 옵션에 따라서 세가지로 동작이 달라집니다.
Required를 사용하여 범위를 인스턴스화하고 앰비언트 트랜잭션이 있으면 범위는 이 트랜잭션에 참여합니다.
그러나 앰비언트 트랜잭션이 없으면 범위는 새 트랜잭션을 만들고 루트 범위가 됩니다.
이 값은 기본값입니다. Required를 사용하면 범위 내부의 코드는 루트 범위이거나 아니면 단순히 앰비언트 트랜잭션에 참여하는지에 따라 다르게 동작할 필요가 없습니다. 이 코드는
두 경우에 모두 동일하게 작동해야 합니다.RequiresNew를 사용하여 범위를 인스턴스화하면 이 범위는 항상 루트 범위가 됩니다. 이 범위가 새 트랜잭션을
시작하면 해당 트랜잭션은 범위 내부의 새 앰비언트 트랜잭션이 됩니다.Suppress를 사용하여 범위를 인스턴스화하면 앰비언트 트랜잭션이 있는지 여부에 관계없이 이 범위는
트랜잭션에 참여하지 않습니다. 이 값을 사용하여 인스턴스화된 범위에서는 항상 앰비언트
트랜잭션이 null입니다.
이 외에도 시간 제한이나 격리수준을 설정하는 방법으로 세세한 설정이 가능합니다.
자세한 내용은 http://msdn2.microsoft.com/ko-kr/library/ms172152(VS.80).aspx 을
참조하기 바랍니다.
한가지 TransactionScope의 결정적 시간 제한 옵션은 따로 있습니다.
machine.config에서 MachineSettingsSection에서 전체적인 설정이 이미 설정되어 있습니다.
따라서 여러분이 하는 설정도 machine.config의 제한 시간을 넘어가지 못합니다.
http://msdn2.microsoft.com/ko-kr/library/ms172152(VS.80).aspx
기본 타임아웃이 10분으로 잡혀 있다고 합니다. 따라서 여러분들이 시간을 아무리 늘려도
10분 이상을 설정할 수 없습니다. 만약 더 큰 시간이 필요하다면 machine.config의 내용을
수정해야 합니다
<system.transactions>
<defaultSettings distributedTransactionManagerName="NERPSVR" timeout="00:00:00" />
<machineSettings maxTimeout="00:00:00" />
</system.transactions>
<리스트3>Machine.config의 Transaction Timeout 설정
이 내용은 정성태님의 블로그에서 내용을 참조할 수 있습니다.
http://www.sysnet.pe.kr/Default.aspx?mode=3&sub=0&pageno=0&detail=1&wid=716
일단은 그렇게 큰 작업과 복잡한 프레임웍을 제작할 것은 아니기 때문에
우선적으로 Web과 Windows를 동시에 지원하는 것으로 가닥을 잡고 준비하고 있습니다.
우선 간단히 네임스페이만 정리해 보았습니다.
마음으로는 .NET Framework 3.0 이상을 사용하고 싶지만 호스팅 업체 사정상
어쩔 수 없이 프레임웍의 버전은 2.0으로 제한했습니다.
기반 서비스는 Microsoft의 Patterns & practices에서 제공하는 Enterprise Library를
사용하는 것으로 가닦을 잡았습니다.
아참에 Enterprise Library를 공부해 보겠다는 욕심도 함꼐 들었습니다.
아무튼 Enterprise Library는 2006 January Enterprise Libarary for .NET Framework 2.0
버전을 사용하기로 결정했습니다.
http://www.microsoft.com/downloads/details.aspx?familyid=5A14E870-406B-4F2A-B723-97BA84AE80B5&displaylang=en&hash=3U2vJPRkpncc5%2bVHbiTc6Nz9M0nkjlDz73r9Bau1mGj%2bQRcTvra0rLldpzp9TUvW0YgteS5RCuEAUdzILjwrHw%3d%3d
Enterprise Library가 버전이 올라가더니 설치화면도 훨씬 미려하게 잘 수정된것 같다.
<그림3> Enterprise Libarary설치
<그림4> 설치 옵션
지금은 네임스페이스마다 필요한 클래스를 도출하고 있는 중.. ^^
댓글을 달아 주세요
닷넷과 관련된 작업을 하다보면 어떤게 표준일까 항상 생각하게
되는 부분들이 많이 생기게 됩니다.
이럴때 참조할 수 있는 가이드 문서 입니다.
나온지는 오래되었지만 그래도 아직 제법 쓸모 있는 문서 입니다.
댓글을 달아 주세요
그냥 그저 그런 광고라고 생각했었습니다. 하지만 모든 것의 시작은 생각에서 부터 시작한다고 하면
정말 맞는 말인것 같습니다. 같은 사물을 그리고 같은 현상을 보고 느끼더라도 생각이 바뀌면
내게는 다른 의미로 받아들여지는 것 같습니다.
지금 살던 집 이전에 동네는 입구가 정해져 있는 약간 외진 동네였습니다.
동네 사람들도 그 동네만큼이나 꽤 오래 된 사람들이 있는 그런 허름한 동네였습니다.
그 동네 입구에는 언제 부터 있었는지 모를 노란털을 가진 떠돌이 개 한마리가 있었습니다.
이 떠돌이 개는 동네 사람들이 던져주는 먹걸이를 받아먹고 살기 시작했고 그래서였는지
자기 스스로 그 동네를 지켜야 하겠다는 사명감 같은 것을 가지게 되었는지도 모르겠습니다.
동네 식구들을 다 기억하고 있다가 이상한 사람들이 오면 새벽이라도 큰 소리로 짖고
아는 사람들이 오면 헥헥거리며 뛰어와서는 기어오르고는 했습니다.
동네 사람들은 당연히 이 떠돌이 개를 좋아했습니다.
한 가지 재미있는 사실은 사람들은 이 개를 각 각 자기 나름데로 이름을 지어서 부르고는 했는데
"노랭이", "누렁이", "해피", "쫑".... 각양 각색이었습니다.
하지만 이 많은 이름들도 다 자기 이름인줄 알고 어디서든 부르면 헥헥거리면서 달려나오는
이 녀석은 누런 털이 떡져 있더라도 충분히 쓰다듬어 주고 싶은 생각이 들 정도로 이쁜 구석이 있었습니다.
가만히 들여다 보면 잘 씻겨서 다듬어 두면 제법 괜찮을 법한 좋은 인물이었습니다.
그냥 지나가면서 보면 아무것도 아닌 그저그런 떠돌이 개 였을 텐데 어느 순간 부터는
지나가다가 안보이기라도 하면 걱정되고 섭섭한 존재가 되어 버렸습니다.
"내가 그의 이름을 불러주었을 때 그는 나에게로 와 꽃이 되었다."
교과서에 나왔던 김춘수님의 시에서 처럼 그냥 흘려버리면 아무것도 아닌 것이지만
주변에 관심을 가지고 사물들을 지켜보면 모든 것이 다 의미를 가지게 되는 가 봅니다.
제 눈에는 배추, 파, 시금치, 상추, 깻잎... 이런것들 외에는 모두 오로지 '풀'로만 보이지만
황대권님의 '야생초 편지'를 읽고 나면 조그만 풀 하나 하나에 모두 이름이 있고 다들 특징이 있고
사람과 교류할 수 있는 부분들이 있는 것을 알게 됩니다.
오늘 새벽에 꿈을 꾸다가 문득 돌아가신 아버지를 만나 뵈었습니다.
돌아가실 때 보다 더 건강해 뵈는 아버지는 제 손을 잡으시면서
"마음 먹기 나름이다." 라는 짧은 말을 해 주셨습니다
그냥 흘려듣기에는 지금 나에게 너무나도 소중한 한 마디였습니다.
생각은 에너지 입니다. 내 마음에 따라서 주변의 모든 것은 아무것도 아닌 그냥 흘러가는 사물이 될 수도
내게 의미있는 에너지가 될 수 있을 것 같습니다.
또 연말이 되고 또 한 해가 넘어가고 있습니다.
우리가 나이를 먹어가는 건 더 보수적이 되는 것이 아니라 주변의 의미들을 더 잘알아가는 현인이
되어가는 의미가 되었으면 좋겠습니다.
댓글을 달아 주세요
-
login 2007.12.17 18:08 ADDR EDIT/DEL REPLY
님 지나가다가 블로그 운영중조언 한가지를 드리자면 님의 사이트를 열었을때 제 노트북의 메모리가 무려 16메가정도를 잡아먹었습니다. 한 화면에 포스트를 하나만 노출되게 하시는 것이 방문자 트래픽을 올리는데 유용합니다. 이렇게 로딩이 느리면 이걸 다 기다리고 포스팅하신것을 읽어줄 방문자는 별로 없습니다. 또한 실사가 많이 들어간 것은 좋은데 용량을 좀 줄여서 하시는 것이 페이지 웰빙에 좋습니다.
-
지나가는 사람 2007.12.17 23:57 ADDR EDIT/DEL REPLY
윗분 정말 이상하시네... ㅡㅡ;
본인 노트북의 하드웨어나 소프트웨어적인 문제는 고려치 않고...
방문한 블로그에 핑계를 ... 참 어이없는 사람이군요...
저는 아무 이상없이 잘 열립니다...
그냥 이 제목으로 사용하고 싶습니다.
인순이 선생님(제게 있어서 선생님은 큰 가르침을 주신 분이면 남녀노소를 가리지 않고 제가 즐겨 사용하는 호칭입니다.)의 거위의 꿈은 누구에게나 큰 힘과 도전을 주는 곡입니다.
폭발할 것 같은 가창력을 폭발시키지 않으면서 극한으로 자제된 최고의 음성으로 불러주는 거위의 꿈은
가만히 듣고 있으면 잃어버린 꿈을 상기시켜주면서 왠지 눈물이 날 것 같은 곡입니다.
때늣은 거위의 꿈 타령인지는 모르겠습니다만
지금의 제 모습과는 달리 어렸을 때는 초라하고 병약했던 볼품없던 아이였습니다.
유난히 잔병치레가 많았고 그 덕분에 아버지 어머니의 마음을 많이 상하게 했던 아이였습니다.
성적도 그저그런 하지만 내게 의미를 주는 무엇인가가 있다면 거기에는 모든 것을 걸고
집중할 수 있었던 열정도 있었습니다.
대학을 졸업하고 컴퓨터를 직업으로 해야되겠다는 생각하나로 48만원을 들고 상경한 서울은
화려하고 현란한 기술로 사람을 미혹게 하는 꿈의 도시였지만 저 같은 이방인들에게는
의지할 곳 하나 없는 모든 것 하나 눈에 익은것 없는 냉정한 도시였습니다.
이 냉정한 도시에서 나를 위한 공간과 시간은 없었고 지방색이 완연한 말투부터
옷차림 까지 모든 것이 촌스러웠습니다.
모든 것이 부족하고 존재감이 없었던 내게도 조그만 하숙방에서 자취방에서 꿈꿔왔던 꿈이 있습니다.
힘들어도 힘든줄 몰랐던 그 시절 저는 꿈을 넣으면 돌아가는 엔진이 달린 자동차 처럼 달릴 수 있었습니다.
여기저기서 일을 하다 보면 항상 그 분야의 뛰어난 사람들도 많이 만나게 됩니다.
뛰어난 사람들 중에는 후배들이나 주변사람들에게 긍정적인 힘들을 주고 이끌어 주는 사람들이 있는가 하면 반대로 자기가 가진 것들을 지키기에 급급한 쪼잔한 기득권 세력도 존재 합니다. 기득권 세력은 자신이 누리고 있는 혜택을 지키려는 강한 관성을 가지고 있어서 기득권 세력이 가지고 있는 기회를 다른 사람들이 가지기 위해서는 많은 노력이 필요로 합니다.
최근에 이런 기득권 세력을 두 번이나 만나게 되었습니다. 아니 세 번이었던가..
기득권 세력의 절대반지 같은 힘을 느끼면 나도 모르게 등을 돌리고 투덜거리고 다른 길을 찾는 방법을 선택했는데 이번에는 왠지 그러고 싶지 않았습니다. 어떻게 하면 좋을까 고민하다가 인순이 선생님의 거위의 꿈을 들었습니다. 한참을 들었습니다. 그리고 계속 들었습니다.
인순이 선생님은 단일 민족국가에서 혼혈이라는 태생적 한계를 가지고도 꿈을 접지 않고
가난과 차별과 외로움의 한켠에서 모두에게 사랑받고 감동을 주는 가수가 되었는데...
조그만 벽 하나 하나 마다 투덜 거리고 있었구나. 거위의 꿈 가사처럼 벽들을 넘어 날아가지 않는 한
계속 돌아 돌아 갈 수 바께 없는 것을 이때까지 회피하면서 살아왔구나 하는 생각이 문득 들었습니다.
또 뒤집어 생각 해보면
"기득권과 충돌한다는 것은 내가 이제 그 기득권과 경쟁해야 할 만큼 성장했다는 것을... 아직 어린 생각으로 뒤돌아 앉아서 투덜거리기만 했구나... 아직 낮은 곳에서의 성공을 믿고 매너리즘에 빠져 있었구나...
어제의 성공이란 지난 주에 내린 흰눈과 같은 것을... "
거위의 꿈은 들을 때 마다 제게 새로운 힘을 줍니다.
- 거위의 꿈
난 난 꿈이 있었죠 찢겨 남루하여도
내 가슴 깊숙히 보물과 같이 간직했던 꿈
혹 때론 누군가가 뜻 모를 비웃움 내 등뒤에 흘릴때도
난 참아야 했죠 참을 수 있었죠 그 날을 위해
늘 걱정하듯 말하죠 헛된 꿈은 독이라고
세상은 끝이 정해진 책처럼
이미 돌이킬 수 없는 현실이라고
그래요 난 꿈이 있어요
그 꿈을 믿어요 나를 지켜봐요
저 차갑게 서 있는 운명이란 벽 앞에
당당히 마주칠 수 있어요
언젠가 난 그 벽을 넘고서
저 하늘을 높이 날을 수 있어요
이 무거운 세상도 나를 묶을 순 없죠
내 삶의 끝에서 나 웃을 그 날을 함께해요
이제 서울 공화국 국적(?)도 있고 결혼도 하고 가족도 생기고 또 다른 삶의 목표인 아기들도 생겼습니다. 나를 알아주는 사람도 많이 생겼고 처음보다는 많은 것을 가지고 있을 수 있게 되었지만 하지만 아직 모든 것은 현재 진행형일 수 밖에 없는 욕심쟁이입니다. (우후후~)
그리고 저 같은 욕심쟁이들이 제가 했던 시행착오들을 안할 수 있게 이끌어 주고 싶습니다.
우리는 모두 함께 편대 비행을 해야할 거위들이니까요 ^^
NET_표준개발가이드.doc
댓글을 달아 주세요
저도 Sandcastle 팬인데요... ㅎㅎㅎ
오 정말 필요한 내용이었어요..^^
저번에 nDoc을 쓰려다가 포기했었는데..
sandcastle이란 것이 있었군요.. 내일 당장 깔아서 실행해봐야겠네요.^^
와... 닷넷에 이런 기능이 숨겨져있었군요..
javadoc.exe와 비슷한 기능이었던가요.
C#에도 있었군요.. 감사합니다. ^^