한국 마이크로소프트에서 주최하는 TECH DAY 2009 행사가 오픈하였습니다. 지난 Dev Days 2008 에 이어 새롭게 개최하는 행사입니다. TECH DAY 는 온라인으로 진행되며 다양한 주제로 동영상 세미나가 준비되어 있습니다.

 

http://www.techdays.co.kr/

이번 TECH DAY 는 새로운 플랫폼 시대를 대비하기 위한 개발자와 IT 전문가를 위한 컨퍼런스 입니다. 특히 온라인 컨퍼런스의 장점이라면 시간과 장소에 구애 받지 않고 언제나 오픈되어 있는 컨퍼런스라는 점입니다.

트랙은 키노트와 개발 트랙, IT 전문가 트랙으로 구성되어 있으며, 특히 개발 트랙과 IT 전문가 트랙은 굉장히 많은 동영상 콘텐트가 준비되어 있습니다. 그리고 개발 플랫폼 트랙은 제가 몸담고 있는 VSTS 2010 팀에서 전체 세션을 맡았습니다.    

 

이번 TECH DAY 2009 행사에 많은 참여를 부탁드립니다. 경품도 많이 준비가 되어있으니 경품 이벤트에도 도전해 보세요.

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 산소나무 2009.10.22 10:14 Address Modify/Delete Reply

    상당히 많은 관심을 가지고 있는 부분이었는데~
    동영상 꼼꼼히 챙겨 보도록 하겠습니다. ^^

우선 설치해서 잠깐 둘러본 결과, 가장 우려했던 IDE 의 성능 문제는 의외로 빨랐습니다. 어떤 부분은 Visual Studio 2008 보다 더 빨랐고, 기본적인 대부분의 동작의 실행 속도는 굉장히 만족스럽습니다.

마이크로소프트 Visual Studio 개발팀도 이 점을 인지하고 개선하려고 상당히 노력한 흔적이 엿보입니다. 기존 CTP 와 Beta 1 에서 기어가는 듯한 IDE 가 느렸던 문제는, Beta 2 버전에서는 걱정하지 않으셔도 될 것 같습니다. 체감적으로 Visual Studio 2008 보다 느리지 않네요.  

Visual Studio CTP 와 Beta 버전에 익숙해졌는지 외관상 크게 거부감도 없습니다. 

   

설치된 구성 요소 검색하는 화면

   

라이선스 동의 화면

   

설치 패키지 선택 화면

   

설치 시작 화면

   

설치되는 구성 요소 목록

   

   

   

   

.NET Framework Beta 2 가 설치 된 후 시스템 재시작이 필요합니다.

   

   

Visual Studio 2010 Beta 2 의 Splash 화면

   

   

Visual Studio 시작 페이지 화면

   

Posted by 땡초 POWERUMC

댓글을 달아 주세요

미국 시간으로 2009년 10월 19일, Visual Studio 2010 Beta 2 버전이 공개가 되었습니다. MSDN 을 통해 Beta 2 버전을 다운로드 받으실 수 있습니다.

다운로드
http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx

 

그간 Visual Studio 2010 CTP/Beta 버전에서 보여주었던 약간의 성능적인 문제는 이번 Beta 2 버전에서 상당히 많이 개선이 되었다고 합니다.

특히 이번 Beta 2 버전부터는 제품 라인이 전체적으로 변경되었습니다. 기존의 Professional 제품을 제외한 모든 제품의 라인이 변경이 됩니다. 다운로드 받으실 때 혼란이 없으시길 ^_^

더불어 Expression 제품 군도 두 개의 제품으로 나뉘어지게 될 것입니다.

기존 제품

Beta 2 부터 적용되는 제품

Visual Studio Team Suite

Visual Studio Ultimate

Visual Studio Test Edition
Visual Studio Database Edition
Visual Studio Architecture Edition Visual Studio Development Edition

Visual Studio Premium

Visual Studio Professional

Visual Studio Professional

아래는 변경된 MSDN 로고 입니다. ^_^

   

Posted by 땡초 POWERUMC

댓글을 달아 주세요

이 포스트도 예전에 3월 달에 써놓기만 해놨다가 이제서야 Publishing 하게 되었습니다. 워낙 구석 구석 써놓고 관리를 하지 않다 보니 뭐가 어디에 있는지 모르겠네요 ㅡㅡㅋ;

   

웹 테스트 중 Favicon 다운로드로 인한 문제

   

Visual Studio 의 웹 테스트 또는 Fiddler 등을 이용하여 테스트 중에 Internet Explorer 7 에서 문제가 발생하였습니다. 크리티컬한 문제는 아니었습니다만, 테스트 중에 불필요한 Favicon 다운로드가 너무 빈번하게 발생하였습니다.

이런 문제는 실제 테스트에서 오류로 작용하지는 않지만, 성능 관련 테스트나 시나리오가 있는 테스트에서는 의도하지 않는 결과가 나올 수 있기 때문에 올바른 테스트라고 보기가 어렵습니다.

웹 테스트로 Favicon 의 빈번한 다운로드 문제가 발생하여 Fiddler 로 캡처해본 화면 입니다.

   

[그림1] 엄청난 Favicon 을 다운로드하여 testing 을 방해한다

   

문제 해결 방법

Internet Explorer 7 에서의 해결 방법
http://blogs.msdn.com/jeffdav/archive/2007/03/01/why-doesn-t-the-favicon-for-my-site-appear-in-ie7.aspx

FireFox 에서의 해결 방법
http://www.howtogeek.com/howto/internet/firefox/quick-tip-disable-favicons-in-firefox/

Posted by 땡초 POWERUMC

댓글을 달아 주세요

VSX(Visual Studio Extensibility) 는 Visual Studio 의 기능을 확장할 수 있는 SDK(Software Development Kit) 를 통해 툴의 기능을 확장할 수 있는 소프트웨어 개발 키트입니다. 잘 설계된 Visual Studio 의 확장 가능한 모델은 Visual Studio 2005 부터 비약적으로 발전했습니다. 그리하여 현재 Visual Studio 2010 은 MEF(Managed Extensibility Framework) 를 기반으로 하여 개발, 패키징, 배포에 이르러 훨씬 단순화된 새로운 확장 모델인 VSIX 를 내놓게 되었습니다.

Visual Studio 2003 부터 Visual Studio SDK 를 제공해 주었지만, Visual Studio 2003 버전에서는 확장 기능을 개발할 수 있는 그리 좋은 여건은 아니었습니다. 왜냐하면 Visual Studio 2003 의 Customizing Point 는 대부분 자동화 개체 모델인 DTE 에 굉장히 의존적이었습니다.

Visual Studio 2005 는 이전의 IDE 기반을 갈아엎었다고 할 수 있을 정도로 상당히 파격적인 모습으로 다가왔습니다. 사실 이때만해도 Visual Studio 2003 에 비해 너무 느려지지 않았냐는 불만을 상당히 많이 들었습니다. 하지만 개발자들의 하드웨어 스팩이 좋아지고, Visual Studio 2005 가 제공하는 다양한 기능은 안쓸래야 안쓸수 없었답니다. 그리고 Visual Studio 2005 SDK 는 2008 버전까지 고스란히 답습하고 있었습니다.

Visual Studio 2008 은 이제 .NET 개발의 국민 IDE 로 자리매김 하였습니다. 그리고 빠르게 많은 기업에서 Visual Studio 2008 과 .NET Framework 3.5 기반으로 마이그레이션을 하고 있습니다. (적어도 제 주변 대부분이..) 그리고 이 시점부터 Software Factories 개념을 도입한 Guidance Automation 과 Blueprints 등 Visual Studio 확장 기능들이 대거 모습을 드러내기 시작했습니다. (GA 는 2005 버전부터 등장했지만 실제 활성화된 시점은 개인적으로 2008 부터가 아닐까 생각합니다)

그렇다면 Visual Studio 2010… 이제는 IDE 환경의 지존을 논한다고 생각합니다. 광고성 멘트라고 생각하시면 그냥 스킵 하셔도 좋습니다. .NET Framework 는 더없이 탄탄해지고, 딱딱했던 IDE 환경은 UX 친화적인 면을 보여주기 위해 노력한 흔적이 엿보입니다. 그리고 Oslo, Velocity, Pex, T4 Templates, 미려해진 DSL Tools, 진정한 통합을 꿈꾸는 Team System, 그리고 이번 주제였던 정말 편한 개발 환경 확장을 제공해주는 VSX...

   

.NET 의 과거와 현재, 그리고 미래
http://blog.powerumc.kr/172

[T4] - 1. Code Generation 과 GA(Guidance AUtomation)
[.NET/Visual Studio] - [T4] - 1. Code Generation 과 GA(Guidance Automation)

[Blueprints] S+S Blueprints
[Software Development/Software Factory] - [Blueprints] S+S Blueprints


   

그럼 기존의 VSX 는 어떻게 IDE 도구를 확장하였을까요?

  • Visual Studio Macro
    VB 스크립트 언어를 이용하여 Visual Studio 의 자동화 개체 모델의 DTE 객체를 제어할 수 있습니다. 아무래도 스크립트 언어이다보니 개발의 편의성은 좋지만 배포와 코드 보안에 좀 떨뜨름합니다.

       

  • Visual Studio Addin
    기능적인 면에서 Visual Studio Macro 와 큰 차이는 없습니다만, 스크립트 언어가 아닌 C# 과 같은 Managed 언어로 개발이 가능합니다. 태생적으로 Visual Studio Macro 와 동일선상이기 때문에 Addin 의 독립적인 기능만으로는 확장에 한계는 있었습니다. 하지만, DTE 개체 모델을 통해 개발이 굉장히 쉽고, 배포 또한 단순하여 가장 많은 사랑을 받은 VSX 분야입니다.

       

  • Visual Studio Integration Package (이하 VSIP)
    Visual Studio 를 진정으로 통합할 수 있는 확장 방법입니다. Visual Studio 의 COM Interface 를 고스란히 사용할 수 있고, 이것을 이용하여 Visual Studio 의 모든 기능을 활용하고 확장할 수 있습니다. 실제로 Visual Studio 기능의 대부분이 VSIP 를 통해 개발이 되었고 Visual Studio 의 특징을 가장 잘 보여주는 Interface 들로 구성이 되어있습니다. 여러분이 잘 알고 있는 솔루션 탐색기, 오류 리스트, 팀 탐색기 등 셀 수 없을 정도의 많은 VSIP 들이 Visual Studio 에 포함되어 있습니다.

       

  • Visual Studio Shell Isolated
    Visual Studio Shell Isolated 는 Visual Studio 와 같은 Shell 을 제공하고 개발할 수 있는 방법입니다. VSIP 가 Visual Studio 확장 기능에 필요한 요소를 가르킨다면, Shell Isolated 는 VSIP 를 담는 그릇이 되겠군요. Visual Studio Shell Isolated 를 이용하게 되면 기존에 Visual Studio 에서 제공하는 여러 가지 인터페이스를 고스란히 사용할 수 있는 이점이 있습니다. 가량, Project Type, Intellisence 와 Microsoft 의 통합 빌드 솔루션인 MSBuild 등 다양한 기능을 곧바로 사용할 수 있다는 장점이 있는 것이죠.

       

  • Visual Studio Language Package
    Visual Studio 에서 사용할 수 있는 언어를 개발할 수 있습니다. 기본적으로 C#, VB.NET, C++ 등을 사용할 수 있지만 PHP, RoR, Native C 등의 언어를 개발할 수 있도록 하고, 이미 Visual Studio for PHP, Visual Studio for RoR 가 상용화 되었고, Visual Studio for C 는 Visual Studio SDK 예제로도 포함이 되어 있답니다.


       
  • Domain-Specific Language Package
    도메인에 특화된 언어를 개발할 수 있는 방법을 제공합니다. 일반적으로 IT 조직과 개발 조직은 서로가 사용하는 언어가 다릅니다. 즉, 경영진과 실무진과 같은 물과 기름의 관계를 이해시키기 위한 언어로써, 이미 Visual Studio 에서 광범위하게 사용되고 있는 방법입니다.

 

  • Help Integration
    MS HELP 2.0 을 이용하여 Microsoft Document Explorer 의 콘텐츠를 추가할 수 있는 방법입니다. Microsoft Document Explorer 는 일반적으로 Visual Studio 도움말로 생각하시면 됩니다. 이곳에 콘텐츠를 추가하기 위해 Setup Wizard 를 제공하고, 쉽게 Visual Studio 도움말에 자사 또는 자신의 콘텐츠를 추가할 수 있습니다.

       

어휴,, 정말 다양한 방법으로 Visual Studio 를 확장하는 방법을 제공해 주는군요. 이러한 아키텍처는 Visual Studio 2005 부터 제대로 뿌리를 내렸는데, 그 중 일부분은 Visual Studio 2010 에서 좀 더 획기적으로 변신을 합니다.

변신을 하면서 기존의 COM 기반의 인터페이스는 더 이상 WPF 기반의 어플리케이션에서 상당수 비호환적인 면이 있고, 한계점을 드러내지 않았나 생각을 해봅니다. 실제로 기존의 인터페이스는 WPF 의 Managed 환경에서 더 이상 호환할 수 없어집니다. WPF 기반의 IDE 환경에서는 새로운 인터페이스가 필요했고, MEF 를 도입함으로써 새로운 확장 가능한 모델이 필요했습니다. 바로 그것이 새로운 확장 가능한 모델인 VSIX 입니다.

VSIX 는 기존의 IDE 확장 모델과 새로운 MEF 기반의 확장 기능을 개발부터 패키징, 배포까지 통합할 수 있는 방법을 제공해 줍니다. 뿐만 아니라 기존의 확장 기능과 새로운 MEF 기반의 확장 기능을 통합하고 연동까지 할 수 있으니 이것이야 말로 누이 좋고 매부 좋은 일이 아닐까 합니다.

   

이제부터 위의 다양한 확장 기능을 개발하는 방법을 시작하여 VSIX 에 이르기 까지 한번 짚고 넘어가볼 예정입니다. 아직까지 국내에서는 이러한 희귀한 분야를 다루는 곳도 흔치 않고, 관심이 있더라도 정보가 부족하여 어느 정도 종점을 찍고 포기하는 분들도 많이 있습니다. 아마 이 연재를 통해서 Visual Studio 에 보다 관심을 갖고 널리 기술을 알리는 좋은 기회가 되지 않을까 생각을 하면서, 연재를 기대해 주세요.

Posted by 땡초 POWERUMC

댓글을 달아 주세요

MEF(Managed Extensibility Framework) 이 2009년 7월 13일에 릴리즈되어 14일에 공개가 되었습니다. 특히 MEF 는 .NET Framework 4.0 에 포함이 되어있으며, CodePlex 에서 굉장히 빠른 속도로 발전하고 있는 프레임워크 중에 하나 입니다.    

CodePlex MEF 사이트에 등록된 릴리즈 노트 입니다.

그 중에서 몇 가지만 살펴보도록 하겠습니다.

실버라이트 3 지원

특히 이번에 눈여겨 볼 만한 것이 Silverlight 3 를 지원하는 것입니다. 이미 Preview 5 이전의 MEF 에서는 실버라이트를 지원하기 위해 코드에서 전처리 명령 구문을 사용하여 프레임워크 실버라이트가 지원되긴 했습니다. 그것을 기반으로 이번 Preview 6 버전에서는 실버라이트 3 용 솔루션이 제공됩니다. 이 솔루션을 통해 실버라이트용 MEF 프레임워크를 빌드 하시면 됩니다.

   

ExportAttribute 의 seal 키워드 제거

이번 MEF Preview 6 에서 ExportAttribute 의 seal 키워드가 제거됩니다. 이 전 Preview 5 에서는 ExportAttribute 을 절대 상속할 수 없는 구조였기 때문에 독자적인 Export 를 제공할 수 없었기, Metadata 를 ExportAttribute 와 같은 기능울 개별적으로 지정해야 하는 등의 Export 기능의 확장에 불합리한 구조로 되어있었습니다. 하지만 이번 Preview 6 버전에서는 ExportAttribute 클래스의 seal 키워드가 제거 됨으로써 ExportAttribute 의 확장이 용이하게 되었습니다.

 

ImportMany 로 통일된 컬렉션 처리

이제 모든 컬렉션은 ImportMany 로 통일되었습니다. Preview 5 에서는 ExportCollection<T> 또는 IEnumerable<T> 와 같이 사용하기도 까다롭고 이것으로 반환된 객체를 처리하기에도 편리한 구조는 아니였습니다. Preview 5 에서도 ImportMany 의 기능이 존재하였지만, 이번 Preview 6 는 이것으로 모든 컬렉션 처리를 하도록 통일되었다는게 혼란스러웠던 부분을 간소화할 수 있을 것 같습니다.

   

기타 그 밖에도 구조적으로 보다 안정되었고, 메서드나 클래스의 네이밍이 변경되었고, 예외 시에 Composition 동작의 분석을 추적하기 쉽도록 덤프(Dump) 를 뜰 수 있는 로깅 기능 등 다양한 기능이 추가되었습니다. 정식 버전의 MEF 는 어떤 모습으로 나올지 정말 기대가 됩니다. 더 자세한 내용은 아래의 링크를 통해 더 쉽게 설명이 되어있으니 참고 하십시오.


참고문헌
MEF Preview 6 Available
http://blogs.msdn.com/nblumhardt/archive/2009/07/09/mef-preview-6-available.aspx

'.NET > .NET Framework' 카테고리의 다른 글

MEF 에 Generic Type 을 지원하기 위해서..?  (0) 2010.01.27
MEF 는 Generic Type 을 지원하지 않는다!  (0) 2010.01.26
MEF Preview 6 공개  (0) 2009.07.20
MEF 세미나 동영상 - 6월 10일  (0) 2009.07.08
CodeFx 프로젝트  (0) 2009.06.24
MEF 세미나 자료  (0) 2009.06.22
Posted by 땡초 POWERUMC

댓글을 달아 주세요

 

지난 6월 10일 VSTS 2010 팀에서 진행한 MEF(Managed Extensibility Framework) 세미나에서 보여드린 데모를 조금 수정하여 Visual Studio Gallery 에 공개하였습니다.

Visual Studio 2010 이 WPF 기반의 IDE 환경으로 탈바꿈하면서 특히 코드 에디터 쪽은 WPF 의 기능을 유감없이 보여주었습니다. 특히 코드 에디터는 MEF 를 통해 대부분의 기능이 만들어졌고, 이것을 확장할 수 있는 기능을 만드는 것이 얼마나 편해졌는지 보여주기 위한 데모였습니다.

세미나에서도 설명했지만 현재 Visual Studio 2008 까지 버전에서 이러한 확장 기능을 개발하기 위해서는 굉장히 많은 단계를 거쳐야 합니다. Visual Studio 2008 까지는 COM 을 기반으로 한 IDE 이기 때문에 적용되는 기술만 나열해도 절대 단순하지 않은 과정을 거쳐야 합니다. 마우스와 키보드와 같은 장치의 이벤트를 핸들링 해야 하고, GDI+ 를 이용해 화면에 드로잉을 하고 잔상과 깜빡임을 없애기 위해 더블 버퍼링 등의 기법이 조합되어야 했습니다. 그리고 나은 사용자 인터페이스를 위해 많은 기교를 부려야만 했죠.

   

멀리서 프레젠테이션을 시청하는 분들도 커서의 위치를 잘 보이도록 화살표가 커서를 따라 다닙니다. 
 

 

Visual Studio Gallery

Umc.Core.Tools.MousePresentationTracker.v1.0

   

   

현재는 단순하게 마우스를 따라다니는 데모를 급 개조했지만, 나중에는 생각해 놓은 기능들을 추가하려고 합니다. 어쨌든 이전에 공개했던 VSGesture 와 다른 컨셉으로 프레젠테이션을 위한 도구로 점차 기능이 추가될 예정입니다.

   

'Umc Projects > MousePresentationTracker' 카테고리의 다른 글

MousePresentationTracker.v1.0  (0) 2009.07.17
Posted by 땡초 POWERUMC

댓글을 달아 주세요

지난 6월 10일 VSTS 2010 팀에서 세미나를 진행하였습니다. 세미나 프레젠테이션은 MEF 세미나 자료 에서 볼 수 있습니다.

그리고 얼마 전에 촬영한 동영상도 공개가 되었습니다. VSTS 2010 은 굉장히 큰 규모의 개발 도구, 개발 플랫폼 등의 버전 업으로 아직도 많은 부분을 알려드리지 못했고, 미처 저희들도 모두 알지 못하는 부분도 많습니다.

하지만 남들보다 먼저 접해본 분야이고 이것을 알려드리기 위해 진행한 세미나입니다. 아래의 동영상을 시청하시고 VSTS 2010 에 많은 관심을 가져주세요. ^^

 

엄준일 - Managed Extensibility Framework

   

그리고 저희 팀원들이 진행한 세미나도 굉장히 볼만합니다. 그리고 전혀 중복되지 않는 분야의 세미나이기 때문에, 하나 하나씩 시청하면서 관심분야에 매진해보는 것은 어떨까요?

   

VSTS 2010 팀 블로그에서 세미나 동영상 더 보기

'.NET > .NET Framework' 카테고리의 다른 글

MEF 는 Generic Type 을 지원하지 않는다!  (0) 2010.01.26
MEF Preview 6 공개  (0) 2009.07.20
MEF 세미나 동영상 - 6월 10일  (0) 2009.07.08
CodeFx 프로젝트  (0) 2009.06.24
MEF 세미나 자료  (0) 2009.06.22
[MEF] 10. Querying the Composition Container  (0) 2009.05.17
Posted by 땡초 POWERUMC

댓글을 달아 주세요



기존 기능을 새롭게 업그레이드한 Comment Helper 0.91 베타 버전을 공개합니다.

업데이트 방법은 기존 Addins 폴더에 CommentHelper.DLL 을 새로운 버전으로 덮어씌우면 됩니다.
( 설치방법 참조 http://umc.pe.kr/article_87.aspx )
 
[ 기존 Comment Helper 0.9b 화면 ]
 
[ 핫키 기능이 추가된 Comment Helper 0.91b 화면]
 
위의 캡쳐 화면과 같이 핫키(Hot key) 기능이 추가 되었습니다.
비쥬얼스튜디오 2005 에서 지원하는 “IntelliSense 코드조각” 으로 불리는 “Code Snippet기능은 참 편리하지만, 정해진 XML Element 에 따라 수정 및 XML 파일을 등록해야 하기 때문에 약간의 불편은 감소해야 합니다.
 
이번에 구현된 핫키(Hot key) 기능은 코드스니펫 보다 편리하게 코드 및 주석을 관리할 수 있습니다.
 
1. 핫키(Hot key) 등록 방법
위 그림과 같이 주석 수정을 클릭하여 Hot Key 항목에 원하는 키워드를 입력합니다.
 
2. 핫키(Hot key) 사용 방법
핫키(Hot key) 로 등록한 키워드(단어) 를 입력합니다.
ESC
키를 두번 연속으로 누릅니다.
 
등록된 Hot key 가 없을경우 기존 방법처럼 기본주석으로 설정된 코드 및 주석이 표시됩니다.
 
본 프로그램은 제작자의 동의 없이 상업적인 용도로 사용할 수 없으며, 재배포를 할 수 없습니다.
Posted by 땡초 POWERUMC

댓글을 달아 주세요

비쥬얼스튜디오는 추가기능 프로젝트를 통해 VS,NET Addin 을 개발할 수 있고, 디버깅도 가능하다.
하지만 비쥬얼스튜디오 2005 버전에서 초기 설정대로 Addin 프로젝트를 디버깅 하려면 다음과 같은 에러 메시지가 뜬다.
 
[그림1. 디버깅시 에러]
 
하지만 간단하게 해결해 보자.
 
[그림2. LoaderLock 해지 방법]
 
비쥬얼스튜디오의 “디버그 -> 예외” 를 클릭하여, Managed Debugging Assistants를 확장시켜 Loaderlock 항목의 체크를 해지한다.
 
이제, 즐겁게 Addin 프로젝트를 디버깅 하자 ^^

요즘은 피곤하니까 글은 짧게 ^_^;;  텨텨텨 =3=3=3

Posted by 땡초 POWERUMC

댓글을 달아 주세요



CommentHelper 0.9 Beta
버전을 공개합니다.
이전버전 기능에 대한 자잔한 버그를 잡고 리플랙션 기능을 추가로 도입하였습니다.
 
 
리플랙션 기능을 이용하여 어셈블리의 모든 메서드 및 프로퍼티 등을 확인하며, 메서드의 실행 및 프로퍼티, 필드 값을 확인 할 수 있습니다.
 
설치방법
 
다음과 같이 압축파일의 CommentHelper.DLL 과 CommentHelper.addin 파일을 내문서의 Visual Studio 2005 -> Addins 폴더에 복사하여 넣습니다.
 
 
그다음 CommentHelperRef.exe 파일과 CommentHelperRef.exe.config 파일을 Visual Stduio 2005 설치경로의 Common7\IDE 폴더에 복사하여 넣습니다.

※ 특정 어셈블리의 리플랙션을 위하여 환경정보는 CommentHelperRef.exe.Config 파일로 복사하시면 됩니다.
 
 
예) C:\Program Files\Microsoft Visual Studio 8\Common7\IDE 에 복사
 
 
사용방법)
 
이번에 추가된 리플랙션 기능을 사용하기 위해선 .NET 으로 만들어진 어셈블리가 필요합니다.
 
리플랙션을 수행하기 위한 어셈블리(*.DLL, *.EXE) 를 선택합니다.
 
 
파일을 선택하면 어셈블리의 모듈을 로드하며 다음과 같이 자신이 작성한 메서드 및 프로퍼티, 필드 등 정보를 볼 수 있습니다.
 
 
마우스 오른쪽 버튼을 눌러 “실행”을 클릭하면 메서드를 실행하거나 필드의 값을 확인할 수 있습니다.
 
메서드의 경우 필요한 인자값을 입력하여야 결과를 확인할 수 있습니다.
 
다음과 같이 인자값이 배열인 경우는 콤마(,)로 배열의 값으로 대체하여 넣을 수 있습니다.
 
 
인자값이 없는경우 바로 결과를 확인할 수 있습니다.
인자값이 필요한 경우 인자값을 넣고 “실행”을 클릭하면 실행결과를 바로 확인할 수 있습니다.(단, 메서드인 경우 리턴 타입이 있어야 합니다.)
 
 
리턴 타입이 DataSet, DataTable 인 경우는 Xml 과 스키마를 저장 할 수 도 있습니다.
 
위와같이 리턴 데이터가 그리드에 바인딩 가능한 리턴타입인 경우 그리드에 데이터가 바인딩 됩니다. ( DataSet, DataTable 또는 Entity Class 인 경우 IListSource 가 구현된 경우)
 
데이터가 그리드에 바인딩 가능한 타입이 아닌경우 아래 그림 처럼 데이터를 확인 할 수 있습니다.
 
 
 
본 프로그램은 상업적인 용도로 사용할 수 없으며 재배포를 할 수 없습니다.
Posted by 땡초 POWERUMC

댓글을 달아 주세요




주석을 달아주는 .NET Addin 을 제작해 보았습니다..
 
현재 진행중인 프로젝트에서 쓰기위해 만든 프로그램인데, 이렇게 공개해 봅니다.
 
 
주요기능)
1)    에디터 창에서 ESC 키를 두번 연속 누르면 기본설정된 주석이 에디터 창에 바로 표시됩니다.
2)    복사 History 기능으로 에디터에서 복사된 내용의 개수를 설정하여 History 를 볼 수 있습니다.
3)    어플케이션에서 사용될 XML 형태의 파일을 읽을 수 있습니다.
 
설치방법)
CommentHelper.zip 파일을 다음의 내문서\Visual Studio 2005\Addins 폴더에 압축을 풉니다
 
다음 Visual Studio 2005 를 실행시켜 도구의 추가기능 관리자를 클릭한다.
 
CommentHelper 항목과 시작 항목을 체크하고 확인을 누릅니다.
 
그럼 다음과 같이 도구 메뉴에 CommentHelper 항목이 추가되었습니다.
메뉴의 CommentHelper 를 클릭하세요.
 
그럼 다음과 같이 사용자를 등록하라는 메시지박스가 뜹니다. 확인을 클릭합니다.
 
아래와 같이 주석에 표시될 작성자를 적고, 확인을 클릭합니다.
 
그럼 기본적인 설치작업은 모두 끝났습니다.
 
 
주요 기능 사용방법입니다.
 
1) 기본설정된 주석을 자동으로 Visual Studio 의 에디터창에 붙여 넣을 수 있습니다.
기본으로 설정할 주석에 마우스 오른쪽 버튼을 눌러 “기본 설정”을 클릭합니다.

커서를 <summary>와 </summary> 사이에 두고 빠르게 ESC 키를 두번 누릅니다.
 
환경설정에서 에디터에 붙이기 및 클립보드에 복사할 수 있습니다.
 
2) 복사 History 기능을 이용하여 얼마전에 복사했던 내용을 다시 사용할 수 있습니다.
 
3) 어플케이션에서 사용될 XML 파일을 열어 검색할 수 있습니다.
 
환경설정에서 사용자의 편의에 맞게 설정을 바꿀 수 있습니다.
기타 궁금한 사항이나 버그 및 개선 사항은 댓글을 남겨주시면 수정 및 개선하도록 하겠습니다.
 
본 프로그램은 현업에 종사하시는 개발자 및 개인적인 용도로 사용할 수 있으며, 본 블로그외의 다른곳에서의 재배포를 금지합니다.
Posted by 땡초 POWERUMC

댓글을 달아 주세요


동적 이벤트 처리.. 어디에 써먹으면 좋은까..
 
우선 이에 앞서 리플랙션 이야기를 잠시만 언급하겠습니다.
System.Reflection 네임스페이스와 System.Type을 사용하면 우리가 원하는 어셈블리의 클래스, 인터페이스, 프로퍼티 와 맴버에 대한 정보를 얻을 수 있습니다.
간단히 말하면, 런타임으로 동적으로 다양한 작업을 하고자 할 때 사용됩니다.
 
대부분 다음과 같은 경우에 자주 사용됩니다.
 
1) 실제 코드가 아닌 정보들, 그 파일에 따라다니는 정보들 등 어플케이션의 메타 정보를 얻어서 유지보수에 도움을 받기도 합니다.
 
2) 어셈블리의 내용을 알고자 할 때 사용할 수 있습니다.
Assembly asm = Assembly.Load("Mscorlib.dll");
Type[] types = asm.GetTypes();
foreach(Type t in types)
{
Console.WriteLine("Type : {0}", t)
}
 
3) Design Pattern 의 Abstract Factory Pattern 의 단점을 보완할 수 있습니다. Factory Class가 추가될 때 마다 본문의 내용이 수정이 불가피 하지만, 리플랙션을 이용하면 Class명만으로도 이것을 쉽게 해결 할 수 있습니다.
 
4) Com 개체를 Late-Binding 으로 불러 사용할 수 있습니다.
private void OpenExcel()
{
Type excel = Type.GetTypeFromProgID("Excel.Microsoft");
 
object objExcel = Activator.CreateInstance(excel)
object[] param = object[1];
param[0]=true;
excel.InvokeMember("Visible", BindingFlags.SerProperty, null, objExcel, param);
}
 
대부분 리플랙션은 접근제한 맴버 또는 프로퍼티, 메서드 호출 등에 사용되거나, 참조되지 않은 어셈블리를 제어할 때 자주 사용되곤 합니다.
 
하지만, 이번에는 자주 사용되지 않는 Event 제어를 해 보도록 하겠습니다.
 
소개될 예제는 WinForm 을 기준으로 작성되었지만, WebForm 에서도 약간의 소스를 변경하면 정상적으로 작동합니다.
 
우리가 즐겨 사용하는 컨트롤중 Button 컨트롤이 있습니다. 모든 닷넷 컨트롤은 Control 을 상속하므로 기본적인 많은 Event 가 존재하고, 컨트롤의 기능에 따라 CustomEvent 또한 존재할 것입니다.
 
우선 컨트롤의 이벤트 목록을 얻어보도록 하겠습니다.
string msg = string.Empty;
EventDescriptorCollection events = TypeDescriptor.GetEvents(button1);
foreach (EventDescriptor ed in events)
{
             msg += ed.Name + "\r\n";
}
MessageBox.Show( msg );
 
실행결과)
 
EventDescriptor 클래스는 이벤트 이름, 특성, delegate 등으로 구성되어 있습니다.
이 클래스의 주요 메서드 중 AddEventHandler 와 RemoveEventHandler 가 존재합니다.
이것을 통해 이벤트를 제어할 수 있습니다.
 
그럼, 이제 우리가 이벤트를 제어해야할 가상의 상황을 만들도록 하겠습니다.
public Form1()
{
             InitializeComponent();
             button1.Click += new EventHandler(button1_Click);
}
 
private void button1_Click(object sender, EventArgs e)
{
             System.Threading.Thread.Sleep(1000);
             MessageBox.Show("처리되었습니다");
}
 
위와같이 샘플로 만든 폼은 button1 을 클릭하면 가상의 1초의 작업 후 MessageBox 를 띄우는 경우입니다.
 
하지만 갑자기 변해버린 요구사항엔 ‘주요 몇몇 공통버튼에 대해 “Loading…” 텍스트나 “작업중입니다” 라는 메시지를 보여달라’는 변경사항이 있을 수 있습니다.
단지 몇 개의 폼이라면 수작업으로 간단히 해결할 수 있지만, 몇백개에 해당하는 폼이라면 사정은 달라지게 됩니다. Otl
그렇다면 당신은 어떻게 하겠습니까?
 
우선 현재 Form 의 Type 과 Loading… 텍스트를 뿌려줘야 하는 Button Type 을 알아와야 합니다
Type thisType                   = this.GetType();
Type btn1                          = button1.GetType();
주의할 점은, button1 이 실행중인 어셈블리가 아니라면 다른 어셈블리에서 PropertyInfo 를 통해 Type을 찾아와야 합니다
 
그리고 Loading.. 이벤트와 Button_Click 이벤트의 메서드가 다음과 같이 구현되어 있습니다.
private void OnLoadingHandler(object sender, EventArgs e)
{
        lblLoading.Visible = true;
        this.Refresh();
}
 
private void OffLoadingHandler(object sender, EventArgs e)
{
        lblLoading.Visible = false;
}
 
private void button1_Click(object sender, EventArgs e)
{
        System.Threading.Thread.Sleep(1000);
        MessageBox.Show("처리되었습니다");
}

위  이벤트의 메서드를 MethodInfo 를 통해 메서드의 정보를 찾습니다.
MethodInfo thisMi = thisType.GetMethod("button1_Click", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
MethodInfo onLoadMi         = thisType.GetMethod("OnLoadingHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
MethodInfo offLoadmi= thisType.GetMethod("OffLoadingHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
여기에서도 Button1_Click 이 실행중인 어셈블리가 아니라면 thisType 은 button1_Click 이 구현되어 있는 Class의 Type 이 되어야 합니다.
 
이제 Button 의 Click 이벤트를 가져와야 합니다.
EventInfo ei          = btn1.GetEvent("Click" , BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
으읔…. 정말 간단하네요 -_-;
 
위의 처음 샘플의 EventDescriptor.AddEventHandler 의 메서드는 EventInfo 에도 존재합니다.
 
아시다시피, 모든 이벤트는 delegate 의 대리자를 통해 추가 또는 삭제할 수 있습니다.
그럼 우리는 이벤트의 delegate 를 만들어야 합니다.
 
Delegate d                         = Delegate.CreateDelegate( ei.EventHandlerType, this, thisMi );
Delegate onLoadD = Delegate.CreateDelegate( ei.EventHandlerType, this, onLoadMi );
Delegate offLoadD = Delegate.CreateDelegate( ei.EventHandlerType, this, offLoadmi);
 
각각 d 는 기존의 Click Event 이고, onLoadD, offLoadD 는 Loading.. 메시지를 보여주고, 없애는 delegate 가 됩니다.
 
이벤트는 += 와 -= 연산을 통해 추가, 또는 삭제할 수 있습니다. 이것을 리플랙션에서 RemoveEventHandler 메서드를 통해 구현할 수 있습니다.
ei.RemoveEventHandler( button1, d );
여기까지 샘플을 실행하게 되면 이미 Event 가 연결되어 있음에도 불구하고, 더 이상 Click 이벤트가 발생하지 않게 됩니다.
 
그럼 다음과 같이 AddEventHandler 메서드를 사용하여 delegate 를 추가합니다.
ei.AddEventHandler( button1, onLoadD );
ei.AddEventHandler( button1, d );
ei.AddEventHandler( button1, offLoadD );
우리는 Button_Click Event 를 제거한 상태입니다. 즉, 아무 반응이 없어 지지요.
Event 는 += 연산을 통해 여러 개의 delegate 를 추가할 수 있습니다.
바로 그것입니다.
Click 이벤트를 제거한 후 On Loding Event -> Click Event -> Off Loading Event 가 발생하도록 Event 를 조작하게 되었습니다.
 
그렇게 많은 라인을 추가하지 않았음에도, 리플랙션을 통해 이벤트를 조작함으로써 해결하였네요^^
 
대부분의 사람들은 “리플랙션” 이라고 하면 느리다고 합니다. 몇몇 사람들은 리플랙션 코드를 보는 순간, “느려집니다” 라고 단언합니다.
리플랙션을 사용하면 최대 1000배의 성능저하가 있다고 들은바 있습니다. 하지만 그것은 Invoke 를 하였을 때의 이야기 입니다.

하지만, Late-Binding 이므로 분명 눈에보이지는 않지만 성능저하는 있을 수 있습니다.
이것을 어떻게 적절히 사용하느냐가 문제인 것 같습니다. 분명 리플랙션은 OOP 의 상속성과 객체지향성을 거스르고, 퍼포먼스를 떨어 뜰일 수 있을테니까요.
 
오늘도, 내일도.. 바쁘시더라도 모두 좋은 하루 되시길 바랍니다. ^^
Posted by 땡초 POWERUMC

댓글을 달아 주세요

오늘은 비동기 ADO.NET 을 알아볼까 합니다.
아티클을 이해하기 위해서는 비동기 호출에 대한 지식이 약간 필요합니다.
 
우리는 다음과 같은 시간이 오래 걸리는 쿼리를 날릴것입니다.
WAITFOR DELAY '00:00:03'; SELECT * FROM Titles
WAITFOR DELAY '00:00:05'; SELECT * FROM Titles
WAITFOR DELAY '00:00:10'; SELECT * FROM Titles
 
위의 WAITFOR DELAY 는 명령문이 암시하듯 이유없는 대기를 하라는 명령입니다.
3초후에 SELECT, 5초후에 SELECT, 10초후에 SELECT 쿼리를 날려 시간이 오래걸리는 작업을 대체하기 위해서 이지요~
 
다음의 쿼리를 쿼리분석기를 통해 실행시켜 보겠습니다.
 
예상대로 18초가 걸리는군요~
하나하나의 쿼리가 종료해야만이 다음 쿼리를 실행할 수 있죠~
이런방식을 동기 방식이라고 합니다.
C# lock 과 같은 키워드가 여러 개의 쓰레드의 요청이 있더라도, 마치 일렬로 줄을 세워 한번에 하나씩 처리하는 것과 비슷하다고 생각하시면 됩니다.
 
그렇다면, 위의 쿼리를 비동기 방식으로 호출하였을 때 어떤 결과가 나올까요?
그럼, 그 의문을 하나하나씩 풀어보기로 합니다.
 
우선 전체 소스를 보면서 비밀을 하나하나씩 파헤쳐 보겠습니다.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
 
namespace ConsoleTest
{
         class Program
         {
                  // 비동기로연결하기위해Asynchronous Processing 를true 로설정해놓은커넥션Connection String
                  public static string GetConnection
                  {
                           get
                           {
                                   return "Asynchronous Processing=true;server=localhost;database=pubs;uid=sa;password=xxxx";
                           }
                  }
 
                  static void Main(string[] args)
                  {
                           SqlConnection cn1 = new SqlConnection( GetConnection );
                           SqlConnection cn2 = new SqlConnection( GetConnection );
                           SqlConnection cn3 = new SqlConnection( GetConnection );
 
                           SqlCommand cmd1            = new SqlCommand("WAITFOR DELAY '00:00:03'; SELECT * FROM Titles", cn1);
                           SqlCommand cmd2            = new SqlCommand("WAITFOR DELAY '00:00:05'; SELECT * FROM Titles", cn2);
                           SqlCommand cmd3            = new SqlCommand("WAITFOR DELAY '00:00:10'; SELECT * FROM Titles", cn3);
 
                           cn1.Open();
                           cn2.Open();
                           cn3.Open();
 
                           // DataAccess 시작시간을기록한다.
                           DateTime startDate = DateTime.Now;
 
                           // 비동기작업을시작한다.
                           IAsyncResult result1       = cmd1.BeginExecuteReader();
                           IAsyncResult result2       = cmd2.BeginExecuteReader();
                           IAsyncResult result3       = cmd3.BeginExecuteReader();
 
                           WaitHandle[] waitHandle    = new WaitHandle[3];
                           string[] resultStr                 = new string[3];
 
                           waitHandle[0]                      = result1.AsyncWaitHandle;
                           waitHandle[1]                      = result2.AsyncWaitHandle;
                           waitHandle[2]                      = result3.AsyncWaitHandle;
 
                           for (int i = 0; i < waitHandle.Length; i++)
                           {
                               // 배열의핸들이모두신호를받을때까지기다립니다.
                               int endIndex           = WaitHandle.WaitAny( waitHandle, 20000, false );
 
                               switch (endIndex)
                               {
                                   case 0:
                                       cmd1.EndExecuteReader(result1);
                                       resultStr[0]   = DateTime.Now.ToString();
                                       break;
                                   case 1:
                                       cmd2.EndExecuteReader(result2);
                                       resultStr[1]   = DateTime.Now.ToString();
                                       break;
                                   case 2:
                                       cmd3.EndExecuteReader(result3);
                                       resultStr[2]   = DateTime.Now.ToString();
                                       break;
                               }
                           }
 
 
                           cn1.Close();
                           cn2.Close();
                           cn3.Close();
 
                           // DataAccess 작업완료시간을기록한다.
                           DateTime endDate = DateTime.Now;
 
                           for( int i=0; i<resultStr.Length;i++)
                                   Console.WriteLine( " Result {0} : {1}", i, resultStr[i] );
 
 
                           // 두시간의시간차를구하여출력한다.
                           TimeSpan timeSpan = endDate - startDate;
 
                           Console.WriteLine("총작업시간은: {0}", timeSpan.ToString() );
                  }
         }
}
 
 
우선 가장 눈에 띄게 차이 나는 것이 ConnectionString 입니다.
Asynchronous Processing=true;server=localhost;database=pubs;uid=sa;password=xxxx
Asynchronous Processing=true는 비동기로 DataBase 에 연결하기 위해 반드시 추가해 주어야 합니다.
 
또한 비동기 데이터베이스 작업을 하기 위해 SqlCommand 클래스는 세가지의 비동기 메서드가 존재합니다.
대부분의 비동기 메서드들이 Begin 으로 시작하는 네이밍을 갖는 것과 마찬가지로, BeginExecuteNonQuery(), BeginExecuteReader(), BeginExecuteXmlReader()가 바로 그것입니다.
이 메서드는 각각 EndExecuteNonQuery(), EndExecuteReader(), EndExecuteXmlReader() 가 호출됨으로써 비로서 비동기 작업의 콜백을 받을 수 있습니다.
위의 경우는 구현되지 않았지만, DataReader 의 경우 콜백이 완료된 후가 되어야지만 비로서 Read 작업을 수행할 수 있는것입니다. 물론 다른 비동기 메서드로 마찬가지입니다.
 
이 구문은 비동기 ADO.NET 작업의 가장 중요한 부분입니다.
waitHandle[0]                      = result1.AsyncWaitHandle;
waitHandle[1]                      = result2.AsyncWaitHandle;
waitHandle[2]                      = result3.AsyncWaitHandle;
WaitHandle.WaitAny( waitHandle, 20000, false );
 
우리는 waitHandler 배열에 비동기 작업이 끝나는데 사용되는 AsyncWaitHandle 를 넣었습니다.
AsyncWaitHandler 는 비동기 작업이 끝나기를 기다리는 핸들러 입니다.
물론 WaitAny 메서드의 3가지 Overload 는 모두 첫번째 인자를 배열로만 받습니다.
WaitWay 메서드는 우리가 넣은 배열의 요소중에 먼저 끝낸 배열의 Index 를 return 합니다.
waitHandler[2] 의 작업이 제일 먼저 끝나게 되면 배열의 인덱스인 2 를 리턴하게 됩니다.
만약 짧은 시간동안 어느 작업도 끝나지 않게 되면, WaitAny 는 두번째 인자에 적은 시간(밀리초)만큼 무한 대기 하게 됩니다.
 
배열에 개수만큼 루프를 돌면서, 비동기 작업이 끝나는 순서대로 SqlCommand 의 작업을 하게 됩니다.
때문에 결과 화면의 DateTime.Now 의 시간은 각각 달라질 수 있는 것입니다.
 
그럼 실행화면을 보겠습니다.
 
보는대로 총 소요시간은 10초가 되었습니다.
위의 동기작업의 쿼리 수행 결과보다 훨씬~ 빨라졌지요?
각가 쿼리 수행이 완료된 시간도 한번 눈여겨 볼만 하네요~
 
긴 시간이 소요되는 작업이나 여러 번 반복적으로 실행되야 하는 작업등에 적용해 보면 상당히 만족할만할 결과가 아닐 수 없네요~
물론 ASP.NET 의 웹 환경에서도 적용이 가능합니다.
 
그럼 이것으로 오늘 강좌 마칩니다. 뱌뱌 ^^//
Posted by 땡초 POWERUMC

댓글을 달아 주세요

처음 데브피아에 활동왕 시스템이 적용되면서 난 활동왕이 되려고 무쟈무쟈 노력했다.
반짝 반짝 거리던 활동왕 메달 아이콘이 너무 탐스러워 보였던 것이다.
현재 데브피아의 활동 레벨 등급이다

r

처음 Bit 에서 시작해서 Master(활동왕) 이 되려고 나름 무쟈~ 노력했던 사람이다.
ZB 에서 Master 등급으로 올라가기까지 거의 매일같이 데브피아에 답변 수개씩 달아서 약 2~3달 만에
드디어 Master 로 등업될 수 있었다.
그리곤 매달 활동점수를 바탕으로 선물을 주는 제도가 도입된 것이다.
그래서 받았던 선물은, 지금까지 짱박아놓고 있는 모아진 전자잡지 구매권이다.
무려 34,050 원의 쿠폰이 적립되어 있다.



이것으로 딱한번 2006년 5월호 마이크로소프트를 구입해 보았다.
하지만 전자잡지는 불편했다.. 봐도 보는것 같지도 않고, 수백페이지가 되는 잡지를 마우스 스크롤로 넘기는 것 자체부터
노가다 였다.

이번에 담청 결과 넉달치가 무려 한번에 공개되었다.

2006년 12월


2007년 2월


2007년 3월


아싸!! ThinkWise 10 카피가 걸렸네~~ ㅋ
근데 ThinkWise 가 뭐지??
네이버에 검색해봤는데, 뭐하는 프로그램인지 아직 잘 모르겠다.. >.,<

근데 4월 5일까지 실수령지 주소가 다를경우 이메일로 주소를 보내지 않을경우 제외 대상이 될 수 있다는 것이다.!!!
지금 4월 9일인데.. 나 이 공지사항 오늘 첨 봤거덩!!
좀 봐주라~~ ㅠ
담청 여부가 이메일로도 안오구~ 넉달치 결과가 나올줄 알았으면 진작 메일 보냈쥐!!
간만에 괜찮은 경품 걸린것 같은데.. 이게 왠 날벼락 -_-

개인적으로 웹켐이 갖고 싶었는데, ThinkWise 라도.. 주는대로 받아야징 ㅠ 
정말 제외 대상이 되면 나 어쩌지 ㅠ

Posted by 땡초 POWERUMC

댓글을 달아 주세요

기본적으로 웹폼을 생성하면 확장자는 ASPX 가 됩니다.
이와 달리 JSP 나 ASP 로 개발된 웹페이지는 여러확장자를 쓸 수 있지요.
가령 .html, .do, 등등.. 하지만 닷넷의 웹폼에선 확장자를 바꾸면 페이지가 동작하지 않습니다.
악의적인 목적으로 게시판이나 자료실 등 ASP 등으로 작성된 페이지를 업로드 하여, 다운로드 경로로 접근하여 페이지를 실행시킬 경우, 보안에 상당히 취약한 부분도 있었습니다.
하지만 언제나 .ASPX 확장자는 이제 식상할 때가 되지 않았습니까!
그럼 어디한번 바꾸어 봅시다.
 
우선 원하는 확장자를 IIS 에서 확장자 매핑 시키고 web.config 의 httpHandlers 에 등록해 보겠습니다.
여기에선 .umcx 라는 확장자를 사용하기로 합니다.
 
 
그다음은 web.config 의 httpHandlers 섹션에 다음과 같이 작성합니다.
<httpHandlers>
         <add path="*.umcx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="true" />
</httpHandlers>
 
여기에서 위의 Type 에 등록된 클래스를 조금 짚고 넘어 가겠습니다.
PageHandlerFactory 는 IHttpHandlerFactory 를 구현한 클래스 입니다.
이 인터페이스는 IHttpHandler 를 리턴하는 GetHandler 메서드를 구현하기만 하면 됩니다.
public IHttpHandler GetHandler(HttpContext context,
        string requestType, String url, String pathTranslated)
 
이 인터페이스를 구현한 클래스를 web.config 의 httpHandlers 에 등록하게 되면 좀더 유연하게 가령, 요청이 get , post 방식에 따라 서로 다른 HttpHandler 를 반환 할 수 있습니다.
IIS 에서 확장자 매핑하면서 get,post 등 요청 방식을 지정할 수 있게 되어있습니다.
하지만 위 인터페이스를 활용하여 요청방식에 따른 각기 기능을 하나의 클래스에 넣을 수 도 있구요, 페이지 요청 방식에 따라 서로 상이한 페이지를 보여 줄 수 도 있습니다.
다음 기회 언젠가 좀 더 자세히 파 보도록 하겠습니다.
 
다시 원점으로 돌아와서,
하지만 이것만으로 끝이 아니랍니다.
우라가 작성한 페이지를 컴파일하고 컴파일 하는 동안 코드를 생성하는데 사용되는 빌드 공급자를 정의해 주어야 합니다.
 
이것또한 최상위 web.config 에 다음과 같이 정의되어 있지요
<buildProviders>
        <add extension=".aspx" type="System.Web.Compilation.PageBuildProvider" />
        <add extension=".ascx" type="System.Web.Compilation.UserControlBuildProvider" />
        <add extension=".master" type="System.Web.Compilation.MasterPageBuildProvider" />
        <add extension=".asmx" type="System.Web.Compilation.WebServiceBuildProvider" />
        <add extension=".ashx" type="System.Web.Compilation.WebHandlerBuildProvider" />
        <add extension=".soap" type="System.Web.Compilation.WebServiceBuildProvider" />
        <add extension=".resx" type="System.Web.Compilation.ResXBuildProvider" />
        <add extension=".resources" type="System.Web.Compilation.ResourcesBuildProvider" />
        <add extension=".wsdl" type="System.Web.Compilation.WsdlBuildProvider" />
        <add extension=".xsd" type="System.Web.Compilation.XsdBuildProvider" />
        <add extension=".js" type="System.Web.Compilation.ForceCopyBuildProvider" />
        <add extension=".lic" type="System.Web.Compilation.IgnoreFileBuildProvider" />
        <add extension=".licx" type="System.Web.Compilation.IgnoreFileBuildProvider" />
        <add extension=".exclude" type="System.Web.Compilation.IgnoreFileBuildProvider" />
        <add extension=".refresh" type="System.Web.Compilation.IgnoreFileBuildProvider" />
</buildProviders>
자주 보던 확장자들이 많이 있지요?
 
<compilation>
</compilation>
Web.config 의 위 섹션이 응용 프로그램의 컴파일을 담당하는 섹션입니다.
우리가 웹사이트를 작성하고 이후 수정된 사항을 복사만 하더라도 컴파일 되어 자동으로 적용되어 지는 미리 컴파일 기능 또한 위 섹션에서 담당하게 되지요~
 
이제 감이 오셨나요?
그럼 우리가 만든 페이지가 컴파일 되도록 하기 위해선 다음과 같이 섹션을 추가해 줍니다
<compilation debug="false">
         <buildProviders>
                  <add extension=".umcx" type="System.Web.Compilation.PageBuildProvider" />
         </buildProviders>
</compilation>
 
이제 모든 설정이 끝났습니다.
 
// 2009-06-20 아래의 주소는 더이상 접속할 수 없습니다.
자신이 만든 웹페이지의 확장자를 .umcx 로 바꾸어 보십시오.
위 예제 페이지는 제 블로그의 접속 차단 IP 를 위해 작성한 페이지 입니다.
 
실행결과
 
 
이번 한 주도 행운만이 가득한 한 주가 되세요~ ^^//

Posted by 땡초 POWERUMC

댓글을 달아 주세요

요즘은 시간이 많아서 그런지 자주 강좌를 올리네요 ㅋㅋ



 

이번에는 웹사이트의 핵심인 Core(코어) 모듈을 구성해 보는 시간을 가져봅니다.





잘 구성된 모듈은 안정된 시스템 그리고 코딩의 작업 속도와 바로 직결됩니다. 





모듈의 구성 방법은 개발자마다, 그리고 시스템 마다 각이 각색이겠지만, 






오늘 구성해 볼 모듈은 대부분의 웹사이트에서 적용할 수 있는 코어 구성 첫 번째




시간을 갖도록 합니다.
 




본 강의는 객체지향적인 문법을 공부하거나 소화한 분을 대상으로 합니다.
 





우리가 구성할 코어는 XML 로 구성된 사이트 맵이 필요합니다.



 
<?xmlversion="1.0"encoding="utf-8" ?>
<AdminID="ADMIN1" Path="WebAdmin">
    <Title>블로그 관리자</Title>
    <ModuleGroupID="MG1" Path="01Blog">
        <Title>기본 설정 관리</Title>
        <ModuleID="UBI1"ViewControl="/WebAdmin/01Blog/BlogBaseInfo.ascx">
            <Title>블로그 기본 정보</Title>
            <InitParams>
                <ParamName="umc">Umc</Param>
                <ParamName="umc1">Umc1</Param>
            </InitParams>
        </Module>
        <ModuleID="UBI2"ViewControl="/WebAdmin/01Blog/ProfileInfo.ascx">
            <Title>프로필 기본정보 관리</Title>
        </Module>
    </ModuleGroup>
    <ModuleGroupID="MG2"Path="02Privacy">
        <Title>프라이버시 관리</Title>
        <ModuleID="UP1"ViewControl="/WebAdmin/02Privacy/Privacy.ascx">
            <Title>프라이버시 관리</Title>
        </Module>
    </ModuleGroup>
    <ModuleGroupID="MG3"Path="02Bbs">
        <Title>게시판 관리자</Title>
        <ModuleID="Bbs1"ViewControl="/WebAdmin/02Privacy/Privacy.ascx">
            <Title>자유게시판</Title>
            <InitParams>
                <ParamName="BoardNo">1</Param>
                <ParamName="Template.Bbs.List">/WebAdmin/02Bbs/ListTemplate.ascx</Param>
                <ParamName="Template.Bbs.Write">/WebAdmin/02Bbs/WriteTemplate.ascx</Param>
                <ParamName="Template.Bbs.View">/WebAdmin/02Bbs/ViewTemplate.ascx</Param>
            </InitParams>
        </Module>
    </ModuleGroup>
</Admin>




ModuleGruop
섹션은 여러 개의 Module 로 구성되어 있습니다. 이 사이트맵을 기준으로






메뉴 컨트롤을 만들때나 이 Module의 부모가 누구인지가 필요할 때 유용합니다.




Module
섹션은 ViewControl 이라는 속성이 있습니다. 사용자 정의 콘트롤로 만들어진





이 컨트롤은 PageTemplate.ascx 이라는 마스터페이지와 같은 역할을 하는 PageTemplate의





PlaceHolder
컨트롤에 들어가게 될것입니다.




Module
섹션안에는 InitParams 라는 섹션이 또 존재하게 되는데,예를 들어 QueryString으로




넘겨야할 BoardNo 등의 파라메터들을 여기에 모두다 집어 넣을 수 있습니다.
 



이제 이 XML 을 사이트에 이용할 수 있도록 Parsing 해야 합니다.




로직은 “C# 디자인 패턴” 책의 Composite 패턴을 확장해 보았습니다. Composite 패턴에




대한 선수 학습이 필요합니다.





 
먼저 ISitemap 이라는 Interface를 만들어 보겠습니다.
namespace Umc.Core.WebAdmin.Sitemap
{
         public interface ISitemap
         {
                  string ID { get; set; }
                  string Path { get; set; }
                  string Title { get; set; }
                  string ViewControl { get; set; }
                  int Count { get; }
                  IEnumerator GetEnumerator();
                  ISitemap Parent { get; }
                  void Add(ISitemap sitemap);
                  bool HasChild { get; }
                  void ReadXml(XmlReader reader);
         }
}
 



Sitemap
에 필요한 모든 클래스는 위 Interface를 상속 받게 되고 가장 핵심이 되는




ReadXml
메서드가 바로 XML 을 해독하게 될 것입니다.




 
이 Interface는 SitemapModule가 상속받습니다.


namespace Umc.Core.WebAdmin.Sitemap
{
         public class SItemapModule : ISitemap
         {
                  protected ArrayList sitemap;
                  protected ISitemap parent;
                  protected string _id;
                  protected string _path;
                  protected string _title;
 
                  // InitParams 섹션
                  protected StringDictionary _initParam = new StringDictionary();
 
                  public SItemapModule(ISitemap _parent)
                  {
                           this.parent       = _parent;
                           this.sitemap      = new ArrayList();
                  }
                  #region ISitemap 멤버
 
                  public string ID
                  {
                           get { return _id; }
                           set { _id = value; }
                  }
 
                  public string Path
                  {
                           get { return _path; }
                           set { _path = value; }
                  }
 
                  public string Title
                  {
                           get { return _title; }
                           set { _title = value; }
                  }
 
                  public virtual string ViewControl
                  {
                           get { return null; }
                           set { throw new Exception("The method or operation is not implemented."); }
                  }
 
                  public int Count
                  {
                           get { return sitemap.Count; }
                  }
 
                  public System.Collections.IEnumerator GetEnumerator()
                  {
                           return sitemap.GetEnumerator();
                  }
 
                  public ISitemap Parent
                  {
                           get { return this.parent; }
                  }
 
                  public virtual void Add(ISitemap sitemap)
                  {
                           this.sitemap.Add( sitemap );
                  }
 
                  public bool HasChild
                  {
                           get { return sitemap.Count>0; }
                  }
 
                  public virtual void ReadXml(XmlReader reader)
                  {
                           throw new Exception("The method or operation is not implemented.");
                  }
                  #endregion
 
                  public void ReadInitParams(XmlReader reader)
                  {
                           while (reader.Read())
                           {
                                   if(reader.IsEmptyElement) return;
 
                                   if (reader.NodeType == XmlNodeType.Element)
                                   {
                                            if (reader.Name == Sitemap.NODE_PARAM)
                                            {
                                                     string _key       = reader["Name"];
                                                     string _value     = reader.ReadElementString();
                                                     _initParam.Add( _key, _value );
                                            }
                                   }
                                   if(reader.Name==Sitemap.NODE_INIT_PARAMS &&
                                            reader.NodeType==XmlNodeType.EndElement)
                                            return;
                           }
                  }
 
                  public StringDictionary GetInitParam
                  {
                           get { return _initParam; }
                  }
         }
}




기본이 되는 각각 메서드와 프로퍼티의 역할을 정의해 놓았습니다. 각각 쓰임새에 따라





특히 ReadXml 은 virtual 로 선언된 것을 볼 수 있습니다.





이 클래스는 각각 섹션을 처리할 클래스들의 뼈다가 되는 클래스로, 다음과 같은




다이어그램을 볼 수 있습니다.
 





 



차례대로 Sitemap 클래스부터 살펴보겠습니다.



public class Sitemap : SItemapModule
         {
                  public const string NODE_ADMIN              = "Admin";
                  public const string NODE_MODULE_GROUP      = "ModuleGroup";
                  public const string NODE_MODULE             = "Module";
                  public const string NODE_INIT_PARAMS       = "InitParams";
                  public const string NODE_PARAM              = "Param";
                  public const string NODE_TITLE              = "Title";
 
                  public Sitemap(ISitemap _parent)
                           : base(_parent)
                  {
                  }
                  public Sitemap() : base(null)
                  {
                  }
 
                  public override void Add(ISitemap _sitemap)
                  {
                           sitemap.Add( _sitemap );
                  }
 
                  public override void ReadXml(XmlReader reader)
                  {
                           while (reader.Read())
                           {
                                   if (reader.NodeType == XmlNodeType.Element)
                                   {
                                            if (reader.Name == NODE_ADMIN)
                                            {
                                                     this.ID = reader["ID"];
                                                     this.Path         = reader["Path"];
                                            }
                                            if (reader.Name == NODE_TITLE)
                                            {
                                                     this.Title        = reader.ReadElementString();
                                            }
                                            if (reader.Name == NODE_MODULE_GROUP)
                                            {
                                                     ModuleGroup moduleGroup = new ModuleGroup(this);
                                                     moduleGroup.ID = reader["ID"];
                                                     moduleGroup.Path = reader["Path"];
                                                     moduleGroup.ReadXml(reader);
 
                                                     this.Add(moduleGroup);
                                            }
                                   }
                                   if(reader.Name==NODE_ADMIN &&
                                            reader.NodeType==XmlNodeType.EndElement)
                                            break;
                           }
                  }
 
                  public static ISitemap ReadSitemap(string path)
                  {
                           XmlTextReader reader       = null;
                           try
                           {
                                   reader            = new XmlTextReader(path);
                                   ISitemap root     = new Sitemap();
 
                                   root.ReadXml( reader );
 
                                   return root;
                           }
                           catch(Exception ex)
                           {
                                   throw ex;
                           }
                           finally
                           {
                                   reader.Close();
                           }
                  }
         }




ReadSitemap
이라는 static 클래스가 시발점으로 각각의 노드를 탐색 할 수 있습니다.




클래스의 상단에는 XML 의 섹션들을 상수로 정의 해 놓았습니다.





ISitemap root = new Sitemap()
과 같이 최상단의 부모는 Null 이라는걸 알 수 있습니다.




ModuleGroup moduleGroup = new ModuleGroup(this);
구문이 의아해 하실겁니다.




XML
의 ModuleGroup 섹션을 만나면 ModuleGroup 내의 요소들을 처리할 또 다른 처리기가





필요합니다. 여기의 this 인자는 ModuleGroup 내에서는 이 this 가 부모 클래스가 되는




것입니다.
 
public class ModuleGroup : SItemapModule
         {
                  public ModuleGroup(ISitemap _parent)
                           : base(_parent)
                  {
                  }
 
                  public override void ReadXml(System.Xml.XmlReader reader)
                  {
                           int depth         = reader.Depth;
 
                           while (reader.Read())
                           {
                                   if (reader.NodeType == XmlNodeType.Element)
                                   {
                                            if (reader.Name == Sitemap.NODE_TITLE)
                                            {
                                                     this.Title        = reader.ReadElementString();
                                            }
                                            if (reader.Name == Sitemap.NODE_MODULE)
                                            {
                                                     ModuleInfo moduleInfo      = new ModuleInfo(this);
                                                     moduleInfo.ID              = reader["ID"];
                                                     moduleInfo.ViewControl     = reader["ViewControl"];
                                                     moduleInfo.ReadXml( reader );
 
                                                     this.Add(moduleInfo);
                                            }
                                   }
                                   if(reader.Depth <= depth ) return;
                           }
                  }
         }




여기도 별반 다를게 없네요~






ModuleGroup
을 탐색하다 Module 섹션을 만나면 this 클래스를 인자로 ModuleInfo




클래스에게 탐색을 넘깁니다.



 
public class ModuleInfo : SItemapModule
         {
                  private string _viewControl                 = null;
                  public ModuleInfo(ISitemap _parent)
                           : base(_parent)
                  {
                  }
 
                  public override string ViewControl
                  {
                           get { return _viewControl; }
                           set { _viewControl = value; }
                  }
 
                  public override void ReadXml(XmlReader reader)
                  {
                           int depth         = reader.Depth;
 
                           while (reader.Read())
                           {
                                   if (reader.NodeType == XmlNodeType.Element)
                                   {
                                            if (reader.Name == Sitemap.NODE_TITLE)
                                            {
                                                     this.Title        = reader.ReadElementString();
                                            }
                                            if (reader.Name == Sitemap.NODE_INIT_PARAMS)
                                            {
                                                     ReadInitParams( reader );
                                            }
                                   }
 
                                   if(reader.Name==Sitemap.NODE_MODULE &&
                                            reader.NodeType==XmlNodeType.EndElement)
                                            return;
                           }
                  }
         }




ViewControl
은 Module 섹션이 갖는 Attribute 이므로 여기에서 override 되었습니다.




그리고 ReadInitParams() 는 이미 부모 클래스에서 정의 해 놓았습니다.
 




이제 이 클래스를 통제시키는 SitemapManager 를 살펴봅니다.



public class SitemapManager
         {
                  private static SitemapManager _instance              = null;
                  private ISitemap _sitemap;
 
                  public ISitemap SiteInfo
                  {
                           get { return _sitemap; }
                  }
 
                  private SitemapManager()
                  {
                  }
 
                  public static SitemapManager GetInstance()
                  {
                           lock (typeof(SitemapManager))
                           {
                                   if (_instance == null)
                                   {
                                            _instance = new SitemapManager();
                                            _instance.Init();
                                   }
                           }
 
                           return _instance;
                  }
 
                  public void Init()
                  {
                           ReConfig();
                           string path       = Utility.GetAbsolutePath( Umc.Core.UmcConfiguration.Core["AdminXmlPath"]);
                           _sitemap          = Sitemap.ReadSitemap(path);
                  }
 
                  public void ReConfig()
                  {
                           _sitemap          = null;
                  }
 
                  public string GetNavigateString(ISitemap _map)
                  {
                           ISitemap _tempSitemap      = _map;
                           StringBuilder naviString   = new StringBuilder();
 
                           naviString.Insert(0, _tempSitemap.Title);
 
                           while (_tempSitemap.Parent != null)
                           {
                                   naviString.Insert(0, _tempSitemap.Parent.Title + " > " );
                                   _tempSitemap      = _tempSitemap.Parent;
                           }
 
                           return naviString.ToString();
                  }




여기에서 Singleton 패턴이 사용되었습니다.




생성자가 private 로 선언되어있습니다. 이 객체를 접근 하기 위해서 GetInstance() 라는




단 한 개의 통로만 열려있습니다.





이로 인한 이점은 객체의 정보를 소멸 시키지 않고 언제든 참조할 수 있습니다.




때문에 언제 어디서든 SiteInfo 프로퍼티를 호출하면 사이트맵의 정보를 다시 읽지 않고




고스란이 참조 할 수 있게 되는것입니다.




또한, GetNavigateString(ISitemap _map) 으로 부모의 Sitemap 까지 찾아 올라가




네비게이트 문자열을 뽑아 낼 수 있습니다.

 



여기의 Init는 언제 호출 될 것이냐가 의문이네요… 간단합니다..




Global.asax
에 첫 어플케이션이 시작될 때 초기화 되면 됩니다.



private SitemapManager _sitemapManager   = null;
        
    void Application_Start(object sender, EventArgs e)
    {
         _sitemapManager            = SitemapManager.GetInstance();
    }
 




이제 이 Sitemap 이 TreeView 컨트롤에 바인딩 될 수 있도록 Sitemap_Node 클래스를






만들어봅니다.



public class Sitemap_Node : System.Web.UI.WebControls.TreeNode
         {
                  ISitemap sitemap;
 
                  public Sitemap_Node(ISitemap _sitemap)
                           : base(_sitemap.Title)
                  {
                           this.sitemap               = _sitemap;
                           base.Value                 = _sitemap.ID;
                  }
 
                  public ISitemap Sitemap
                  {
                           get { return sitemap; }
                  }
         }




이와 같이 TreeView 에 Sitemap의 Title 프로퍼티가 바인딩 되고, TreeView의 Value 에는




Sitemap.ID
가 바인딩 됩니다.
 




그럼 우리가 구성한 Sitemap 은 TreeView 컨트롤과 거의 흡사한 형식으로 메모리에




저장됩니다. Sitemap 은 지금 내가 누구인지, 내 부모가 누구인지, 그리고 Root 가 



누구인지 까지 알아낼 수 있습니다.




 
마지막으로 재귀호출을 이용하여 TreeView 컨트롤에 Sitemap 노드들을 바인딩 해봅니다.



public partial class WebAdmin_Default : Umc.Core.WebAdmin.WebAdminTemplate
{
         private ISitemap sitemap;
         protected void Page_Load(object sender, EventArgs e)
         {
                  // Postback 또는 UpdatePanel 안의 클릭후 Sitemap_Node 로 캐스팅이 안되므로
                  // 매번 다시 바인딩
                  BuildTree();
         }
 
         private void BuildTree()
         {
                  treeMenu.Nodes.Clear();
                  sitemap = SitemapManager.GetInstance().SiteInfo;
                  Sitemap_Node node = new Sitemap_Node(sitemap);
 
                  treeMenu.Nodes.Add(node);
 
                  AddNodes(sitemap, node);
 
                  treeMenu.ExpandAll();
         }
 
         private void AddNodes(ISitemap sitemap, Sitemap_Node node)
         {
                  IEnumerator currentSitemap = sitemap.GetEnumerator();
 
                  while (currentSitemap.MoveNext())
                  {
                           ISitemap newSitemap                = (ISitemap)currentSitemap.Current;
                           Sitemap_Node newNode       = new Sitemap_Node(newSitemap);
                           node.ChildNodes.Add( newNode );
                           AddNodes( newSitemap, newNode );
                  }
         }
         protected void treeMenu_SelectedNodeChanged(object sender, EventArgs e)
         {
                  ISitemap _sitemap = (ISitemap)((Sitemap_Node)treeMenu.SelectedNode).Sitemap;
 
                  lblNavigate.Text = SitemapManager.GetInstance().GetNavigateString(_sitemap);
 
                  CurrentSitemapInfo         = _sitemap;
 
                  if (_sitemap.ViewControl != null)
                  {
                           Control template = LoadControl(_sitemap.ViewControl);
                           MainPlace.Controls.Clear();
                           MainPlace.Controls.Add(template);
                  }
         }
}
 









실행결과 화면은 다음과 같습니다.







이런 방식의 Sitemap 을 구성함으로써 다음과 같은 장점이 있습니다.






1.    
MasterPage 가 필요없음
2.     SiteMap 컨트롤 / SiteMapPath 컨트롤이 필요없음.

3.     불필요한 QueryString 이 필요없음

4.     Menu 컨트롤 등이 필요없음

5.     Sitemap 을 Dom 과 같은 형태로 탐색이 가능

6.     Atlas/Ajax 등을 활용하여 한 페이지로 동적인 사이트가 완성 가능


(사실 뭐좀 준비하고 있어요^^ㅋ)

 


이외에도 많은 장점을 가지고 있지만, 결정적인 단점은 직접 만들어야 한다는거~~ oTL
 




하지만 오늘 구성한 사이트맵이 가장 핵심이 되는 부분이므로, 핵심이 완성된다면 다른




부분은 쉽게 구현 가능 할 것입니다.



 
훔… 내가 쓰고 봐도 재미가 없네요 ㅋ




그럼 다가오는 크리스마스는 행복하게 보내시기 바랍니다^^//







※ UmcBlog 소스 ( http://umc.pe.kr/article_107.aspx ) 관리자 부분을 보시면 위의 패턴으로 구현이 되어있으니, 참고 하시기 바랍니다.


Posted by 땡초 POWERUMC

댓글을 달아 주세요

이번 시간에는 이미지에 워터마크를 찍어보는 시간을 갖겠습니다.
우선 이 내용이 이해가 가지 않는 분은
제네릭처리기를이용하여자동가입방지구현아티클을 선수학습 하세요~
 
오늘 알아볼 내용은 무척이나 간단하답니다.
 
우선 IIS 에서 자신의 웹사이트의 구성으로 가셔서 다음의 “.mark” 확장자를 매핑하세요
 
이제 web.config 의 httpHandlers 섹션에 다음의 구문을 추가해 줍니다
<addverb="*"path="*.mark"type="UmcMarkImageHandler, App_Code"></add>
Type 속성은 클래스이름(네임스페이스부터) 과 DLL 이름으로 구성되어 있습니다.
 
위의 UmcMarkImageHandler 는 IHttpHandler 만 상속받아 작성하시면 됩니다.
 
UmcMarkImageHandler.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
 
///<summary>
/// UmcMarkImageHandler의 요약 설명입니다.
///</summary>
public class UmcMarkImageHandler : IHttpHandler
{
       public UmcMarkImageHandler()
       {
       }
 
       #region IHttpHandler 멤버
       public bool IsReusable
       {
             get
             {
                    return false;
             }
       }
 
       public void ProcessRequest(HttpContext context)
       {
             string filename = context.Request.Path;
             string fn = Path.GetFileName(filename).ToLower();
             string ext = Path.GetExtension(fn);
             // 확장자가 .mark 가 아니라면 걍 이미지를 뿌려준다.
             if (!(ext == ".mark"))
             {
                    System.Drawing.Image nonImg = System.Drawing.Image.FromFile(context.Server.MapPath(filename));
 
                    nonImg.Save(context.Response.OutputStream, ImageFormat.Jpeg);
 
                    nonImg.Dispose();
 
                    return;
             }
 
             // 이미지를 가져와서...
             System.Drawing.Image img = System.Drawing.Image.FromFile(context.Server.MapPath(filename));
             Bitmap bitmap = new Bitmap(img.Width, img.Height);
             Graphics g = Graphics.FromImage(bitmap);
 
             g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
             g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
 
             // 이 이미지는 합성될 이미지 입니다.
             System.Drawing.Image imgText = System.Drawing.Image.FromFile(context.Server.MapPath("mark.gif"));
 
             // 여기서부터 mark.gif 의 마크업 이미지에 투명도를 줘서 합성시킵니다.
             float[][] matrixItems ={
                                    new float[] {1, 0, 0, 0, 0},
                                    new float[] {0, 1, 0, 0, 0},                                      
                                    new float[] {0, 0, 1, 0, 0},
                                    new float[] {0, 0, 0, 0.8f, 0},                                          
                                    new float[] {0, 0, 0, 0, 1}};
             ColorMatrix colorMatrix = new ColorMatrix(matrixItems);
             ImageAttributes imageAtt = new ImageAttributes();
             imageAtt.SetColorMatrix(
                    colorMatrix,
                    ColorMatrixFlag.Default,
                    ColorAdjustType.Bitmap);
             g.DrawImage(imgText,
                    new Rectangle(0, 0, img.Width, img.Height),
                    0,
                    0,
                    imgText.Width,
                    imgText.Height,
                    GraphicsUnit.Pixel,
                    imageAtt);
             g.DrawImage(img,
                    new Rectangle(0, 0, img.Width, img.Height),
                    0,
                    0,
                    img.Width,
                    img.Height,
                    GraphicsUnit.Pixel,
                    imageAtt);
 
             bitmap.Save(context.Response.OutputStream, ImageFormat.Jpeg);
 
             g.Dispose();
             img.Dispose();
             imgText.Dispose();
             bitmap.Dispose();
       }
       #endregion
}
 
약간 소스가 쬐~~까~~ 긴감이 있네요~
 
여기서 mark.gif 이미지 만드는 법을 알려드리겠습니다.
포토샵에서 원하는 글자를 적으신 후 글자 이외의 배경은 투명하게 만드세요
 
Mark.gif
 
보이는 대로 위 이미지와 합성될 것입니다.
 
MarkImage.aspx
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>제목 없음</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
             두 이미지는 같은 이미지 입니다. 확장자만 바꾼결과 마크 이미지가 생겼습니다.<br>
             <br>
             image.jpg<br>
             <img src="image.jpg" />
             <p />
             image.mark<br>
             <img src="image.mark" />
    </div>
    </form>
</body>
</html>
 
이제 완성이 되었네요~
 
이 예제의 샘플을 보시려면

http://umc.pe.kr/Sample/MarkImage/marksample.umcx


근데 정확히 시간은 재보지 않았지만, 눈에 띄게 합성 속도가 느리더군요~
샘플로 사용된 이미지 자체가 뷁~ 스럽게 큰 이유도 있고,
이미지 출력을 JPG 압축하는 이유도 있겠습니다만..^^; 
한가지 팁… 확장자를 JPEG 또는 JPG 등으로 사용하시면 안됩니다.
브라우져가 먼저 이미지를 뿌려주지 않고, 닷넷이 먼저 확장자에 접근합니다.
 
이부분을 좀더 활용해 보시면 의외로 응용부분이 많을 겁니다^^
 
이런;;
 
다음번에는 이것보다 더 유익한거 하나 알려드릴께요^^
기대하세용~

Posted by 땡초 POWERUMC

댓글을 달아 주세요

ConfirmBitmapHandler.zip



정말 간만에 다시 글을 쓰게 되었네여~
세월아~ 네월아~~
오늘은 자동가입방지, 또는 자동댓글/글쓰기 방지를 위해 뭐좀 하나 만들어 보았습니다.
이번 방법은 제네릭 처리기를 이용하려고 합니다.
우선 다음과 같이 제네릭 처리기를 새항목 추가 합니다.
 
 

제네릭 처리기가 뭘까 해서 MSDN 을 보니…. 안나왔더군요~ ㅋ
우선 제네릭 처리기를 생성해 보기로 하겠습니다.
 
.. 단순히 IHttpHandler 를 상속하였네요~
친절하게도 Hello World 와 함께 말이져~
 
요놈은 IIS 에 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll 과 같이 매핑이 되어있으며, C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\Web.Config 에
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory"
        validate="true" /> 과 같이 핸들러가 등록 되어 있군요~,
 
결론은 IHttpHandler 를 구현하라는 것이네요.
 
그럼 ConfirmBitmapHandler.ashx 의 소스를 보여드립니다.
<%@ WebHandler Language="C#" Class="ConfirmBitmapHandler" %>
 
using System;
using System.Web;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Web.SessionState;
 
public class ConfirmBitmapHandler : IHttpHandler, IRequiresSessionState {
   
    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "image/jpeg";
              
               // 이미지사이즈
               int lenX = 80, lenY = 30;
              
               Bitmap bm              = new Bitmap( lenX, lenY );
              
               Graphics g             = Graphics.FromImage( bm );
              
               // 배경으로그라데이션처리
               LinearGradientBrush bgGr = new LinearGradientBrush(
                       new Point(0,0),
                       new Point(lenX, lenY),
                       Color.Blue,
                       Color.Black);
                             
               g.FillRectangle( bgGr, 0, 0, lenX, lenY );
              
               // 5자리숫자의난수를발생하여텍스트를만든다           
               string text = string.Empty;
               Random rnd = new Random();
               for(int i=0; i<5; i++)
               {
                       text += rnd.Next(9).ToString();
               }
              
               // 텍스트를그린다.
               Brush textBrush        = new SolidBrush( Color.White );
               g.DrawString( text, new Font("굴림", 15), textBrush, 10, 5, StringFormat.GenericDefault );
              
               // 스트림에비트맵을쓴다.
               bm.Save( context.Response.OutputStream, ImageFormat.Jpeg );
              
               // 5자리숫자를세션에담는다.
               context.Session["ValidateString"] = text;
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }
 
}
 
그럼 이제 우리가 만든 ConfirmBitmapHandler.ashx 를 브라우져 보기를 통해 실행해 보십시오
 
실행결과>>>
 
오오~~~~~ 짝짝짝~~ 잘 실행이 되었네여~
 
그럼 다음으로 방금 만든 전처리기를 이용하여 웹어플케이션을 만들어 봅시다.
 
소스 ( Default.aspx )
<%@ Page Language="C#" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<script runat="server">
 
        private void Page_Load(object sender, EventArgs e)
        {
        }
       
        protected void lnkValidate_Click(object sender, EventArgs e)
        {
               string validateString = (string)Session["ValidateString"] ?? string.Empty;
 
               if (txtValidateString.Text == validateString )
                       lblResult.Text = "오케이~~ 통과~!";
               else
                       lblResult.Text = "틀렷삼~~~~~ ";
        }
</script>
<script type="text/javascript">
        function checkEnter()
        {
               if( event.keyCode == 13 )
               {
                       __doPostBack('lnkValidate','');
               }
               else
                       return true;
        }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>제목없음</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
               <img src="ConfirmBitmapHandler.ashx" />
               <p></p>
               <asp:TextBox ID="txtValidateString" runat="server" onkeypress="return checkEnter()"></asp:TextBox>&nbsp;&nbsp;&nbsp;
               <asp:LinkButton ID="lnkValidate" runat="server" OnClick="lnkValidate_Click">확인</asp:LinkButton>
               <p></p>
               <asp:Label ID="lblResult" runat="server"></asp:Label>
    </div>
    </form>
</body>
</html>
 
 
이 소스는 대부분 어렵지 않게 보실 수 있을 것 같아서 특별히 주석은 안달았습니다.
 
 
이것을 이용하여 다음엔 시간나는대로 이미지 도용방지 어플케이션을 작성해 보도록 할게여~
Posted by 땡초 POWERUMC

댓글을 달아 주세요

이 아티클은 Devpia.co.kr 에 제가 답변 등록한 내용입니다...
 


  2006-12-18 오후 9:38:43   /  번호: 4233  / 평점:  (-) category: General Discussions (일반 사항)  /  조회: 35 
 긴급) response.write의 문자열을 압축해서 찍기..  이종민 / mildblue  
이종민님께 메시지 보내기   
이종민님의 블로그 가기   
 response.write("aaaaaaaaaaaa")
했을대.. 실제로 "문자열"이 엄청 많다고 가정하고.
이걸 gzip로 압축된 문자열로 내보내는 명령이 무엇인가요?
 
response.write("aaa")이라고 해서 콘솔에서 웹서버에 연결해 호출해보면 전혀 압축되어 지지  않고 리턴이 됩니다.
 
jsp를 보면
void sendHTML( HttpServletResponse response , String zipHTML ) {        
 
    ServletOutputStream  svrOut = null ;
 
    BufferedOutputStream outStream = null ;
 
    GZIPOutputStream zipStream = null ;            
 
       try {
 
         response.setHeader("Content-Encoding","gzip");  
 
         svrOut = response.getOutputStream();  
 
         outStream =  new BufferedOutputStream( svrOut );           
 
         zipStream = new GZIPOutputStream(  outStream ) ;
 
         byte[] zipHTMLArray = zipHTML.getBytes();
 
         zipStream.write(  zipHTMLArray, 0, zipHTMLArray.length );      
 
         zipStream.flush();   
 
       } catch( Exception writeException ) {
 
         writeException.printStackTrace();
 
       } finally {
 
           try {
 
             if ( zipStream != null ) zipStream.close();         
 
} catch( Exception closeException ) {
 
            closeException.printStackTrace();
 
           }    
 
       }
 
  }
 
해서 압축하여 출력할수가 있는데.. asp.net에는 이렇게 하는 방법이 없는지요?
 
아무리 찾아도... 찾지를 못했습니다...
 
asp.net 2.0에 Imports System.IO.Compression 을 사용하면 되다는데. 이거는 도무지 파일을 압축하는 소스 밖에는 못 찾겠내요..
 
response.write 할때 값을 압출하는 방법을 즉..(text)를 바로 압축하여 string변수에 담을수 있는 방법을 가르쳐 주세요^^
 
이 글에 평점 주기:  
  2006-12-19 오후 5:51:06   /  번호: 4246  / 평점:  (-)  
 [답변]  엄준일 / umjunil  
엄준일님께 메시지 보내기   
엄준일님의 블로그 가기   
저도 첨 보는 클래스라서 연습삼아 해봤습니다. ^^;
 
private void Page_Load(object sender, EventArgs e)
        {
               Response.ContentType   = "gzip";
               Response.AddHeader("Content-Disposition", "attachment;filename=a.zip");
              
               FileStream fs          = new FileStream(@"C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\WebSites\MediaPlayer\intro.jpg", FileMode.Open);
              
               byte[] buffer          = new byte[fs.Length];
               fs.Read( buffer, 0, (int)fs.Length );
              
               fs.Close();
 
               MemoryStream ms               = new MemoryStream();
               GZipStream gs          = new GZipStream(ms, CompressionMode.Compress, true);
               gs.Write( buffer, 0, (int)buffer.Length );
 
 
               Response.Clear();
               Response.BinaryWrite( ms.GetBuffer() );
               Response.End();
              
               gs.Close();
               ms.Close();
        }
 
이런식으로 이미지 파일을 압축하여 a.zip 이라는 파일로 다운 받을 수 있습니다.
 
근데 압축 파일 열어보면 확장자도 없는 a 라는 파일이 달랑 하나 들어가 있는데..
 
이거 확장자를 다시 .jpg 로 바꾸어 주시면 됩니다.
 
위에 AddHeader를 빼시면 압축 내용을 그냥 화면에다가 뿌려줄 수도 있구요....
 
텍스트 압축도 위와 별단 다를거 없다고 생각합니다. 텍스트르 byte 배열로 넣어주시면 되구요
 
( JPG 압축하니 용량이 더 커지네요 ㅋ^^; )
이 글에 평점 주기:  




Posted by 땡초 POWERUMC

댓글을 달아 주세요

 
이번에는 Ajax.Net ( 이하 Ajax ) 이 제시한 두가지 콜백 방법의 차이에 대해서 알아봅시다.
예제에 필요한 DLL 을 다운 받기 위해서 다음의 사이트에서 다운 받으실수 있습니다.
 
다운받은 DLL 을 프로젝트에 참조시킵니다.
 
다음은 Web.Config 파일에 다음의 구문을 추가 합니다.
<system.web>
<httpHandlers>
<addverb="*"path="*.ashx"type="AjaxPro.AjaxHandlerFactory,AjaxPro.2"/>
</httpHandlers>
</system.web>
 
이제 기본 설정은 모두 마쳤습니다.
 
이번에도 여과없이 예제 샘플부터 보도록 하겠습니다.
publicpartialclassAjaxNet : System.Web.UI.Page
{
        protectedvoid Page_Load(object sender, EventArgs e)
        {
               AjaxPro.Utility.RegisterTypeForAjax( typeof(AjaxNet) );
 
               TextBox1.Attributes["OnKeyPress"]    = txtChange1(this)";
               TextBox2.Attributes["OnKeyPress"]    = txtChange2(this)";
        }
 
        [AjaxPro.AjaxMethod]
        publicstring GetMessage()
        {
               System.Threading.Thread.Sleep(1000);
               return"메서드가 호출되었습니다";
        }
} 
 
AjaxPro.Utility.RegisterTypeForAjax( typeof(AjaxNet) ); 의 구문으로 비동기 호출 대상 클래스를 등록할 수 있습니다. This.GetType() 과 같이 지정하신다면 정상적으로 작동되지 않습니다.
 
TextBox1.Attributes["OnKeyPress"]    = "txtChange1(this)";
TextBox2.Attributes["OnKeyPress"]    = "txtChange2(this)";
 
TextBox 에 밑의 html 소스에 포함되는 자바스크립트를 이벤트에 연결합니다.
 
GetMessage() 메서드는 콜백 받기 위한 메서드로 호출되면 1초의 쓰레드 Sleep을 주고 string을 리턴합니다
 
HTML 소스는 다음의 같습니다.
 
<headrunat="server">
    <title>제목 없음</title>
    <scripttype="text/javascript">
               function txtChange1( obj )
               {
                       if( obj.value.length == 9 )
                       {
                              alert( AjaxNet.GetMessage().value );
                       }
               }             
               function txtChange2( obj )
               {
                       if( obj.value.length == 9 || obj.value.length == 10)
                       {
                              AjaxNet.GetMessage(txtChange2_Callback);
                       }
               }             
               function txtChange2_Callback( response )
               {
                       var obj = response.value;
                       if( obj != null && typeof(obj) == "string" )
                       {
                              alert( obj );
                       }
               }
    </script>
</head>
<body>
    <formid="form1"runat="server">
    <div>
               <asp:TextBoxID="TextBox1"runat="server"MaxLength="100"></asp:TextBox>
               <p></p>
               <asp:TextBoxID="TextBox2"runat="server"MaxLength="100"></asp:TextBox>
    </div>
    </form>
</body>
 
 
(OnKeyPress 는 키보드가 눌려지는순간 발생하므로 10번째 텍스트부터 콜백이 일어납니다)
소스가 완성되었다면 각각 텍스트 박스에서 아무 알파벳을 꾸욱 누르고 계셔 보세요.
 
1. AjaxNet.GetMessage().value
 이 메서드가 호출되는 순간 스레가 1초 쉬고, 리턴받은string 을 보여줍니다.
 보시는 바와 같이 콜백이 모두 완료될때까지 클라이언트는 아무 것도 못합니다.
 마치, 컴퓨터가 잠깐 먹통이 된 듯 콜백이 완전히 종료되야 다음 텍스트가 눌러지는
 것을 확인할 수 있습니다.
 
2. AjaxNet.GetMessage(txtChange2_Callback);
 두번째 텍스트 박스의 함수는 Callback 과 매핑되어 있습니다.
 이상하게 1번 방법의 호출과는 상당히 다른 결과를 보여줍니다.
 눈치빠른 분이라면 잠깐 멈찟 하는듯 하나 키보드로 누른 텍스트는 이내 쭈욱 써지는
 것을 확인할 수 있습니다.
 
 
 이렇게 상이한 결과에 대해 많이 궁금하여 여러 문서를 검색해 보았으나, 그 이상의 해답을 찾지 못하였습니다.^^;
추측건데, 2번 경우의 호출은 단지 호출만 할뿐 Callback 에 대해선 txtChange2_Callback에게 위임하게 되고, 1번의 경우 호출과의 매핑된 콜백이 없기 때문에, 콜백이 완료되기 전까지 무한 대기 상태에 빠지는 듯 합니다.
 
다음에 또 기회가 된다면 보안적인 요소가 강화된 AjaxPro 에 추가된 AjaxEnum,AjaxProperty, 캐시,및 세션 다루는 방법에 대해 알아보도록 하겠습니다.
(기회가 된다면… ^^;; )
소스코드 첨부 하였습니다~
 
재미없는 글 읽어주셔서 감사합니다^^//

'.NET > AJAX' 카테고리의 다른 글

Ajax.Net 으로 DataSet 컬렉션 제어하기  (0) 2007.07.08
AJAX 로 구현한 윈도우  (0) 2007.04.06
Ajax.Net 의 두가지 콜백 방법의 차이  (0) 2007.04.05
채팅방 베타  (0) 2007.04.05
Ajax 를 활용한 간단한 채팅 로직  (0) 2007.04.05
Posted by 땡초 POWERUMC

댓글을 달아 주세요



너무 허접하게 만들어서 공개를 할까 말까 많이 망설여 지네여

AJAX이 뭔지 막 접한 분들을 위한 소스이니,

참고만 하세여.. 별 도움 될랑가 몰겟네~~


'.NET > AJAX' 카테고리의 다른 글

Ajax.Net 으로 DataSet 컬렉션 제어하기  (0) 2007.07.08
AJAX 로 구현한 윈도우  (0) 2007.04.06
Ajax.Net 의 두가지 콜백 방법의 차이  (0) 2007.04.05
채팅방 베타  (0) 2007.04.05
Ajax 를 활용한 간단한 채팅 로직  (0) 2007.04.05
Posted by 땡초 POWERUMC

댓글을 달아 주세요