'ASP.NET'에 해당되는 글 40건

  1. 2014.08.11 ubuntu 14.04에서 asp.net vnext 설치하고 사용하기
  2. 2014.08.10 ASP.NET Custom Loader의 원리
  3. 2013.11.16 Visual Studio 2013에서 ASP.NET 프로젝트가 만들어지지 않는 경우
  4. 2013.10.12 ASP.NET을 이용한 이식성 높은 클라우드 서비스 개발하기
  5. 2012.11.01 2012년 11월 Windows Azure 관련 소식 종합
  6. 2012.09.15 Visual Studio 2012 Express 출시 (1)
  7. 2012.08.08 무료 Microsoft eBook 컬렉션 (2)
  8. 2012.04.17 ASP.NET Universal Provider 소개
  9. 2012.02.10 Phalanger와 PHP의 차이점들
  10. 2012.02.08 PHP x C# x VB.NET = ASP.NET
  11. 2011.12.15 jQuery Mobile에 대한 소개
  12. 2011.09.12 ASP.NET과 IIS 7을 위한 로드 밸런싱 전략과 기초적인 이야기, 그리고 Azure Platform
  13. 2011.02.17 DevForce 프레임워크의 Windows Azure 마이그레이션 DEMO 동영상
  14. 2011.01.12 최대 URL 길이에 대한 이야기 (6)
  15. 2011.01.04 [이벤트] Microsoft WebMatrix - 여러분이 Windows로 웹사이트를 만드는 데 필요한 모든 것!
  16. 2010.09.06 [세미나] Visual Studio Seminar #1 / 2010년 9월 28일
  17. 2010.08.19 PDC10 - Developers Developers Developers
  18. 2010.08.10 Hello Windows Azure / Twitter 스타일 방명록 만들기 #2
  19. 2010.07.27 Hello Windows Azure / Twitter 스타일 방명록 만들기 #1
  20. 2010.06.25 taeyo.net 실전 jQuery 세미나 (2010년 7월 10일)
  21. 2010.05.29 .NET Framework 4에서 새로워진 핵심 기술들
  22. 2010.04.18 Windows Azure 들여다보기
  23. 2010.03.11 ASP.NET 웹 사이트를 Windows Azure로 옮기기 #1 - 개요
  24. 2010.03.09 Visual Studio 2010 RC 패치 (KB980610)가 발표되었습니다.
  25. 2010.02.26 강력 추천! Stackoverflow.com
  26. 2010.02.21 Windows Azure 개발: 간단한 방명록 만들기 [Step 3]
  27. 2010.01.04 Windows Azure 개발: 간단한 방명록 만들기 [Step 1]
  28. 2009.10.25 Windows Azure Platform에 대한 소개 (2)
  29. 2009.09.14 App_Code 폴더를 통하여 여러 프로그래밍 언어 동시에 사용하기
  30. 2009.09.13 jQuery를 이용하여 POST 방식의 WCF 서비스 호출하기
Linux + .NET2014. 8. 11. 09:35

업데이트: mono 3.8이 9월 초에 새로 릴리즈되었으며 이 내용을 기초로 새로 업데이트한 아티클을 올렸습니다.

이 블로그 포스트의 내용은 아래 두 블로그 포스트의 내용을 기초로 작성한 것임을 말씀드립니다.
•http://graemechristie.github.io/graemechristie/blog/2014/05/26/asp-dot-net-vnext-on-osx-and-linux/
•http://www.rocko.me/install-mono-3-4-ubuntu/

또한 이 블로그 포스트는 MS Azure Virtual Machine과 Ubuntu Server 14.04 버전을 최초 설치했을 때의 상태를 기준으로 작성된 것이며, 이 블로그 글을 작성하는 2014년 8월 현재 ASP.NET vNext가 정식 출시 전임을 말씀드립니다.

주의: 실제 배포 환경에서 이 블로그 포스트의 내용을 활용하시는 것은 매우 위험합니다.

 

 

ASP.NET vNext는 기존의 System.Web 기반의 레거시 웹 개발 프레임워크에서 탈피하고자 하는 MS의 강력한 의지의 결과물인듯 합니다. 이전에는 상상하기 어려웠고, MS의 손이 아닌 오픈 소스 그룹 (Mono의 System.Web 구현)이나 써드 파티 회사 (Grasshoper 같은)에 의한 제한적인 수준의 작업 결과물일 뿐이었던 ASP.NET의 이식성이 이제서야 완벽함을 기할 수 있게 되었습니다.

이 블로그 포스트에서는 ASP.NET vNext를 우분투 서버 14.04에서 설치해본 과정을 기록하여 그것을 토대로 작성하였습니다. ASP.NET vNext의 발전 가능성을 살펴보시고, 여러 이야기를 나눌 수 있지 않을까 하여 기록해봅니다.

사전 준비 작업

ASP.NET vNext는 Windows 서버 환경에서는 손수 기존에 설치된 .NET Framework를 대체하는 K Runtime을 사용하여, 어느 버전의 K Runtime을 사용할 것인지 패키지 레벨에서 정의할 수 있는 것이 특징이었는데, 리눅스의 경우 기본 실행 엔진은 현재는 Mono를 기반으로 하고 있는 것이 특징입니다. 그럼에도 불구하고 K Runtime이 가지는 영역이 엄연히 있고, 아마 핵심 실행 엔진만 현재는 Mono를 기반으로 실행되는 것 같습니다.

그런 이유로 Mono의 최신 버전을 시스템에 설치해야 하는데, 안타깝게도 Ubuntu 14.04에 등록된 Mono 패키지의 최신 버전은 ASP.NET vNext를 실행하기 위해 필요한 버전과 격차가 상당히 크고, 또한 지원되지 않습니다. 그래서 제일 먼저 해야 할 일은 github에 올라와있는 Mono 소스 코드를 내려 받아 컴파일하고 새 버전으로 바꾸는 작업입니다.

우선은 기존에 Mono 런타임을 설치했던 이력이 있을 경우를 고려하여 Mono와 관련된 모든 패키지를 제거해야 하는데, 아래 명령어로 간단히 제거할 수 있습니다.


sudo apt-get -y purge mono-*

그 다음, Mono를 설치하기 위하여 필요한 이미징 라이브러리 관련 종속성을 해결해주어야 하는데, 필요한 패키지들중 상당수는 Ubuntu 14.04에서 직접 지원하지 않거나 오래된 버전으로 취급하여 apt-get으로 직접 설치가 어려운 패키지들입니다. 따라서, 이들 패키지들을 수동으로 내려 받아 설치하는 작업이 필요한데, 아래 명령어를 복사하여 하나씩 실행하시면 되겠습니다.


wget http://security.ubuntu.com/ubuntu/pool/main/j/jbigkit/libjbig0_2.0-2ubuntu1.13.10.1_amd64.deb
 wget http://security.ubuntu.com/ubuntu/pool/main/libj/libjpeg-turbo/libjpeg-turbo8_1.3.0-0ubuntu1.1_amd64.deb
 wget http://mirrors.kernel.org/ubuntu/pool/main/libj/libjpeg8-empty/libjpeg8_8c-2ubuntu8_amd64.deb
 wget http://mirrors.kernel.org/ubuntu/pool/universe/t/tiff3/libtiff4_3.9.7-2ubuntu1_amd64.deb
 wget http://mirrors.kernel.org/ubuntu/pool/universe/t/tiff3/libtiffxx0c2_3.9.7-2ubuntu1_amd64.deb
 wget http://mirrors.kernel.org/ubuntu/pool/main/libj/libjpeg8-empty/libjpeg-dev_8c-2ubuntu8_amd64.deb
 wget http://security.ubuntu.com/ubuntu/pool/main/j/jbigkit/libjbig-dev_2.0-2ubuntu1.13.10.1_amd64.deb
 wget http://security.ubuntu.com/ubuntu/pool/main/libj/libjpeg-turbo/libjpeg-turbo8-dev_1.3.0-0ubuntu1.1_amd64.deb
 wget http://mirrors.kernel.org/ubuntu/pool/main/libj/libjpeg8-empty/libjpeg8-dev_8c-2ubuntu8_amd64.deb
 wget http://mirrors.kernel.org/ubuntu/pool/main/libj/libjpeg8-empty/libjpeg-dev_8c-2ubuntu8_amd64.deb
 wget http://mirrors.kernel.org/ubuntu/pool/universe/t/tiff3/libtiff4-dev_3.9.7-2ubuntu1_amd64.deb

sudo dpkg -i libjbig0_2.0-2ubuntu1.13.10.1_amd64.deb
 sudo dpkg -i libjpeg-turbo8_1.3.0-0ubuntu1.1_amd64.deb
 sudo dpkg -i libjpeg8_8c-2ubuntu8_amd64.deb
 sudo dpkg -i libtiff4_3.9.7-2ubuntu1_amd64.deb
 sudo dpkg -i libtiffxx0c2_3.9.7-2ubuntu1_amd64.deb
 sudo dpkg -i libjbig-dev_2.0-2ubuntu1.13.10.1_amd64.deb
 sudo dpkg -i libjpeg-turbo8-dev_1.3.0-0ubuntu1.1_amd64.deb
 sudo dpkg -i libjpeg8-dev_8c-2ubuntu8_amd64.deb
 sudo dpkg -i libjpeg-dev_8c-2ubuntu8_amd64.deb
 sudo dpkg -i libtiff4-dev_3.9.7-2ubuntu1_amd64.deb

Mono 최신 버전 설치하기

이제 기본 준비 작업은 끝났고, 필요한 패키지들을 한꺼번에 설치할 차례입니다. 아래 명령어를 입력하도록 합니다.


sudo apt-get -y install libpng3 libpng3-dev libtool libexif12 libexif-dev libgif4 libgif-dev libpango1.0-dev libatk1.0-dev libgtk-3-0 libgtk-3-dev bison automake autoconf make gcc gtk-sharp2 build-essential xorg-dev libfreetype6 libfontconfig libfontconfig-dev gettext libglib2.0-dev git libjpeg-dev libjpeg8-dev libjpeg-turbo8-dev g++ unzip

쉬운 설명을 위하여, 사용자 프로필 디렉터리에서 설치를 진행한다고 가정하겠습니다.


cd ~

설치가 모두 되고 나면, mono git 리포지터리에서 libgdiplus 소스를 복사합니다.


git clone https://github.com/mono/libgdiplus.git

받은 소스 디렉터리로 이동합니다.


cd ~/libgdiplus

그리고 각종 설정 검사 및 헤더 구성을 진행합니다. 주의할 것은 공식 가이드에서는 –prefix=/usr/local로 소개하고 있으나 우분투의 경우 아래와 같이 /usr을 기준으로 잡아야 합니다.


./autogen.sh –prefix=/usr

구성이 끝나면 컴파일을 하도록 합니다.


make

컴파일 중 특별한 오류 메시지가 없었다면 시스템에 설치하도록 합니다.


sudo make install

이제 다시 홈 디렉터리로 이동합니다.


cd ~

mono 소스를 컴파일하는 과정 중에는 재귀적으로 mcs 컴파일러가 필요합니다. 이를 위하여 mono-gmcs 패키지를 구 버전이지만 우선 설치해야 합니다.


sudo apt-get -y install mono-gmcs

설치가 끝나면, 이제 mono 소스를 복사하도록 합니다.


git clone git://github.com/mono/mono.git
 cd mono

libgdiplus 때와 마찬가지로 prefix 설정에 유의하여 자동 구성을 진행합니다. 자동 구성 중에 다른 git 리포지터리에서 추가로 관련된 소스를 내려받기도 합니다.


./autogen.sh –prefix=/usr

모든 구성이 끝나면 컴파일하고 설치하도록 합니다.


make
 sudo make install

모든 설치가 다 끝났다면, 새 버전 (2014년 8월 현재 3.8)으로 업데이트가 잘 되었는지 확인해보도록 합니다.


mono –version
 mcs –version

위의 명령어에서 새 버전으로 표시가 된다면 ASP.NET vNext를 설치할 준비가 다 끝난 것입니다. 이제 다시 홈 디렉터리로 이동합니다.


cd ~

계속 하기 전에, 라이브러리 경로에 관련된 환경 변수를 하나 설정해주는 것이 좋습니다. 아래 명령어를 실행하여 LD_LIBRARY_PATH 환경 변수를 설정하도록 합니다.


export LD_LIBRARY_PATH=/usr/lib:/usr/local/lib:$LD_LIBRARY_PATH

K Runtime과 ASP.NET vNext 설치하기

이제 중요한 부분이 남았습니다. K Runtime과 ASP.NET vNext를 설치하는 것이 남았는데, 앞의 과정보다 시간도 짧게 걸리고 비교적 쉽습니다.

ASP.NET vNext의 전체 소스 코드를 복사하지 않고 필요한 셸 스크립트 파일인 kvminstall.sh 파일만 가져오도록 합니다. 아래 명령어를 홈 디렉터리에서 실행합니다.


curl https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.sh | sh

경로 설정을 맞추기 위하여, 아래 명령어를 실행합니다.


source ~/.kre/kvm/kvm.sh

이제 KVM을 사용자 프로필 디렉터리 아래의 .kre 폴더에 설치하기 위해, 다음 명령어를 실행합니다.


kvm upgrade

기본적인 실행 환경이 준비되었고, K Package Manager (달리 표현하면 K Package Manager의 실행을 담당하는 Mono)가 통신해야 할 사이트들의 HTTPS 인증서를 추가한 다음, 시스템에 설치된 루트 인증서를 가져올 수 있도록 하기 위하여 아래 명령어들을 실행합니다. 확인 프롬프트가 나타나면 여러번 yes를 입력하여 모든 필요한 인증서 및 인증서 체인을 가져오도록 합니다.


sudo certmgr -ssl -m https://go.microsoft.com
 sudo certmgr -ssl -m https://nugetgallery.blob.core.windows.net
 sudo certmgr -ssl -m https://nuget.org
 sudo certmgr -ssl -m https://myget.org
 mozroots –import –sync

Hello, World! 찍어보기

모든 설치가 끝났습니다. 예제 소스 코드를 가져와서 실행하기 위하여, David Fowler님의 github 리포지터리에 올라와있는 ASP.NET vNext 샘플을 이용하도록 하겠습니다. 공식 웹 사이트에 있는 샘플은 HTTPAPI를 기반으로 하는 것이어서 Nowin Factory로 교체하여 실행할 수 있지만 쉬운 설명을 위해 David Fowler님의 예제를 가져와서 대신 설명함을 말씀드립니다.

홈 디렉터리로 이동합니다.


cd ~

그리고 아래 명령어를 실행하여 콘솔 프로젝트 샘플 소스를 복사합니다.


git clone https://github.com/davidfowl/HelloWorldVNext.git

해당 디렉터리로 이동하여 다음 순서대로 명령어를 입력하여 Hello World! 메시지가 나타나는지 확인합니다.


cd ~/HelloWorldVNext/src/helloworld
 kpm restore
 k run

여기서 kpm restore 명령은 해당 예제를 실행하기 위하여 필요하다고 project.json에서 명시한 NuGet 패키지들을 전부 시스템에 설치하는 과정을 포함하며, 최초 한 번만 실행하면 됩니다. 그리고 k run 명령은 project.json 또는 그 상위에 정의되어있는 run 명령어를 실행한다는 의미이며, 보통 run 명령어는 재정의하지 않는 한 Main 메서드를 찾아 실행하는 것과 의미가 같습니다.

받은 프로젝트 디렉터리 상의 파일을 보면 흥미로운 것이, 이전처럼 mcs (gmcs)를 호출하여 exe 파일을 만들지 않았는데도 소스 상태에서 바로 k run이라는 명령어를 넣으면 프로그램이 시작된다는 점입니다. 이런 방식의 닷넷 응용프로그램은 웹 환경에서 큰 강점을 발휘하게 될 것입니다.

ASP.NET vNext 샘플 웹 프로젝트 띄워보기

이제 핵심입니다. ASP.NET vNext 샘플 웹 프로젝트를 띄워볼 차례인데, 다음과 같이 명령어를 입력하도록 합니다. 물론, 진행의 편의를 위해 홈 디렉터리에서 실행하는 것이 좋겠습니다.


git clone https://github.com/davidfowl/HelloWorldVNext.git
 cd ~/HelloWorldVNext/src/helloworldweb
 kpm restore
 k web

예제에 같이 들어있는 Nowin Factory 프로젝트의 코드를 보면 TCP/5000 포트를 웹 리스너 포트로 사용하고 있습니다. 밖에서 호스트 이름과 함께 5000번 포트로 접속하면 웹 페이지가 나타나는 것을 볼 수 있습니다. 그리고 서버를 종료하려면 콘솔에서 아무 키나 누르면 종료가 됩니다.

만약에 원격에서 좀 더 지속적으로 서버의 성능을 측정해보고 싶으시다면 screen 유틸리티를 사용하여 세션을 분리하신 상태에서 위의 명령어를 입력하고, 서버가 떠 있을 때 Ctrl 키를 누른 상태에서 빠르게 a, a, d 키를 누르면 세션이 분리되어 계속 살아있는 서버가 만들어집니다. 이 상태에서 Apache Bench (AB)등의 유틸리티를 사용하여 부하 테스트 등을 해보시는 것도 의미가 있을 것입니다.

참고로, NAT 환경이나 퍼블릭 클라우드 환경에서는 대표 IP 주소에 대한 외부 방화벽 설정을 열어주셔야 밖에서도 접속이 가능합니다.

마무리

아직 ASP.NET MVC 6나 다른 기술들이 완전히 준비된 것은 아니지만, 이 정도만 하더라도 ASP.NET은 더 이상 윈도 OS 안에서만 사용 가능한 기술이 아니라는 것을 증명하는데에는 손색이 없을 것입니다. 더 많은 가능성과 잠재력을 포함하는 최신 기술이 곧 나타나게 될 것이 무척 기대가 됩니다.

만약 기존에 ASP.NET 웹 사이트를 개발해 놓은 것이 있다면, ASP.NET vNext로 프로젝트를 마이그레이션하면서 플랫폼에 중립적으로 동작하는 코드로 업데이트하는 프로젝트를 한 번 진행함으로서 그리 어렵지 않게 멀티 플랫폼으로 ASP.NET 웹 응용프로그램을 포팅하실 수 있을 것입니다.

앞으로 더 자세한 정보와 상세한 내용들, 그리고 활용 방안들도 블로그 포스트로 전할 수 있도록 하겠습니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

PaaS2014. 8. 10. 09:34

ASP.NET Custom Loader (코드 네임 Helios)는 기존의 System.Web 기반의 전통적인 ASP.NET 프레임워크를 대체하는 기술로, IIS 파이프라인에 직접 관여하여 System.Web에 의존적이지 않은 최신 ASP.NET 개발 프레임워크들 (OWIN, Nancy, FubuMVC 같은)의 실행에 필요하지 않은 System.Web 및 관련 파이프라인을 생략하고 직접 이들 프레임워크를 중개할 수 있도록 도와주는 도우미입니다.

 

 

이 글을 작성 중인 2014년 8월 현재 최신 버전은 1.0 알파 버전으로, 조만간 출시될 ASP.NET vNext와 함께 릴리즈가 될 것으로 예상되는 기술입니다. 현재는 Windows Server 2008 R2 및 Windows 7 이상의 운영 체제를 정식으로 지원하며, IIS 및 IIS Express의 경우 7.5 버전 이상을 지원합니다. 정식 출시에 맞추어, Windows Server 2008과 Windows Vista, 그리고 IIS 7도 지원 대상에 포함될 것으로 예상됩니다.

ASP.NET Custom Loader의 실행 성능 개선 효과에 대해서는 여러 블로그 아티클이 있지만, http://blogs.msdn.com/b/webdev/archive/2014/02/18/introducing-asp-net-project-helios.aspx 의 내용을 살펴보실 것을 권합니다.

이 글에서는 ASP.NET Custom Loader의 동작 원리에 대해서 간단하게 설명을 하려고 합니다.

ASP.NET Custom Loader의 구성 파일 내역

ASP.NET Custom Loader는 다음과 같이 구성됩니다.
•AspNet.Loader.dll
•Microsoft.AspNet.Loader.IIS.dll
•Microsoft.AspNet.Loader.IIS.xml
•x86\Microsoft.AspNet.Loader.IIS.Interop.dll
•amd64\Microsoft.AspNet.Loader.IIS.Interop.dll

일단 위의 파일들이 bin 폴더에 복사되면, 특별히 web.config에서 수정하는 내용 없이 곧바로 기능이 활성화됩니다. 또한 이름에서도 알 수 있듯이, 지원 가능한 아키텍처는 x86과 amd64 아키텍처만 가능하며, 아이태니엄 및 ARM 아키텍처는 지원되지 않습니다.

실제 웹 프레임워크와의 연결

이제 중요한 것은 위의 Loader가 그 다음으로 주선할 웹 프레임워크를 지정하는 과정인데, 각 웹 프레임워크 별로 HttpApplicationAttribute를 어셈블리 수준에 적용하여 자신들의 웹 프레임워크 기술을 사용하는 개발자들을 위한 부트스트랩을 제공합니다. ASP.NET Web Loader는 이 정보를 찾아 연결을 시도하게 됩니다.

대강 아래와 같은 모양새를 가진 부트스트랩이 있어야 합니다. (물론 필요하다면 직접 만들 수도 있습니다.)

[assembly: HttpApplication(typeof(YourClass))]
 public class YourClass : HttpApplicationBase
 {
 }

이런 목적에 부합하는 기능과 관련된 종속 기능들을 OWIN에서는 아래 어셈블리들에 나누어 제공하고 있습니다.
•Microsoft.Owin.Host.IIS.dll
•Microsoft.Owin.Host.IIS.xml
•Microsoft.Owin.Host.IIS.Security.dll
•Microsoft.Owin.Host.IIS.Security.xml
•Microsoft.Owin.Hosting.dll
•Microsoft.Owin.Hosting.xml

기존에 OWIN 기반으로 배포한 응용프로그램이 있다면 ASP.NET Custom Loader를 배포한 다음 위의 어셈블리 파일들을 추가로 복사해야 ASP.NET Loader가 OWIN 시작 클래스를 연결해줄 수 있습니다.

주의 사항

이 글을 작성하는 현 시점에서 ASP.NET Custom Loader는 알파 버전을 릴리즈한 상태입니다. 그리고 이에 관하여 다음의 제약 사항들이 있습니다.
•Windows Server 2008과 Windows Vista, 즉 IIS 7의 경우 로더 실행 시 보안 알고리즘 관련 알 수 없는 HRESULT가 발생했다는 예외가 나타나면서 초기화가 이루어지지 않습니다. 공식 개발팀의 언급에 따르면, 정식 버전에서 해결할 예정이라고 합니다.
•Web.config에 configSource 애트리뷰트를 사용하여 나누어놓은 구성 파일이 있을 경우, 잘못된 경로 문자열이라면서 역시 Helios 초기화 도중 예외가 발생합니다. 불편하더라도 알파 버전의 테스트를 위해서는 구성 파일을 web.config 하나로 통합하셔야 테스트할 수 있습니다.

위와 같은 문제점에도 불구하고, 상당한 수준의 성능 개선은 개인적으로 만족스러웠습니다. :-)

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Useful Solutions2013. 11. 16. 02:00

Visual Studio 2013에서는 One ASP.NET이라는 새로운 형태의 프로젝트 생성 방식을 제공하고 있습니다. 이전에는 ASP.NET MVC, Web Form, Web Page, Web API가 각기 다른 프로젝트로 분리되어있어서 구성하기에 불편한 점이 많았습니다만 2013부터는 한 위치에서 동시에 여러 ASP.NET 웹 스택을 선택하고 조합할 수 있게 되었으며, 인증 시나리오도 Windows Identity Foundation, 기본 인증, 소셜 네트워크 기반 인증 등을 지원할 수 있는 옵션이 추가되었습니다.

그런데 이러한 특성 때문에, 처음부터 NuGet 패키지 관리자에 대한 의존성이 필수가 되었습니다. 그래서 간혹 어떤 컴퓨터에서는 Visual Studio 2013으로 ASP.NET 프로젝트를 생성하려 할 때 다음과 같은 오류 메시지가 나타나기도 합니다.

지정된 파일을 찾을 수 없습니다. (예외가 발생한 HRESULT: 0x80070002) 

오류: 이 템플릿에서 구성 요소 어셈블리 'NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'을(를) 로드하려고 했습니다. 이 문제에 대한 자세한 정보 및 이 템플릿을 활성화하는 방법에 대한 정보는 "프로젝트 템플릿 사용자 지정"의 설명서를 참조하십시오. 

위와 같은 오류 메시지가 나타나는 것은 NuGet Package Manager 애드인이 설치되어있지 않기 때문이며, ASP.NET 프로젝트 생성과 동시에 인터넷 상에서 NuGet Package Manager를 이용하여 프로젝트 구성에 필요한 각종 라이브러리들 (jQuery, ANTLRv3 등)을 내려받으려고 시도하기 때문입니다.

문제를 진단하기 위하여, Visual Studio에 현재 설치된 확장 및 업데이트 내역을 확인합니다. 메뉴에서 아래와 같이 실행하면 해당 항목을 찾을 수 있습니다.

도구(T) - 확장 및 업데이트(U) 클릭 

온라인 - Visual Studio 갤러리 선택 - 검색어에 nuget 입력 후 Enter 키 누름 - "NuGet Package Manager for Visual Studio" 선택 - 다운로드 버튼 클릭 

다운로드 진행 - EULA 동의 - 설치 - 아래와 같이 화면이 나타나면 하단의 "지금 다시 시작(R)" 버튼 클릭

이제 ASP.NET 프로젝트를 다시 생성하면 정상적으로 생성이 완료될 것입니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

PaaS2013. 10. 12. 21:00

요즈음은 Infrastructure as a Service를 이용하여 VM의 Mobility를 통한 클라우드 서비스 사업자 간 이동 및 이전이 요즈음 주목 받고 있습니다. 익히 잘 알려진대로, Windows Azure의 경우 사설 혹은 기업 데이터센터 구축을 위하여 사용하는 Hyper-V 환경의 가상 PC를 Windows Azure로 진출시키거나 역으로 가져오는 등의 기능은 상당히 잘 알려져 있어서 많이들 이용하고 계실 것 같습니다.

그런데 Platform as a Service는 이런 부분에서 확실한 이동성을 보장하기 많이 어렵다는 것이 문제가 됩니다. 특히 비즈니스 로직을 내부에 많이 포함하고 있는 클라우드 응용프로그램일 수록 해당 클라우드 서비스에 종속적이기 때문에 클라우드 사업자간 이동이 훨씬 더 어렵습니다. 물론, 이를 극복하기 위하여 Dependency Injection이나 Inversion of Control을 이용하여 클라우드 사업자들이 제공하는 SDK의 공통 분모를 추출하여 그 대상으로 삼는 것도 가능한 전략이기는 하겠습니다만 사실 쉽지 않습니다.

좀 더 현실적이고 직관적인 방법이 없을까 많이들 고민하시는 데에 어느정도 도움이 될까 하여 한 가지 방안을 제시해 보겠습니다. 바로 ASP.NET과 Web Deploy를 이용한 개발입니다.

왜 ASP.NET과 Web Deploy를 사용하는가 - ASP.NET을 사용할 수 있는 환경의 다양성

PHP, Node.js, Ruby on Rails 등 웹 세계에서 유명한 프레임워크나 개발 환경이 많이 있습니다만 상대적으로 ASP.NET은 늘 저평가되어있습니다. 특히 ASP.NET을 버전 1.0~2.0 시절의 Web Form과 연결하여 선입견을 가지는 경우가 무척 많습니다. 그렇지만 이전부터 필자가 계속 강조해왔던 NuGet, Web Developer Express 등 다양한 OSS에 친화적인 기술들과의 결합과 ASP.NET MVC의 등장은 이 선입견에 묻혀서 거의 알려지지 않은 경우가 많습니다. (특히 국내에서는 더욱 그렇지요.)

그러나 이런 와중에 생각보다 ASP.NET의 입지는 넓습니다. Microsoft 기술과 가장 친화적이지 않을 것 같은 Amazon의 BeansTalk가 ASP.NET Web Deploy 패키지를 사용한 PaaS 배포 기법을 전면에서 지원하고 있으며, 사용 중인 환경이 Linux인 경우 다양한 방법으로 Mono ASP.NET 런타임과 결합하여 ASP.NET 웹 사이트를 호스팅할 수 있습니다. 그리고 Windows Azure는 Web Site와 Cloud Service를 이용하여 각각 웹 사이트를 호스팅할 수 있는 방법을 제공합니다. 멀리 가지 않아도 시중에 나와있는 웹 호스팅 서비스는 모두 FTP를 통한 ASP.NET 웹 사이트 배포까지 지원합니다. 수단은 얼마든지 많고, 남는 것은 전략의 수립에 관한 부분만이 남는 셈입니다.

왜 ASP.NET과 Web Deploy를 사용하는가 - 단일 코드 베이스 유지

ASP.NET을 이용하여 독립적으로 실행할 수 있는 Web Application Project를 만들어두면, Public Cloud만을 이용해서 서비스를 구축하였을 때 간간히 문제가 발생하는 특정 데이터센터, 혹은 특정 클라우드 서비스의 장애로 인해서 전체 서비스가 중단되는 사고로부터 좀 더 자유로워질 수 있습니다.

여러 위치에 분산된 응용프로그램을 배포하는 것은 기본적으로 매우 어려운 작업입니다. 그리고 이 어려운 작업의 난해함을 지수승으로 더 복잡하게 만드는 것은 바로 클라우드 서비스 사업자 간의 고유한 기능 집합 때문입니다. 이 문제를 해결하기 위해서는 사업자 간 이해 관계가 비교적 덜 연결되어있으면서도 구성의 차이가 거의 없는 기술을 택하는 것이 바람직한데, 여기에 들 수 있는 후보로는 ASP.NET을 포함하여 다수의 기술들이 있습니다. 그 중에서도 오늘 소개하려는 ASP.NET은 수준 높은 IDE 지원과 다양한 OSS 프로젝트와의 연계가 가능하기 때문에 유용한 점이 많습니다.

왜 ASP.NET과 Web Deploy를 사용하는가 - 배포 시의 문제점을 최소화

기능 상의 유용함 이외에도, 스스로 스케줄링을 해야 하는 Daemon Type의 서비스 프로세스가 아닌 RPC나 REST 형태의 시스템일 경우 ASP.NET을 사용하여 프로그래밍하고 Visual Studio의 지원을 받을 때의 큰 이점이 하나 더 있습니다. 바로 배포 시의 문제점을 최소화할 수 있다는 것입니다.

ASP.NET Web Deploy 및 관련 프로세스들은 패키지로 만들 때, 종속성에 관련된 모든 문제를 예방할 수 있도록, 웹 프로젝트와 연관성이 있는 모든 종속성 관계 상의 파일을 자동으로 복사하여 패키지에 포함시키는 정책을 사용합니다. 이러한 특징 때문에, ASP.NET MVC나 Razor의 최신 버전이 처음 .NET Framework가 배포된 이후에 바뀌더라도 최신 기능을 사용하면서도 배포 상의 DLL 버전 차로 인한 문제가 발생할 가능성이 높지 않습니다.

클라우드 서비스 별 배포 방법 - Amazon BeansTalk

우선 Amazon BeansTalk의 경우를 예로 들어보도록 하겠습니다. Amazon BeansTalk는 Visual Studio에 추가 기능으로 설치할 수 있는 Toolkit을 통한 배포/모니터링과 Management Console (Web)를 통한 패키지 파일 업로드 방식의 배포를 모두 지원합니다.

웹 프로젝트를 만들고, 아래 화면과 같이 배포 프로필을 Web Deploy 패키지로 만드는 것으로 설정한 다음, 지정된 위치에 패키지 파일을 만들도록 합니다. 패키지 파일은 ZIP 파일입니다.

만들어진 파일을 AWS Management Console로 이동하여 다음과 같이 업로드를 시작합니다.

업로드 완료 후 배포 프로세스가 시작되면 다음과 같이 진행 상황이 표시됩니다.

잠시 기다리면 다음과 같이 정상 배포가 완료되었음을 알리는 화면이 표시됩니다.

그리고 로드 밸런서 앞으로 부여된 FQDN 앞으로 접속하면 다음과 같이 로컬 개발 환경에서 개발할 때와 비슷한 응용프로그램이 실제 클라우드 서비스에서 실행 중인 것을 볼 수 있습니다.

BeansTalk의 멤버 노드로 참여하는 VM 인스턴스들이 있다면 여느 PaaS 플랫폼들과 마찬가지로 모든 배포를 자동화하여 처리하므로 배포 프로세스의 상당 부분을 쉽게 완료할 수 있습니다.

클라우드 서비스 별 배포 방법 - Azure Web Site

이번에는 Azure Web Site를 위한 배포 방법을 살펴보도록 하겠습니다. Visual Studio에서 앞의 경우와 마찬가지로 웹 게시 대화 상자를 띄운 다음, 가져오기 버튼을 클릭합니다.

 

처음 이 기능을 실행하면 배포 프로필을 한 번도 사용한 적이 없으므로 아래와 같이 빈 목록이 나타나게 됩니다. Windows Azure 구독 추가 링크 (드롭 다운 상자 아래)를 클릭합니다.

 

Windows Azure 구독 가져오기 대화 상자가 나타나면 구독 파일 다운로드 링크를 클릭합니다.

 

로그인 페이지에서 로그인을 완료하면 로그인한 Microsoft ID와 연결된 모든 Windows Azure Web Site 프로필 정보를 취합한 통합 프로필 파일의 다운로드를 시작하게 됩니다.

 

앞의 대화 상자로 되돌아와서, publishsettings 파일을 다시 지정하고, 가져오기 버튼을 클릭합니다. 잠시 기다리면 지정한 Live ID로 만든 여러 가입 상의 여러 Azure Web Site에 대한 정보가 한번에 나타납니다. 관리자 권한만을 가지고 있었다고 할지라도 여기에 한번에 나타나므로 손쉽게 배포를 진행할 수 있고, 이 과정 이후에 따로 웹 사이트를 새로 만들더라도 다시 이 대화 상자만 띄우면 목록이 새로 업데이트됩니다.

 

이와 같이 설정을 마무리하고 연결에 이상이 없는지 유효성 검사 버튼을 클릭하여 녹색 체크 마크가 나타나면 배포를 위한 연결이 성립된 것으로, 계속 진행해도 좋습니다.

 

클라우드 서비스 별 배포 방법 - Azure Cloud Service / Web Role

기존에 만들어진 ASP.NET 웹 사이트 프로젝트를 Web Role로 변환하여 내보내는 작업은 생각보다 어렵지 않습니다. 기술적인 고려 사항을 제외하면, Web Role용 프로젝트는 Beans Talk의 경우와 마찬가지로 Azure Cloud Service만을 위해서 무언가 꼭 추가해야 하거나 심각하게 변경해야 할 것이 전혀 없습니다.

Windows Azure Tools 최신 버전을 설치한 다음, 클라우드 서비스 프로젝트를 생성할 때 아래와 같이 아무것도 추가하지 않은 상태로 확인 버튼을 클릭합니다. 기존 프로젝트를 가져오기 위해서입니다.

 

그러면 멤버 역할이 없는 상태의 빈 클라우드 서비스 프로젝트가 만들어지게 됩니다. 이제 솔루션 탐색기의 역할 폴더를 오른쪽 버튼으로 클릭하고 아래 그림과 같은 순서로 팝업 메뉴를 접근합니다.

 

그러면 아직 지금 클라우드 서비스와 연결된 적이 없는 프로젝트의 목록이 나타나게 됩니다. 항목을 선택하여 클라우드 서비스 프로젝트로 가져옵니다.

 

정상적으로 가져오게 되면 다음과 같이 솔루션 탐색기의 클라우드 서비스 프로젝트 아래의 역할 폴더에 프로젝트 이름이 나타나면서 클라우드 서비스의 웹 역할로 등록됩니다.

 

이제 Azure Cloud Service로 배포하기 위하여 패키지를 만들 차례입니다. 패키지를 만들어서 Azure Management Portal을 이용하여 업로드를 해도 좋고, 사전에 인증서 및 계정 연동을 미리 구성하여 Visual Studio에서 진행해도 상관 없습니다. 여기서는 패키지 만들기 기능으로 배포를 해보겠습니다. 클라우드 서비스 프로젝트를 오른쪽 버튼으로 클릭한 다음 패키지 메뉴를 클릭합니다.

 

그러면 배포 대화 상자가 나타나게 됩니다. 각각의 드롭 다운 상자의 의미는 어렵지 않습니다. 서비스 구성이란 클라우드 서비스의 구성을 의미하는 것이고, 빌드 구성은 각 역할과 연결된 C#이나 VB.NET 프로젝트들의 빌드 구성을 의미하는 것으로 양쪽은 서로 독립적인 관계이므로 적절한 옵션을 선택합니다. 설정을 확인한 다음 패키지 버튼을 클릭합니다.

 

빌드 상의 오류가 없으면 탐색기 창이 열리면서 .CSCFG 파일과 .CSPKG 파일이 표시됩니다. 이 파일을 다루기 쉬운 위치로 이동시켜 Windows Azure Management Portal에서 클라우드 서비스를 만든 다음 게시합니다.

 

 

고려할 사항들

전통적인 웹 응용프로그램들과는 달리 클라우드 서비스들은 단일 인스턴스에서 실행하는 것 보다는 로드 밸런싱을 전제로 여러 인스턴스에서 실행하는 것을 기준으로 생각합니다. 그렇기 때문에, 전통적인 웹 기반 응용프로그램을 그대로 전환하는 것은 생각보다 쉽지 않습니다. 특히, 컴퓨터 자체적으로 업로드한 파일을 보관하거나, 서버 컴퓨터의 상태에 의존적인 웹 응용프로그램은 클라우드 기반의 서비스로 이동하기 전에 적절한 보완이 반드시 필요합니다.

그리고 여러 위치에 클라우드 서비스를 배포하고 관리하기 위해서는 자동화된 빌드, 배포, 모니터링 도구가 필요합니다. 각각의 개별 클라우드 서비스들이 제공하는 REST API를 이용하는 도구를 직접 만들 수도 있지만, 재미있는 것은 대다수의 클라우드 서비스 공급자들이 Windows에서는 PowerShell에 대응하는 모듈을 개발하여 배포하고 있다는 것이고, Unix나 Linux에서는 node.js의 클라이언트 기반 런타임을 개발하여 배포하는 일이 많다는 점입니다.

이러한 특징들을 이용하여, 여러 클라우드 서비스를 손쉽게 관리할 수 있는 노하우를 개발하여 여러분의 개발 및 운영 프로세스에 자연스럽게 통합시킬 수 있을 것으로 기대합니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

기술 소식2012. 11. 1. 23:14

안녕하세요. Windows Azure MVP 남정현입니다. 이번 BUILD 2012에서는 Windows 8과 Windows Server 2012를 필두로 하는 다양한 업데이트 소식이 있었는데요, 한 번에 알아보기 쉽도록, 그리고 약간의 시차를 두고 있는 흥미로운 새 소식들도 같이 전해드릴까 합니다.

Windows Server 2012 및 .NET Framework 4.5 지원 추가

Visual Studio 2012 출시와 함께 Windows Server 2012, .NET Framework 4.5에 대한 지원이 새로 추가되었습니다. 그리고 ASP.NET의 경우 ASP.NET MVC 4.0 업데이트를 포함하고 있고, C# 5.0 및 VB 11.0에 대한 지원도 포함하여 멀티 스레드 프로그래밍을 좀 더 생산성있게 할 수 있는 방안을 대폭 마련하고 있습니다. .NET Framework 4.5에서 향상된 내용들은 http://msdn.microsoft.com/ko-kr/library/ms171868.aspx 에서 확인하실 수 있습니다.

Windows Azure Mobile Service의 Windows Phone 8 지원 추가

Windows Phone 8 SDK 발표와 함께 Windows Azure Mobile Service에서 Windows Phone 8 대상 SDK도 같이 발표하였습니다. Windows 8과 Windows Phone 8을 위한 App 모두를 지원하는 것이므로 N 스크린 앱 개발에 큰 도움이 될 것입니다. 자세한 튜토리얼은 https://www.windowsazure.com/en-us/develop/mobile/tutorials/get-started-wp8/ 에서 확인하실 수 있습니다.

Windows Azure Store 런칭

Windows Azure 2012년 초반 업데이트에 공개된 적이 있었던 ClearDB의 Azure 기반 MySQL 데이터베이스 서비스는 이미 잘 알려져 있습니다. 그런데 한 가지 아쉬웠던 점이 있었다면 무료 서비스에 한정되어있었던데다 Windows Azure와는 따로 떨어져있는, 접근성이 그다지 좋지 않은 부가 서비스였었습니다. 그러나 이제는 ClearDB의 사례를 포함하여 Windows Azure 서비스에 결합할 수 있는 다양한 컴패니언 서비스 및 데이터 소스를 한 곳에서 쉽게 구매하고 자원으로 관리할 수 있도록 Windows Azure Store 안에서 통합 관리할 수 있게 되었습니다. 아쉽게도 2012년 11월 현재 미국에서만 런칭이 된 상태입니다만 조만간 한국에서도 편리하게 대량 E-MAIL 발송, 대용량 MySQL 데이터베이스 등 다양한 서비스를 쉽게 구매해서 실제 클라우드 서비스에 반영할 수 있을 것입니다. 자세한 내용은 https://www.windowsazure.com/en-us/store/overview/ 에서 살펴보실 수 있습니다.

새 버전의 .NET용 Windows Azure SDK 및 가이드 런칭

.NET용 Windows Azure SDK의 새 버전이 발표되었습니다. 다른 써드파티의 Windows Azure 관련 도구와 비슷하게 동작하도록 개선되고 향상된 Visual Studio Add-in을 대거 포함하며, 새롭게 설계된 클래스 라이브러리 및 .NET Framework 4.5 타겟팅을 지원합니다. 자세한 내용은 http://msdn.microsoft.com/en-us/library/ff683673.aspx#BK_October2012 에서 확인하실 수 있습니다.

Windows Azure 분산 캐시 정식 업데이트

AppFabric Cache로 소개되었던 적이 있는 이전 버전의 캐시는 매우 가격이 비쌌고 이에 비해 얻을 수 있는 득이 그렇게 크지 않았었습니다. 이를 대체하여 좀 더 사용자에게 실질적인 캐시 서비스의 이점을 누릴 수 있게 하기 위하여 새롭게 분산 캐시를 업데이트하였는데, 이번 릴리즈에서 정식 서비스로 업데이트되었습니다. Web Role이나 Worker Role, 혹은 Cache 전용 Worker Role을 만들어서 상황에 따라 유동적으로 증감하는 고성능 분산 캐시를 쉽게 구축할 수 있게 되었습니다. 이에 대한 자세한 내용은 https://www.windowsazure.com/en-us/home/features/caching/ 에서 살펴보실 수 있습니다.

Visual Studio Team Foundation Service Online 정식 런칭

Visual Studio TFS Online 또한 정식으로 서비스가 런칭되었습니다. 2012년 11월 현재 무료 버전으로만 서비스가 운영되고 5명의 사용자까지 지원합니다. Visual Studio, Eclipse, XCode와 함께 연동할 수 있도록 다양한 애드인과 함께 배포되며, Windows Azure Web Site 서비스와 함께 연동할 수 있으므로 다양한 요구 사항을 충족할 수 있습니다. 그리고 Git을 이용하여 TFS를 대상으로 작업할 수 있는 도구인 Git-TF (코드프로젝트 홈페이지: http://gittf.codeplex.com/, Microsoft 다운로드 페이지 주소: http://www.microsoft.com/en-us/download/details.aspx?id=30474)도 같이 활용하시면 유용하실 것입니다. http://blogs.msdn.com/b/somasegar/archive/2012/10/31/team-foundation-service-is-released.aspx 에서 자세한 내용을 보실 수 있으며, 서비스 사용은 http://tfs.visualstudio.com/ 에서 신청 가능합니다.

Windows Azure SQL Data Sync 10월 업데이트

오랜 기간에 걸쳐서 평가를 진행 중인 Windows Azure SQL Data Sync 서비스가 이번 10월 업데이트를 기준으로 전세계 모든 데이터센터에서 사용 가능하도록 배포가 완료되었습니다. Windows Azure SQL Data Sync 서비스를 사용하면 기존 SQL 서버 데이터베이스 간, Windows Azure SQL Database 간, 혹은 기존 SQL 데이터베이스와 Windows Azure SQL Database 사이의 데이터 동기화를 비동기적으로 최소한의 코드 작성을 통하여 손쉽게 수행할 수 있는 것이 특징이며 이에 대한 자세한 내용이 문서화되어있습니다. SQL Data Sync 서비스에 대한 소개는 http://msdn.microsoft.com/ko-kr/library/hh456371 페이지를, SQL Data Sync 서비스에 대한 시행착오를 최소화하기 위한 가이드는 http://msdn.microsoft.com/ko-kr/library/hh667328.aspx 페이지의 내용을 참고하시면 유용합니다.

Windows Azure 기술 운영에 관한 중국의 21Vianet社와의 MOU 체결

Windows Azure는 Public Cloud Computing Service로, 그동안 중국 내에서는 해외 데이터센터의 이용이 쉽지 않았던 비즈니스 상의 특성 때문에 Windows Azure가 서비스를 할 수 없었던 대표적인 국가였습니다. 이러한 한계를 극복하기 위해서 21Vianet社 (http://www.en.21vianet.com/)와의 MOU를 체결하여 Windows Azure 운영 시스템을 중국 내 로컬 데이터센터에서 이용할 수 있도록 협약을 맺었다는 소식이 Windows Azure 공식 블로그를 통해서 공개되었습니다. ( http://blogs.msdn.com/b/windowsazure/archive/2012/11/01/cloud-os-is-coming-to-china.aspx) 중국 내에서 클라우드 컴퓨팅 서비스를 도입할 것을 계획 중이신 경우 향후 21Vianet을 통하여 Windows Azure와 유사한 서비스를 중국 내 로컬 데이터센터를 이용하여 경험할 수 있을 것입니다.


Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Windows + .NET2012. 9. 15. 20:37

안녕하세요. Windows Azure MVP 남정현입니다. 오늘은 Visual Studio 2012 출시와 더불어서 Express Edition의 업그레이드에 대한 이야기를 전해드리려고 합니다.

개인적으로 매우 좋아하고 아끼는 Visual Studio 제품 라인 업 중에 Express Edition이 있습니다. 무료로 제공되는 개발 도구임에도 기능에서나 활용 면에서 부족함이 전혀 없고, 제 스스로에게 있어서 작업 시간을 줄여주고 시행 착오를 최소화하는데에 지대한 공헌을 하는 멋진 개발 툴입니다.

이번 2012 라인 업에서는 아래와 같이 구성이 변경되었습니다.

  • Visual Studio 2012 Express for Web: 기존의 Visual Web Developer 2010을 이어서 업그레이드된 버전으로 ASP.NET 4.5와 Windows Azure 최신 개발 툴킷, Silverlight 개발 환경등을 포함하고 있습니다.
  • Visual Studio 2012 Express for Desktop: 기존의 Visual C# Express 2010, Visual Basic .NET Express 2010, Visual C++ Express 2010을 통합하여 데스크탑 응용프로그램 개발에 최적화된 버전으로 업그레이드되었습니다.
  • Visual Studio 2012 Express for Windows 8: Windows 8에서 새로 추가된 Windows Store 앱을 만들기 위하여 필요한 개발 도구로 동시에 Expression Blend for Windows 8이 같이 설치됩니다.
  • Visual Studio Team Foundation Server 2012 Express: 고가의 상용 버전 제품으로만 알려져있었던 Team Foundation Server도 Express 버전을 새로 출시하게 되었습니다. 소규모 개발 팀을 운영 중인 경우 한 번즈음 고려해볼 수 있는 형상 관리, 작업 관리, 빌드 자동화를 제공합니다.

언어 별로 나누어져 있었기 때문에 장점이자 단점으로 동시에 작용하던 작고 가벼움은 아쉽게도 더 이상 존재하지는 않습니다. 그렇지만 Express Edition 특유의 한계를 극복하고 더 강력한 기능을 더하고 단순히 학습용이 아닌 소규모 개발 팀을 위한 배려를 모두 포함하고 있다는 것은 매우 기쁜 일입니다.

그리고 실제로 Visual Studio 2012 전체 버전을 구입하시기 전에 제품의 표면적인 기능만을 제한된 시간 내에 평가해야 하는 트라이얼 버전 대신, 실제 업무에도 자연스럽게 반영해볼 수 있는 Express Edition을 통해서 충분한 시간을 가지면서 활용하시면 좀 더 좋은 부분을 많이 보실 수 있을 것이라고 기대합니다.

Web과 Desktop 버전은 Windows 운영 체제 버전과 관계없이 사용이 가능하며, Windows 8 버전의 경우에는 실제로 Windows 8 운영 체제 위에서 실행되어야만 개발 환경 구축이 가능합니다. 그리고 이전과 마찬가지로, 무료로 사용이 가능하고 상용으로도 활용이 가능하지만 설치 후 기간 내에 Microsoft 등록 페이지에 가서 제품에 대한 25자리 등록 번호를 받아서 등록해야 하는 절차는 변함 없습니다.

2012 Express Edition과 2010 Express Edition을 다운로드하시려면 http://www.microsoft.com/visualstudio/kor/downloads 페이지로 가시면 됩니다. :-)

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

  1. 현재 네이버 메인에 나오고 있습니다.

    2013.01.28 15:38 신고 [ ADDR : EDIT/ DEL : REPLY ]

Useful Solutions2012. 8. 8. 20:26

안녕하세요. Windows Azure MVP 남정현입니다.

오늘 소개해드리려고 하는 것은 Microsoft Press에서 그동안 출간된 eBook, 백서, 가이드 문서 등을 eBook 형태로 집대성해서 다운로드할 수 있도록 공개한 내용인데요, 상당히 많은 자료들이 있지만 그 중에서도 개발자나 IT 엔지니어에게 도움이 될 만한 부분들만 따로 간추려서 블로그 포스팅을 해 봅니다. 제공되는 모든 eBook은 영어로 작성되어있습니다.

여기서 소개하지 않은 백서나 가이드 문서, 트레이닝 킷 혹은 PDF 이외의 다른 포맷의 다운로드 컨텐츠를 찾으시려면 아래 웹 사이트에 방문하셔서 더 찾아보실 수 있습니다. :-)

제품 별로 자료들을 분류한 것으로 적절한 카테고리의 항목을 찾아 검색하시면 쉽게 다운로드하실 수 있습니다.

클라우드 기술 관련

프로그래밍 관련

Office 365 및 Office 2010 관련

Windows Server 관련

일반 사용자

출처: http://blogs.msdn.com/b/jspark/archive/2012/08/06/ebook-windows-azure-windows-8-windows-phone-7.aspx

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

  1. 유용한데요? ^^

    2012.08.09 10:47 신고 [ ADDR : EDIT/ DEL : REPLY ]

Windows + .NET2012. 4. 17. 11:55

ASP.NET 환경에서 사용자 멤버십, 프로파일, 역할과 세션 상태 관련 기능은 별도의 공급자 클래스에 의하여 구현되는 경우가 많은데, 이러한 공급자 클래스들은 개발자 스스로 원한다면 별도로 정의하여 각자의 서버 및 네트워크 인프라에 맞추어 다시 작성할 수 있습니다. 하지만 이렇게 작업하기에는 녹록치 않은 면들이 많고, 또 실제로 많은 테스트와 검증 과정이 뒷받침되어야 할 필요가 있습니다.

최근에는 SQL Server Compact Edition이나 SQL Server 2012에서 소개된 SqlExpress 또는 SQL Azure와 같이 전통적인 SQL Server 환경이 아닌 곳을 기반으로 택해야 하는 일도 자주 있습니다. 이러한 경우 많은 시행 착오와 오류를 경험할 수 밖에 없는데, 이러한 문제를 크게 덜어줄 유용한 기술이 하나 있습니다. 바로 ASP.NET Universal Provider이며, 향후 Microsoft가 언급하는 Hybrid Cloud Computing 환경에서의 단일 프로그래밍 모델을 구현하기 위한 초석으로 자리매김할 것으로 예상됩니다. :-)

ASP.NET Universal Provider의 구성

ASP.NET Universal Provider는 다음과 같은 구성을 가지고 있습니다.

  • System.Web.Providers.DefaultMembershipProvider
    (기존의 System.Web.Security.SqlMembershipProvider에 대응)
  • System.Web.Providers.DefaultProfileProvider
    (기존의 System.Web.Profile.SqlProfileProvider에 대응)
  • System.Web.Providers.DefaultRoleProvider
    (기존의 System.Web.Security.SqlRoleProvider에 대응)
  • System.Web.Providers.DefaultSessionStateProvider
    (내장된 세션 상태 관리 공급자를 대체)

ASP.NET Universal Provider를 Visual Studio의 확장 패키지 갤러리 (NuGet 갤러리)를 통하여 설치하게되면 위의 각 공급자에 대한 설정을 현재 ASP.NET 프로젝트 상의 web.config 파일에 지정하게되고, 데이터 소스를 어떻게 선택하는지에 따라서 미리 구성된 데이터 스키마에 맞추어 관련된 서비스 기능을 수행할 수 있도록 맞추게 됩니다.

ASP.NET Universal Provider 설치하기

ASP.NET Universal Provider는 Nuget Package Install Site에서 손쉽게 asp.net 프로젝트에 추가할 수 있습니다. Visual Studio나 Visual Web Developer를 설치한 경우 Nuget Console에서 아래 패키지 이름을 검색하여 기존 프로젝트에 추가하시면 됩니다. 

패키지 설치가 끝나면 web.config 파일에 아래와 같이 Membership, Role, Profile, Session State에 대한 설정을 Universal Provider로 업데이트합니다.

<configuration>
    <connectionStrings>
        <add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\aspnet.mdf;Initial Catalog=aspnet;Integrated Security=True;User Instance=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient"/>
    </connectionStrings>
    <system.web>
      <profile defaultProvider="DefaultProfileProvider" >
        <providers>
          <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider" connectionStringName="DefaultConnection" applicationName="/"/>
        </providers>
      </profile>
      <membership defaultProvider="DefaultMembershipProvider">
        <providers>
           <add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider" connectionStringName="DefaultConnection"
             enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
             maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
             applicationName="/" />
        </providers>
      </membership>
      <roleManager defaultProvider="DefaultRoleProvider">
        <providers>
           <add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider" connectionStringName="DefaultConnection" applicationName="/" />
        </providers>
      </roleManager>
      <sessionState mode="Custom" customProvider="DefaultSessionProvider">
        <providers>
          <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider" connectionStringName="DefaultConnection" applicationName="/"/>
        </providers>
      </sessionState>
    </system.web>

위의 설정에서 DefaultConnection에 적절한 연결 문자열과 함께 정확한 providerName을 기재하면 Universal Provider가 정확한 ADO.NET Connection Driver를 사용하여 필요한 서비스들을 제공하게 됩니다. 이렇게 만듦으로서 SQL Azure는 물론 기존 SQL Server, SQL Server CE를 데이터 원본으로 선택할 수도 있습니다.

좀 더 자세한 정보 알아보기

패키지의 최신 업데이트 정보와 설치 방법은 아래 웹 사이트에서 확인할 것을 권합니다.

http://nuget.org/packages/System.Web.Providers/1.0.1

구체적인 사용 방법과 시나리오에 대해서는 Scott Hanselman의 블로그 아티클을 참고하시기 바랍니다.

http://www.hanselman.com/blog/IntroducingSystemWebProvidersASPNETUniversalProvidersForSessionMembershipRolesAndUserProfileOnSQLCompactAndSQLAzure.aspx

 

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Windows + .NET2012. 2. 10. 01:30

지난 아티클에서는 Phalanger와 PHP 사이에 차이점들이 있다고 말씀드렸습니다. 구체적으로 어떤 차이점들이 있을까요? 여러 프로그래밍 언어를 지원한다는 사실이 가장 큰 차이점이고 닷넷 기반 위에서 실행된다는 것이 구분되는 점이겠지만 이런 점을 차치하고 PHP 관점에서 차이점을 살펴본다면 지금 이야기하려는 토픽들에 대한 이야기가 빠질 수 없을 것입니다.

App_Code 폴더의 사용

Phalanger가 ASP.NET을 기반으로 하고 있기 때문에 자동으로 이어받는 특성으로, App_Code 폴더의 사용에 관한 부분이 있습니다. ASP.NET에서는 App_Code 폴더 안에 낱개 코드 파일들을 넣어두면 이것을 자동으로 웹 페이지의 서버 런타임에서 자유롭게 가져다쓸 수 있다고 하였는데, Phalanger도 마찬가지입니다. 웹 페이지를 렌더링하기 위한 목적이 아닌 공통이 되는 PHP 코드를 이 폴더에 넣어두기만 하면 자동으로 이 폴더에 속한 모든 PHP 코드들이 글로벌 문맥 상에서 사용 가능하게 활성화됩니다.

단, 조심해야 할 부작용이 하나 있다면 여기에 지나치게 많은 코드를 배치할 경우 컴파일 시간이 늘어나서 처음 사이트를 시작할 때 시간이 오래 걸리게 될 가능성이 있습니다. 안타깝게도 C나 C++처럼 병렬 컴파일은 아직 지원되지 않기 때문에 컴파일 시간이 오래 걸릴 경우 다양한 문제를 야기할 가능성이 있습니다.

php.ini와 같은 Global Configuration이 아닌 web.config에 의한 설정

PHP의 경우 설정을 변경하기 위해서는 PHP 전체의 설정을 주관하는 php.ini 파일을 업데이트하거나, PHP를 다시 컴파일하여 설치하는 번거로운 과정을 거쳐야만 모듈에 대한 설정이나 추가/제거가 가능했습니다. 하지만 Phalanger의 경우 현재 만들어진 응용프로그램 풀마다 다른 설정을 가지도록 구성할 수 있으므로 좀 더 자유도 높은 설정이 가능합니다. 이를 위해서 web.config 파일을 수정하고 저장하기만 하면 됩니다.

이러한 설정을 다루기 위해서는 phpNet이라는 XML 요소를 web.config에 지정해야 하는데, 그냥 지정할 수는 없고 반드시 적절한 처리기를 연결해주어야 합니다. web.config은 단순한 XML 파일이 아니라 닷넷 프레임워크가 직접 내용을 검사하고 분석하는 프로그램 코드의 일부이기 때문에 규칙을 준수하는 것이 매우 중요합니다.

phpNet 요소를 추가하려면 web.config에서 <configuration> 요소의 제일 첫 번째 노드로 아래 XML 조각이 배치되어야 합니다.

<configSections>
<section name="phpNet" type="PHP.Core.ConfigurationSectionHandler, PhpNetCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=0a8e8c4c76728c71" />
</configSections>

그 다음, 보기에 편리한 위치에 phpNet 요소를 추가합니다. 보통 아래의 코드 조각으로 최초 설정을 시작하면 무난합니다.

<phpNet>
<classLibrary>
  <add assembly="PhpNetClassLibrary, Version=3.0.0.0, Culture=neutral, PublicKeyToken=4af37afe3cde05fb" section="bcl" />
  <add assembly="PhpNetXmlDom, Version=3.0.0.0, Culture=neutral, PublicKeyToken=2771987119c16a03" section="dom"/>
</classLibrary>   
</phpNet>

php.ini 파일의 샘플 사본을 복사하여 php.ini 파일로 사용하던 것과 비슷한 접근 방법이지만 각 사이트 혹은 도메인 별로 따로 사용하는 web.config 파일 안에서 이러한 설정을 다루는 것이 중요한 차이점입니다. 그리고 무엇보다도 안심해도 좋은 것은 INI 파일처럼 프로그램이 잘못 다루게 될 가능성이 있는 파일이 아니라, XML의 형태로 설정 파일이 관리되므로 web.config 파일을 건드리는 다른 써드 파티 어플리케이션 때문에 Phalanger의 설정이 깨지거나 변형될 일이 거의 없다는 점입니다.

위의 기본 설정을 지정하면 Phalanger에서 기본적인 PHP API를 사용할 수 있으며, PHP5부터 기본으로 제공되는 SimpleXMLElement도 위의 설정으로 기본으로 활성화됩니다.

PHP/CLR의 사용

이제 위의 설정을 토대로 PHP/CLR을 활성화하여 닷넷 프레임워크의 기본 API를 Phalanger에서 즉시 호출하여 사용할 수 있습니다. 위의 <phpNet> 요소 아래에 다음의 XML 요소를 추가하면 됩니다.

<compiler>
  <set name="LanguageFeatures">
    <add value="PhpClr" />
  </set>
</compiler>

그리고 <classLibrary> 요소 아래에 .NET Framework 기본 어셈블리에 대한 레퍼런스를 추가합니다.

<classLibrary>
  <add assembly="mscorlib" />
  <add assembly="System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  <add assembly="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  <add assembly="PhpNetClassLibrary, Version=3.0.0.0, Culture=neutral, PublicKeyToken=4af37afe3cde05fb" section="bcl" />
  <add assembly="PhpNetXmlDom, Version=3.0.0.0, Culture=neutral, PublicKeyToken=2771987119c16a03" section="dom"/>
</classLibrary>

이제 새로 추가한 코드가 의도한대로 잘 작동하는지 살펴보기 위하여, 이미지 리사이징을 수행하는 샘플 코드를 Phalanger 위에서 실행하도록 PHP/CLR 기반으로 코드를 만들어보도록 하겠습니다. 이 코드는 http://wiki.php-compiler.net/Code_Samples/Resize_image 의 예제를 발췌하여 조금 변형한 것입니다.

<?php
use System\Drawing\Bitmap;
use System\Drawing\Graphics;
use System\Drawing\GraphicsUnit;
use System\Drawing\Rectangle;
use System\Web\HttpContext;

function resize_imageSysDraw($from,$wid,$hgt)
{
  $bmp = Bitmap::FromFile($from);
  $fmt = $bmp->RawFormat;
  $new = new Bitmap($wid, $hgt);
  $gr = Graphics::FromImage($new);
  $gr->DrawImage($bmp,
    new Rectangle(0,0,$wid,$hgt),
    new Rectangle(0,0,$bmp->Width, $bmp->Height),
    GraphicsUnit::Pixel);
  $gr->Dispose();
  $new->Save(HttpContext::$Current->Response->OutputStream, $fmt);
  $new->Dispose();
}

resize_imageSysDraw(realpath('Penguins.jpg'), 320, 240);
?>

PHP/CLR의 경우 여느 닷넷 언어들과 마찬가지로 네임스페이스에 속한 클래스에 대한 참조를 use 명령어로 지정하고 있으며, 정적 멤버에 대해서는 :: 연산자를, 객체 생성은 new 연산자를 사용하였습니다. resize_imageSysDraw 함수에서는 ASP.NET의 HttpContext를 가져와서 기본 출력 대신 비트맵 이미지를 내보내도록 만들었고 그 결과 아래와 같이 축소된 이미지가 렌더링되서 나타나게 됩니다.

Phalanger의 LINQ 지원

이제 마지막으로 PHP/CLR의 하이라이트라고 할 수 있는 LINQ 지원에 대해서 살펴보겠습니다. LINQ는 Microsoft Research에서 C# 언어의 확장 사양인 C-omega 언어의 일부로 개발 중이던 사양을 정규화하여 Production Spec으로 만든 것으로, C# 이외에 VB.NET에도 영향을 주었으며 Prism이나 지금 소개하는 Phalanger에서도 개념을 적극 채택하여 정규 사양으로 활용 중입니다. 그리고 F#은 이러한 접근을 더욱 드라마틱하게 활용하여 함수형 언어로 발전시키기도 하였습니다.

LINQ에 대해서 이야기하려면 책을 한 권 따로 만들어야할 만큼 방대합니다. 그래서 자세한 이야기는 하지 않고, LINQ 자체에 대해서 진지하게 학습하기 원한다면 LINQ 관련 국내외 도서들을 검토하기 바랍니다. 개인적으로는 "생각하는 C# LINQ"라는 책을 추천합니다. :-)

http://kangcom.com/sub/view.asp?sku=200809180001&mcd=571

LINQ는 한 마디로 이야기하면, 프로그래밍 코드를 한 방향에서만 바라보도록 뷰 포인트의 시각을 고정한 것과 같습니다. 본디, 어떤 연관성이 있는 데이터 집합을 접근하는 방법에는 여러 가지 방법이 있을 수 있지만 LINQ는 데이터가 어떤 순서로 들어있든, 어떤 형태로 연결되어있든 관계없이 데이터를 꺼내올 수 있도록 도와주는 Iterator 패턴의 한 형태인 Enumerator를 조금 독특하게 해석하였습니다.

Enumerator가 열거할 대상을 미리 정할 수 있도록 만들고, 열거할 때 조건을 지정하여 필요없는 데이터는 건너뛸 수 있게 해준다던지 이런 취지에서 해석을 한 것이 LINQ입니다. 그리고 Enumerator를 수정하게 되는 시점이 이미 메모리 상에 저장된 데이터 셋에 대한 작업인지, 아니면 아직 수신되지 않은 미지의 데이터 셋에 대한 작업인지에 따라서도 지연 실행이냐 즉시 실행이냐 이렇게 구분하기도 하구요. 그러면서도 항상 잃지 않는 것은 핵심은 Enumerator라는 사실이며, 이에 입각하여 배열이나 리스트같은 정규화된 자료 구조로 변환할 수 있는 길을 항상 열어놓아 최대한의 유연성을 부여하기도 합니다.

어렵게 들릴 수도 있지만 Enumerator를 수정할 수 있게 해준다는 컨셉은 생각보다 활용 폭이 넓은데, 가장 가까이 있는 예로는 SQL 쿼리가 될 수 있습니다. 처음의 아이디어는 SQL 쿼리를 이용하여 전체 데이터 셋보다 가능한 적게 데이터를 반환하여 네트워크 트래픽을 줄이고 빠르게 데이터를 검색할 수 있도록 최적화하자는 것에 있었을 것이며, 이것을 좀 더 프로그래밍 언어와 친화적으로 만들 방법을 모색한 끝에 LINQ to SQL이 나타나게 된 셈입니다. 그리고 이를 필두로 접근할 수 있는 모든 유형의 컬렉션에 대해서 이런 아이디어를 대입하여 현재는 오픈 소스를 찾아보면 정말 엄청나게 많은 LINQ provider들을 발견할 수 있을 정도입니다.

이렇게 독창적이고 전례없던 기술을 Phalanger에서도 이용할 수 있다는 것은 매우 좋은 일입니다. <phpNet> 요소에 대해 PHP-CLR을 활성화하도록 설정을 수정한 후 아래 코드를 테스트해보기 바랍니다.

<?php
$myarray = json_decode('[
    {"label":"foo","name":"baz"},
    {"label":"boop","name":"beep2"},
    {"label":"foo","name":"baz1"},
    {"label":"boop","name":"beep3"},
    {"label":"foo","name":"baz2"},
    {"label":"boop","name":"beep1"}
]', true);

$result =
from $myarray as $x
where $x['label'] == 'foo'
select $x['name'];

foreach ($result as $x) {
    print($x.'<br />');
}

print_r($result);

?>

json_decode라는 기본 PHP 함수를 이용하여 JSON을 PHP 연관 배열로 바꾸고, 이것을 LINQ로 조회한 다음, 그 결과를 foreach 문을 통해서 출력하도록 만들었습니다. C#이나 VB.NET의 LINQ와 약간 다른 점은, from 절에서 in 연산자 대신 as 연산자를 사용하고 in 연산자와는 도치되는 좌/우항 관계를 가집니다. 즉, [나열 변수] in [데이터 소스] 에서 [데이터 소스] as [나열 변수]로 바뀝니다. 그리고 이것은 foreach 문에도 동일하게 적용됩니다. 아래는 실행 결과입니다.

PHP, JSON, 그리고 LINQ가 한 자리에 모여 매우 재미있는 상호 작용을 이룬 것을 볼 수 있습니다. 이 정도면 닷넷에서의 웹 프로그래밍이 이전과는 제법 많이 달라질 수 있다는 것을 체감할 수 있을 것입니다.

다음번에는 Phalanger가 기존 PHP의 모듈들을 어떻게 다루고 관리하는지에 대한 상세한 내용을 살펴보도록 하겠습니다. 긴 글 읽어주셔서 감사합니다. :-)

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Windows + .NET2012. 2. 8. 02:00

지난 아티클에 이어 오늘은 Phalanger를 이용하여 C#과 VB.NET 코드를 동시에 활용하는 예를 한 번 조명해보려고 합니다. 사실 이것이 Phalanger의 하이라이트라고 하여도 무방하지 않습니다. 기존의 C#과 VB.NET 로직을 재사용하면서도 Phalanger로 빠르고 가볍게 웹 페이지를 풀어나가는 방식은 여러모로 웹 개발에 가속을 붙여줄 것입니다.

계속 설명하기 전에, Phalanger가 ASP.NET 위에서 실행되기 때문에 적용되는 한 가지 특수한 규칙을 이야기할 것이 있습니다. 바로 미리 정해진 이름의 폴더인데, Bin, App_Code 폴더입니다. 그 외 많은 폴더들이 있지만 지금은 두 가지만 살펴보겠습니다.

앞에서 이야기한대로 ASP.NET은 닷넷 프레임워크를 기반으로 작동한다고 하였고, 닷넷 프레임워크는 언어의 종류와 무관하게 MSIL이라는 코드로 컴파일되서 나오는 DLL 파일들을 취급할 수 있습니다. 그렇게 만들어지는 DLL 파일들은 Bin 폴더에 파일을 넣어주면면 자동으로 참조가 활성화되서 해당 웹 사이트 안의 모든 닷넷 코드에서 클래스 라이브러리를 사용할 수 있게 됩니다. 단, 주의할 것은 이 폴더 안에 아무 DLL이나 넣을 수 있는 것은 아니며 반드시 닷넷으로 컴파일된 DLL만 포함시킬 수 있습니다.

그리고 이번 아티클에서 가장 핵심이 되는 기능을 제공하는 폴더인 App_Code 폴더는, 컴파일을 하려는 모듈에 대한 코드를 여기에 넣어서 모든 페이지에서 공유할 수 있습니다. 기본적으로 이 폴더에는 한 종류의 언어에 해당되는 파일들만 넣을 수 있고, 그외 다른 언어의 파일이 포함되면 아래 이미지와 같은 오류가 발생합니다. 하지만 제가 이전에 소개했던 약간의 추가 설정을 적용하면 App_Code 폴더에서 여러 프로그래밍 언어를 동시에 사용할 수 있습니다.

위와 같이 나타나는 문제를 해결하기 위하여, App_Code 폴더 자체에서 사용할 언어는 Phalanger로 정하고, App_Code 폴더 안의 두 번째 수준의 디렉터리들에 C#이나 VB.NET 같은 언어를 사용하기로 결정합니다. 그리고 web.config 파일에 다음과 같이 <system.web> 요소 아래에 하위 디렉터리가 존재한다는 것을 알려줍니다.

<system.web>
<globalization requestEncoding="utf-8" responseEncoding="utf-8" fileEncoding="utf-8" />
<compilation>
  <codeSubDirectories>
    <add directoryName="Cs" />
    <add directoryName="Vb" />
  </codeSubDirectories>
</compilation>
</system.web>

그리고 App_Code 폴더에 각각 Cs 폴더와 Vb 폴더를 만듭니다. 폴더 이름에서 바로 알 수 있듯이 각각 C#과 VB.NET 코드를 따로 보관할 수 있도록 하고, 위의 그림처럼 오류가 발생하지 않으면서 자동으로 C#과 VB.NET으로 만든 코드를 Phalanger에서 액세스할 수 있도록 하게 할 것입니다. 이것으로 준비는 모두 끝났으며 우리가 원하는대로 C#과 VB.NET 코드를 추가하기만 하면됩니다.

C# 코드

using System;
using System.Collections.Generic;
using System.Web;

/// <summary>
/// Summary description for ClassName
/// </summary>
public class ClassName
{
    public string Name { get; set; }
    public int Age { get; set; }
    public override string ToString() {
        return String.Format("Name: {0} / Age: {1:D3}", Name, Age);
    }
}

VB.NET 코드

Imports Microsoft.VisualBasic

Public Class ClassName2
    Public Content As String
End Class

그리고 중요한 부분이 있습니다. Phalanger가 서브 디렉터리에 있는 코드들을 컴파일하였을 때 각각 따로 만들게 될 코드 조각들을 인식할 수 있도록 최소한 1개 이상의 임의의 PHP 파일이 필요합니다. 이후 아티클에서 따로 설명하겠지만 Phalanger는 App_Code 폴더 안에 있는 PHP 파일을 모두 자동으로 include하는 동작을 가지고 있습니다. (이것이 이전의 Original PHP와는 다른 부분입니다.)

지극히 일상적이고도 당연한 클래스 선언을 담고 있는 파일을 각 디렉터리에 추가하였습니다. 이제 웹 매트릭스의 폴더 레이아웃은 아래 그림과 같은 형태가 되면 됩니다.

이제 마지막으로 index.php 코드를 아래와 같이 작성합니다. 아래와 같이 작성하면 정말 PHP에서 C#과 VB.NET 코드를 자동으로 불러올 수 있을까요? 기대됩니다. :-)

<?php       
// C#
$test1 = new ClassName();
$test1->Name = "남정현";
$test1->Age = 2012-1987;
print $test1->ToString().'<br />';
print get_class($test1).'<br />';

// VB.NET
$test2 = new ClassName2();
$test2->Content = '<strong>안녕하세요!!!</strong>'.'<br />';
print $test2->Content;
print get_class($test2).'<br />';

phpinfo();
?>

ClassName은 C#으로, ClassName2는 VB.NET으로 만든 코드입니다. PHP/CLR 확장의 도움으로 Name, Age, Content 프로퍼티에 문자열을 대입하고 있으며, print 문을 이용하여 웹 페이지 상에 문자열을 출력합니다. 그리고 get_class라는 기본 PHP 함수를 사용하여 클래스 형식명을 가져오는 일도 하려고 하는군요. 마지막으로는 phpinfo() 함수를 호출하여 Phalanger 및 서버 시스템에 대한 정보도 덤프로 출력합니다. 이제 이 페이지를 실행해보면 아래와 같이 나타나게 될 것입니다. :-)

훌륭합니다! C#과 VB.NET 컴파일러를 따로 부르는 일 없이 앉은 자리에서 한 번에 코드를 컴파일하고, 이것을 PHP에서 보기 좋게 가져다 쓰는 일까지 해냈습니다.

다음 아티클에서는 마지막으로 Phalanger만의 고유한 기능이라고 할 수 있는 자동 include에 대해서 마지막으로 이야기해볼까 합니다. Original PHP에서는 include나 include_once 같은 함수를 어떤 인과 관계에 따라서 포함하게 될 것인지, 그리고 순서에 대해서도 많은 고민을 해야 했지만 Phalanger는 이러한 부분에 대한 고민을 많이 덜어낼 수 있습니다. 그리고 그 중심에는 App_Code 폴더의 역할이 크다고 했는데요, 이 부분에 대해서 집중적으로 살펴보려고 합니다.

 

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Web Programming2011. 12. 15. 12:47

요즈음 웹 개발에 있어서 하나의 중추적인 트렌드로 자리 잡은 것이 바로 모바일 웹 개발이다. 모바일 웹 개발이라고 하면 흔히 하는 생각으로 막연하다는 느낌부터 들 것이다. 1세대의 모바일 웹 개발은 확실히 HTML보다 가벼워야 했고 하드웨어의 제한 사항이 큰 편이었기 때문에 WML과 같은 메타 언어의 존재감이나 그 수요가 분명했다. 하지만 모바일 기기와 일반 PC의 사양 차이가 날이갈수록 좁혀짐은 물론 이제 모바일 기기가 경우에 따라서는 일반 PC나 랩톱 컴퓨터보다 훨씬 더 유용해지고 쓰임새가 많아지게 되면서 이런 구분이 모호해지게 된다.

필자 역시 모바일 웹 개발을 해야 할 필요성을 자주 느끼게 되었다. 당장 가지고 있는 스마트폰인 Windows Phone 7.1 (이름하여 망고폰)을 비롯해서 주변 지인들이 빠짐없이 가지고 있는 아이폰, 아이팟, 아이패드, 그리고 안드로이드 계열이나 크롬 북을 포함하여 상당히 많은 수의 브라우저들을 고려하는 모바일 웹 사이트가 필요했다. 물론 이들 모두 일정 수준 이상의 HTML5와 CSS3, 그리고 자바스크립트 렌더링 엔진을 갖추고 있긴 하지만 특유의 해상도 제한이나 성능 제한, 그리고 결정적으로 고밀도의 선택이 가능했던 마우스를 대신하여 터치 인터페이스에 최적화된, 이전보다 훨씬 둔감한 조작을 이해할 수 있는 인터페이스를 디자인해야 한다는 것이 난제가 되었다.

기존 웹 기술을 최대한 보존하면서도 검증된 프레임워크의 이점을 누릴 수 있는 방법이 없을까 고민하다가 아주 훌륭한 프레임워크를 테스트해보게 되었고 그 내용을 블로그를 통하여 간단하게 소개하고자 한다. 바로 jQuery Mobile이다.

jQuery Mobile과 jQuery의 차이점?

그냥 얼핏 듣기에 jQuery Mobile과 jQuery는 큰 차이점이 없어보인다. 오히려 어떻게 보면 jQuery의 축소 버전이 아닌가 하는 생각이 들 수도 있다. 하지만 이 둘 사이의 정확한 관계는, jQuery Core를 기반으로 만들어진 Extension이 jQuery Mobile이며, jQuery Mobile은 단순히 기능 집합을 축소한 것이 아니라 오히려 모바일 환경에 알맞도록 확장시킨 일종의 확장팩에 해당되는 개념이다.

사실, 여러분이 어떻게 jQuery Mobile을 사용하는가에 따라서 jQuery 특유의 자바스크립트 기술을 전혀 사용하지 않을 수도 있다. jQuery Mobile이 제공하는 몇 가지 규칙에 맞추어 웹 페이지를 프로그래밍한다면 나머지 시각 효과, 간단한 검색 기능, 심지어 대화 상자 기능까지 자동으로 jQuery Mobile이 알아서 처리해주기 때문이다.

jQuery Mobile을 가장 잘 활용할 수 있는 방법

이제까지 여러분은 자바스크립트 모듈을 어떤 방식으로 사용해왔는가? 대개는 웹 사이트 안에 들어가는 부속품 정도로 여기고 이것을 같은 웹 사이트 안에서 서비스하도록 구성하는 일이 많았다. 그리고 웹 서버에 대한 트래픽이나 부하가 일어나지 않도록 하기 위하여 적절한 Cache Timeout 설정을 사용하여 클라이언트가 jQuery 라이브러리를 지속적으로 재사용할 수 있는 방안을 적용해왔을 것이다.

그렇지만 기왕 최적화를 할 요량이면 밀어 붙일 수 있는 곳까지는 밀어붙여보는 것도 나쁘지 않을 것이다. jQuery는 물론 jQuery Mobile까지 여러분의 웹 서버가 아닌 곳으로 레퍼런스를 걸 수 있는 방법이 요즈음 유행하고 있다. 즉, CDN 서버를 이용하는 방식으로, jQuery를 비롯한 몇 가지 유명한 자바스크립트 및 공통적인 웹 자원들을 공개적으로 서비스하는 곳이 있고 이곳의 라이브러리를 가져다 쓰는 방식이다.

jQuery의 경우 jQuery 프로젝트 팀이 자체적으로 운영하는 CDN 서비스가 있으며, Microsoft의 ASP.NET AJAX CDN, 그리고 잘 알려진 Google의 CDN 서비스까지 모두 세 가지 유형의 CDN 서비스를 사용하여 jQuery 및 jQuery Mobile 자바스크립트 라이브러리를 개별 웹 페이지에 붙여넣을 수 있다.

CDN에 대해서 간단히 설명하면, CDN 네임스페이스 상의 특정한 URL에 대해서 요청이 발생하면 해당 리소스에 대한 사본을 CDN 네트워크 상에서 현재 위치로부터 가장 가깝거나 혹은 빠른 응답 속도를 보이는 서버로부터 데이터를 가져와 클라이언트로 내려보내는 서비스이다. 물론 이 과정을 수행할 수 있도록 하기 위하여 원본 서버가 필요하고 이 원본 서버로부터 데이터를 가져와서 네트워크 상에 고속으로 배포하는 작업은 필수적이다. 글로벌 CDN으로 불리는 서비스들은 당연히 이러한 CDN에 큰 비용을 투자할 수 있는, 그리고 전세계적인 네트워크 망을 보유할 수 있는 기업이어야 할 필요성이 있으며 이러한 기업으로는 대표적으로 Google과 Microsoft가 있는 셈이다.

Microsoft CDN을 이용하여 jQuery 시작하기

각각의 CDN 서비스들마다 자바스크립트를 제공하는 방법에는 차이점도 있고 장단점도 있지만 여기서는 Microsoft의 CDN 서비스를 사용하는 경우를 예로 들어 설명하고자 한다. 당연한 이야이기이지만 Microsoft CDN에서는 jQuery를 Visual Web Developer의 JavaScript Intellisense와 연계할 수 있는 vsdoc 버전의 자바스크립트 라이브러리를 CDN 버전으로 제공받을 수 있다. Microsoft CDN 서비스로부터 여러분이 가져오고 싶은 자바스크립트 코드를 카탈로그로부터 가져오기 위하여 아래 웹 사이트를 찾아볼 수 있다.

http://www.asp.net/ajaxlibrary/cdn.ashx

위의 웹 사이트에 구체적인 설명이 잘 나와있지만 이 웹 페이지에서는 여러분이 상황에 맞게 쓸 수 있도록 코드 조각을 정리하여 설명하려고 한다.

만약 여러분이 jQuery 1.5.1 버전을 http 버전 프로토콜로 연결하려고 하면 아래와 같이 <HEAD> 태그 내부에 Child Element로 기술하면 된다.

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.min.js" type="text/javascript"></script>

만약 HTTPS 기반 웹 사이트를 사용 중이고 여기서 CDN을 사용하려고 한다면 프로토콜 접두사만 바꾸면 HTTPS 버전의 CDN도 이용할 수 있다.

<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.min.js" type="text/javascript"></script>

만약 VSDOC 버전을 연결하려고 하면 아래와 같이 min 대신 vsdoc으로 이름을 바꾸면 된다.

<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.vsdoc.js" type="text/javascript"></script>

jQuery UI를 사용하기 위해서는 CSS 파일, 이미지 파일, 그리고 자바스크립트 파일에 대한 참조가 필요한데, CSS 파일에 대한 참조만 정확하다면 이미지 파일들의 경로는 신경쓰지 않아도 된다. 그리고 jQuery UI는 jQuery를 기반으로 하는 프레임워크이므로 jQuery에 대한 참조가 필수이다. 그리고 테마는 여러분이 http://www.asp.net/ajaxlibrary/CDNjQueryUI1816.ashx 페이지에서 1.8.16 버전에 해당되는 미리 제공되는 테마 중에서 하나를 택하여 CSS 파일에 대한 참조만 정확히 지정하면 된다. 이런 설정을 바탕으로 jQuery UI를 CDN에서 가져올 때 Redmond 테마 버전으로 가져오고자 한다면 아래와 같이 코드 조각을 쓸 수 있다.

<link rel="stylesheet" href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.16/themes/redmond/jquery-ui.css" media="all" type="text/css" />
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>

그리고 jQuery Mobile을 사용하려 한다면 아래와 같이 작성한다.

<link rel="stylesheet" src="http://ajax.aspnetcdn.com/ajax/jquery.mobile/1.0/jquery.mobile-1.0.min.css" media="all" type="text/css" />
<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.mobile/1.0/jquery.mobile-1.0.min.js" type="text/javascript"></script>

jQuery Mobile의 경우 HTML5 마크업을 사용하는 것이 중요하다. Custom Attribute에 대한 지원이 필수적이기 때문이다. 이 부분에 대한 설명은 다음 기회로 넘기기로 하겠다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

PaaS2011. 9. 12. 23:32

요즈음 클라우드 서비스들을 이용하다보면, Windows 서버 운영체제를 통해서 확장성있는 클라우드를 만들고자 하는 경우가 자주 있습니다. 일반적인 웹 사이트를 구축할 때에도 마찬가지이고, 당연히 KT UCLOUD나 Amazon과 같은 환경에서도 같은 노력이 뒷받침이 되어야 하지요. 그리고 제가 주 전공으로 하고 있는 Windows Azure 역시, 첫 배포 때에는 간과하기 쉬운 점이 바로 로드 밸런싱 환경이라는 점입니다.

이러한 로드밸런싱 환경을 만들때에는, 이전에 구축해본 경험이 없는 관리자가 개발자 입장에서는 상당히 어려운 문제에 봉착하게 될 가능성이 많습니다. 특히 요즈음 웹 환경에서는 당연하게 사용하는 세션이나 쿠키에 관련된 설정들이 로드밸런싱 환경에서 기대했던 것과 다르게 동작해서 좌절하는 경험을 많이들 하실텐데요, 제가 오늘 블로그에 올리는 것은 ASP.NET에 관한, 그리고 IIS 7에 관한 내용입니다. (PHP나 JSP 개발자분들께서도 공감하실 수 있는 부분이 있을 것입니다.)

로드밸런싱 환경을 잘 알고 구축할 수 있다면, 앞으로 나오게될 어떤 종류의 클라우드 서비스이든 관계없이 문제를 정확하게 해결할 수 있을 것입니다. 사실 클라우드 기반의 웹 서비스는 달리 표현하면, 기본 골자는 로드밸런싱에 기반을 두고 있는 것이고, 그 이후의 확장성 전략을 클라우드 솔루션으로 채우는 것과 같다고 말할 수 있습니다. (어떤 뼈대를 사용할 것인지는 전적으로 여러분들의 선택에 달린 것입니다.)

로드 밸런싱 환경이란?

로드 밸런싱 기술 자체는 상당히 오래된 것입니다. 이름에서 알 수 있듯이, 몰려오는 트래픽을 내부적으로 분산하여 특정 서버 컴퓨터로 연결이 몰려 서비스가 사용 불가 상태로 빠지는 것을 "지연"시키거나 "완화"시키는 것에 목적이 있습니다. 로드 밸런싱의 기술적 개념도는 다음과 같습니다. (이미지 출처: http://msdn.microsoft.com/en-us/library/ff650667.aspx)

다양한 상황에서 로드밸런싱이 쓰이겠지만 가장 일반적으로는 웹 환경에서 많이 쓰입니다. 연결을 오래 유지할 필요가 없으면서도, 짧은 시간 내에 빠른 연결 회전을 보이는 웹 프로토콜에서 가장 중요한 것은 바로 신속성인데, 분산 처리를 하지 않는 경우에는 필연적으로 서버 컴퓨터가 받아들일 수 있는 동시 연결 한계치에 금방 치닫게 됩니다. 그러나 로드 밸런싱을 정확히 사용하면 이러한 한계치에 치닫게 되는 속도가 로드 밸런싱에 참가하는 컴퓨터의 댓수만큼 반비례하게 됩니다. 그리고 이 때 하나의 웹 사이트를 위한 로드 밸런싱 서비스에 멤버로 참여하는 서버 컴퓨터들을 묶어서 "웹 팜"이라고 정의를 하는 것이지요. 더 일반적으로는 "서버 팜"이라고도 합니다.

잠시 다른 이야기로 넘어가자면, 요즈음 대두되는 클라우드 컴퓨팅은 관리 측면에서 봤을 때, 충분한 대역폭을 보장하는 연결과 매우 뛰어난 성능을 가진 로드 밸런서를 이용하여 연결을 분산하는 작업을 수행하는 것입니다. 그리고 웹 팜 안에 참여하는 컴퓨터의 유형에 있어서는 이전과 다른 점이 하나 있는데, 마치 구름과 같이 수축과 팽창을 자유자재로 한다는 것입니다. 물론 이런 수축과 팽창이 가능함은 내부적으로 가상화 솔루션을 이용했다거나 여기에 대응할 수 있는 알고리즘을 사용했다는 가정이 깔려있는 것입니다.

정말 완벽하고 정확하게 구축했다면, 적은 전원이나 자원 공급으로도 충분히 웹 팜이 유지가 될 수도 있고, 필요하다면 웹 팜의 크기가 엄청나게 커질 수도 있겠지요. 이걸 여러분이 관리하신다면 프라이빗 클라우드, 신뢰할 수 있는 IT 기업이 관리한다면 퍼블릭 클라우드가 된다고 보실 수 있겠습니다. 그러나, 클라우드 컴퓨팅이 만능약처럼 들릴 수 있는 부분이 있지만 정확히 알아야 할 것은 클라우드 컴퓨팅 역시 이 로드 밸런싱을 기초로 만들어지는 것이고, 여러분이 운영할 수 있는 한계에까지 트래픽이 몰리거나, 이런 일을 하는 IT 업체에게 지불할 수 있는 재정의 한계에까지 트래픽이 몰린다면 이것이 여러분이 생각할 수 있는 클라우드의 한계입니다. 무제한이라고 해서 값이 저렴하거나 무료에 수렴하는게 아님을 명확히 이해하고 있어야 합니다.

웹 로드 밸런싱을 위한 이야기

다시 본론으로 돌아와서, 웹을 로드 밸런싱할 수 있으려면 무엇을 검토해야 할까요? 가장 중요한 것은 웹 서버에 참여하는 각각의 컴퓨터 자체에는 "절대로" 컴퓨터의 고유한 정보를 가지고 있으면 안된다는 점입니다. 매우 단순한 이야기같지만 이러한 원칙을 지키지 않도록 설계되어있는 것이 지금 이 시점까지의 서버 컴퓨팅 기술들의 대다수의 원칙입니다. 간단한 예를 들어볼까요?

여러분이 일상적으로 사용하는, 웹을 통한 파일 업로드 기능을 담당하는 간단한 웹 앱이 있다고 가정해 보겠습니다. 이 웹 앱은 서버가 한 대 일때에는 참 쉽고 빠르게 설치해서 쓸 수 있었습니다. 당연히, 설치를 잘 했다면, 사용자가 웹 페이지를 방문해서 파일을 업로드하면 웹 서버가 그것을 알아보고 파일을 회수해서 하드 디스크 어딘가에 저장하겠지요. 그러나 시간이 지나서 이 웹 앱의 기능을 업그레이드하고 좀 더 많은 사용자들이 파일을 저장하고 다운로드할 수 있도록 만들어보고자 해서 로드 밸런싱 환경을 구축하여 베타 테스트를 시작했습니다. 그런데 어떤 문제들이 생겼을까요?

앞서 이야기한 기술적인 특성때문에, 사용자들은 분명히 조금전까지 파일을 업로드했었는데 페이지를 다시 와서보니 파일이 업로드되지 않은 상태로 페이지가 나와서 혼란스러워합니다. 혹은 파일을 어디로 빼돌린거냐며 분노하는 사람들도 있구요. 그래서 몇 번 F5키를 누르다보면 "어라?"하고 놀라게 됩니다. 조금 전에 업로드했던 파일이 다시 나타나니까요. 그러고나서 그 파일을 다운로드하려고 링크를 클릭하면 이번엔 또 다시 404 오류를 만납니다. 이제 사용자들은 이 서비스에 대해서 대단한 분노와 원성을 쏟아낼 것입니다. 서비스 상태에도 일관성이 없을 뿐 아니라 불안정한것 같다. 믿을 수 없다면서요.

이것이 일선 IT 현장에서 로드 밸런싱이나 클라우드를 처음 접목했을 때 겪는 "가장 흔하고 일반적인 장애"입니다. 더 안타까운 것은, 이것을 신 기술에 의한 책임으로 회피하고 문제시하는 것입니다. 문제의 본질을 정확히 알고 있다면 이렇게 말하는 것이 왜 잘못인지도 금방 알 수 있을 것입니다.

여기서 든 예제처럼, 이 웹 앱의 문제는 단순히 업로드한 파일을 자신의 컴퓨터에 저장하려고 했다는 데에 문제가 있습니다. 로드 밸런싱 멤버로 참여하는 컴퓨터가 자신의 상태를 중요하게 여기면, 다음번에 이어받는 다른 서버 컴퓨터의 입장에서는 이전에 그 컴퓨터가 무엇을 했는지 알 길이 없습니다. 그저, 찾고자 하는 내용이 없음을 이야기하는 수 밖에 없습니다. 이런 상황이 반복되면서 서비스 전체는 들어올때와 나갈때가 전혀 다른, 일관성이 없고 이상한 서비스가 되는 것입니다.

이 문제를 해결하기 위하여 어떻게 수정해야 할까요? 답은 간단합니다. 파일 저장소를 로드 밸런싱 멤버 컴퓨터 내부가 아닌, 여러 멤버 컴퓨터들이 같이 이용할 수 있는 공용 저장소로 바꾸는 것입니다. 가장 간단한 방법은 네트워크 UNC 경로로 이용할 수 있는 스토리지가 있을 수 있습니다.

여기서 궁금한 점이 하나 더 있는데, 그렇다면 로드 밸런싱에 의하여 애써 분산한 서비스가 다시 모이는 것이 아니냐고 반문할 수도 있습니다. 그런데 사실, 생각외로 사용자들이나 웹 크롤러와 같이 인터넷 상에서 발생하는 별 뜻없이 바쁘게 만드는 다양한 유형의 트래픽을 웹 팜 수준에서 한 번은 로드 밸런싱을 해주는 것 만으로도 실제 스토리지에 대한 요구 사항은 획기적으로 감소한다는 점입니다. 거기다, 역할 분담도 정확히 할 수 있으며 스토리지 자체에 대한 요구 사항이 폭증하는 것을 방지하기 위하여 기술적으로는 좀 더 복잡해질 수 있지만 캐싱 기능을 사용할 수도 있습니다. 이렇게 함으로서, 우리가 흔히 잘 아는 클라우드 서비스의 시작을 뗄 수 있게 됩니다.

기술적인 이야기 1 - 세션 처리 방법 바꾸기

그렇다면 IIS와 ASP.NET에서는 이런 이상한 상황을 예방하고 신뢰할 수 있는 서비스를 만들기 위해서 어떤 수정 사항을 반영해야 하는 것일까요? 제가 이제까지 인터넷 상으로 자료 조사를 해왔던 것은 모두 제각기 흩어져있는 정보들이었고 이것을 한 번에 취합할 수 있는 방법을 오늘 블로그 포스팅을 통하여 소개할까 합니다.

기본적으로 ASP.NET은 세션 처리를 IIS 프로세스 안에서 수행하도록 되어있습니다. 가장 동선도 짧고, 신속하게 반응하기 때문입니다. 그러나 로드 밸런싱 환경에서 이는 당연히 "채택하면 안되는" 기법입니다. 이 방법은 web.config 파일 안의 <sessionState> 요소에서 변경할 수 있는 부분으로, <configuration> 요소 아래의 <system.web> 요소 아래에서 없는 경우 새로 지정할 수 있습니다. <sessionState> 요소의 mode 속성의 값을 변경하면 됩니다. 지금 이야기한 부분은 mode 속성이 InProc으로 지정되어있거나, 아무것도 지정되어있지 않을 때 .NET Framework의 글로벌 web.config 설정을 바꾸지 않은 경우 기본으로 지정되는 설정입니다.

IIS 7에서 볼 수 있는 아래 그림과 같은 설정도 이 XML 파일의 수정을 텍스트 에디터 없이 수정하는 것입니다.

로드 밸런싱 환경에서 정상적으로 동작하는 웹 사이트를 만들기 위해서는 mode의 설정 값을 InProc 대신 StateServer나 SQLServer로 바꾸어야 하는데, 양쪽 값 모두 장단점이 있습니다. StateServer의 경우 기본적으로는 꺼져있는 ASP.NET State Service라는 NT 서비스가 제공하는 별도의 서버를 이용하는 방식이고, SQLServer는 이름에서 알 수 있듯이 실제 SQL Server를 사용하여 세션을 구현하는 방식입니다. 데이터베이스 서버의 성능이 세션을 모두 수용할 수 있을만큼 획기적으로 뛰어나거나, 세션 서버가 죽었다가 살아나도 로그아웃 처리가 안되게 한다던가, 혹은 여러 로드 밸런싱 사이트 사이에서 세션 공유를 안전하게 할 방법이 필요하다면 이 모드를 사용할 수 있습니다. 이에 비하여 StateServer는 별도의 SQL 서버 없이도 간편하게 구축할 수 있는 방법을 제공하긴 하지만, 세션 서버가 죽었다 살아날 경우 내용이 없어지는 휘발성 세션입니다.

양쪽 모드 모두 중요한 것은 멤버로 참여하는 웹 서버 컴퓨터 밖에 상태를 보관해야 한다는 것이 키 포인트로, 이것을 지키지 않고 멤버 컴퓨터 안에 이런 설정을 구축하면 전혀 나아지는 것이 없습니다. 그리고 당연한 이야기이지만 멤버 컴퓨터로 참여하는 모든 웹 서버가 같은 설정을 가지고 있어야 합니다.

StateServer와 SQLServer 모드를 구현하는 방법에 대한 자세한 내용은 아래 아티클을 참고하시면 되겠습니다.

http://msdn.microsoft.com/ko-kr/library/ms178586.aspx

기술적인 이야기 2 - ASP.NET 사이트 간에 립싱크 맞추기

세션을 공유하는 것 이외에, ASP.NET은 내부적으로 Machine Key라는 것을 사용합니다. Machine Key의 용도는 ASP.NET 안에서 참 다양한데, 가장 대표적으로는 클라이언트와 서버 사이에 쿠키 정보를 주고 받을 때 암호화하기 위한 수단으로 이용하는 것이 유명한 사례입니다. 쿠키를 이용한 취약점 공격은 웹 세계에서 너무나 당연한 공격 방식 중 하나이기 때문에 ASP.NET은 처음부터 이를 보완하기 위한 전략을 구현하고 있었습니다. 그러나 이것이 지금 와서 로드 밸런싱 환경이 되면서는 또 다른 어려운 문제로 바뀐 것입니다.

이 Machine Key라는 것 역시 서버 컴퓨터마다 고유하게 생성할 뿐 아니라, 매번 연결할 때 마다 다른 값을 생성하여 암호화에 사용합니다. 클라이언트 입장에서야, 서버가 "ABC"라는 쿠키를 주니까 "아 그렇구나. 나중에 돌려주면 서버가 날 알아보겠지?"하며 성실하게 반납합니다. 그런데 로드 밸런싱에 참여하는 A라는 서버 대신 C라는 서버가 이 쿠키를 받아들었을 때는 "이거 내것 아님" 하며 클라이언트에게 퇴짜를 놓습니다. 이것이 문제의 핵심인 것이죠.

이 문제를 해결하기 위해서는 아까전에 이야기한 주제보다 좀 더 많은 노력이 필요합니다. 생각보다, 보안을 완벽하게 유지하기 위하여 ASP.NET이 관리자들에게 요구하는 사항이 까다롭기 때문입니다. 이 Machine Key를 만들기 위해서는 별도의 생성 도구를 사용해야 합니다. 그러나 안타깝게도 이 도구를 구한다거나 만들 수 있으려면 개발자들의 조력이 좀 필요합니다. 그리고 개발자 본인들도 이런 방법을 찾아야 하기때문에 꽤나 귀찮습니다. Codeproject에 가면 이러한 방법을 자세히 설명한 아티클도 있습니다만 간단한 도구도 드리고, 코드 조각도 드리니 프로그램에 넣어 활용하시면 더 편리할 것입니다.

using System;
using System.Text;
using System.Security.Cryptography;

/* 중략 */

        public static string getRandomKey(int bytelength)
        {
            byte[] buff = new byte[bytelength];
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            rng.GetBytes(buff);
            StringBuilder sb = new StringBuilder(bytelength * 2);
            for (int i = 0; i < buff.Length; i++)
                sb.Append(string.Format("{0:X2}", buff[i]));
            return sb.ToString();
        }

        public static string getASPNET20machinekey()
        {
            StringBuilder aspnet20machinekey = new StringBuilder();
            string key64byte = getRandomKey(64);
            string key32byte = getRandomKey(32);
            aspnet20machinekey.Append("<machineKey\n");
            aspnet20machinekey.Append(" validationKey=\"" + key64byte + "\"\n");
            aspnet20machinekey.Append(" decryptionKey=\"" + key32byte + "\"\n");
            aspnet20machinekey.Append(" validation=\"SHA1\" decryption=\"AES\"\n");
            aspnet20machinekey.Append("/>\n");
            return aspnet20machinekey.ToString();
        }

        public static string getASPNET11machinekey()
        {
            StringBuilder aspnet11machinekey = new StringBuilder();
            string key64byte = getRandomKey(64);
            string key24byte = getRandomKey(24);

            aspnet11machinekey.Append("<machineKey");
            aspnet11machinekey.Append(" validationKey=\"" + key64byte + "\"\n");
            aspnet11machinekey.Append(" decryptionKey=\"" + key24byte + "\"\n");
            aspnet11machinekey.Append(" validation=\"SHA1\"\n");
            aspnet11machinekey.Append("/>\n");
            return aspnet11machinekey.ToString();
        }

위의 코드를 사용하여 프로그램을 만들거나 ZIP 파일 안의 프로그램을 이용하여 값을 만들도록 하면 아래와 같은 XML 코드 조각을 얻을 수 있을 것입니다. 이 코드 조각을 각각의 서버에 들어있는 web.config에 지정하거나, 특정한 값만 인용하여 아래의 IIS 7 설정 아이콘에서 볼 수 있는 설정 도구를 통해서 직접 설정할 수도 있습니다.

<machineKey
 validationKey="FACBB6C89C44CB8BB7165FC4639BAA7267B...EF297D815E1BDD40E883E3451628CB95D34309"
 decryptionKey="4E95057676CC8DBA9AB...AACC1121B6B962E5AFA7849B0C82"
 validation="SHA1" decryption="AES"
/>

기술적인 이야기 3 - IIS에서 놓치면 안되는 것

ASP.NET을 가장 먼저 사용할 수 있게 된 웹 서버가 IIS이다보니 발생한 일종의 특성입니다만 여러 포럼에 걸쳐서 잘 언급되지 않는 문제점이 하나 있습니다. 바로 IIS에서 사용하는 사이트 ID 값을 통해서 정해지는 Application Path를 Machine Key와 같이 활용된다는 사실입니다. 웹 사이트 관리를 하다보면 로드 밸런싱에 참여하는 컴퓨터들을 다음과 같이 관리하게 되는 경우가 있습니다.

  • 서버 A에서는 기본 웹 사이트를 먼저 지우고 새 웹 사이트를 만들었다.
  • 서버 B에서는 새 웹 사이트를 먼저 만들고 기본 웹 사이트를 지웠다.

혹은 아래와 같은 경우도 있을 수 있습니다.

  • 서버 C에서는 사이트 A를 만들고 사이트 B를 만들었다.
  • 서버 D에서는 사이트 B를 만들고 사이트 A를 만들었다.

별 차이 없이 생각할 수 있지만, IIS에서는 이 경우 각각의 사이트들에 다른 ID 값을 부과하게 됩니다. 이 경우, 분명히 Machine Key를 동일하게 지정했음에도 불구하고 로드 밸런싱 환경에서 세션 상태가 일관성없게 변하는 문제를 만나게 됩니다. 제가 이번에 고민하게 된 부분도 바로 이 부분이었는데요, 이 문제를 해결하기 위해서는 IIS 7에서 전체 웹 사이트 목록에 나타나는 내용 중 다음의 ID 값이 멤버로 참여하는 웹 서버마다 차이가 있지 않은지 우선 검토해야 합니다.

위에있는 그림에서 빨간색으로 그린 부분이 서버 컴퓨터마다 차이가 있다면 이 값을 수정해주어야 합니다. 이 값을 수정하기 위해서는 수정할 사이트를 클릭하고, 고급 설정 링크를 아래 그림과 같이 클릭합니다.

이제 아래와 같은 팝업 대화 상자가 나타나면 강조 표시한 속성인 ID 값이 멤버로 참여하는 웹 서버 모두 같은 값을 가질 수 있도록 통일시켜줍니다.

확인 버튼을 누른 다음, ID 값이 바뀐 서버 컴퓨터에 한해서 IIS 전체를 재시작해주시거나 사이트 재시작을 시켜주시면 정상적으로 작동하게 될 것입니다.

Windows Azure 환경에서의 고려 사항

오늘 살펴본 내용은 IIS 7과 ASP.NET에 관한 부분이었지만, Windows Azure Platform의 경우에도 비슷한 문제가 있습니다. Windows Azure Platform에 VM Role로 웹 사이트를 게시를 하든, Web Role로 웹 사이트를 게시하든 세션을 사용하게 될 경우 비슷한 문제가 있을 수 있습니다.

다행히, Web Role을 이용한다면 내부적으로 사용하는 IIS에서 여러분이 몇 개의 웹 사이트를 추가적으로 구성하든 관계없이 같은 순서로 같은 ID를 사용하는 웹 사이트를 만들 것이므로 세 번째로 이야기한 ID 값 수정과 같은 작업은 할 필요가 없을 것입니다. 그러나 Machine Key에 대한 설정이나 세션 공유를 위한 설정은 SQL Azure를 이용한다거나, Worker Role에서 ASP.NET State Service 혹은 써드파티의 Session State Server를 이용해야 할 수 있습니다.

물론, 최근에 Windows Azure Platform의 일부로 Windows Azure AppFabric Cache가 새로 출시되기는 하였습니다만 상당히 이용 가격이 비싼 편입니다. (비싼만큼 확실한 성능을 제공합니다.) 로드 밸런싱 환경에서 특별한 문제를 일으키지 않는 일반적인 세션 공유가 필요하시다면 오늘 이야기한 주제를 응용한 Azure Project를 구축해보는 것도 의미가 있을 것입니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

PaaS2011. 2. 17. 16:37

인터넷 검색 중에 아주 흥미로운 웹 캐스트를 하나 발견하였습니다. 닷넷 기반 응용프로그램 프레임워크 전문 개발 업체인 DevForce를 기반으로 하는 Prism Explorer와 이에 연관된 Northwind 샘플 데이터베이스를 기초로 하는 엔터프라이즈 응용프로그램을 Windows Azure Platform의 Windows Azure Compute와 SQL Azure Database로 마이그레이션하는 웹 캐스트입니다. 기본적으로 이 동영상은 DevForce 프레임워크의 클라우드에서의 활용 가능성 및 실리성을 설명하기도 하지만, 동시에 Windows Azure Platform에 대한 실질적인 예를 들어주는 좋은 사례라 생각하여 블로그에 백서와 동영상에 대한 링크를 첨부하였습니다.

백서 다운로드 (English Only): http://www.ideablade.com/PDF/DevForceInAzure.pdf
동영상 출처 (English Only): http://www.ideablade.com/Videos/PrismExToAzure/
홈페이지: http://www.ideablade.com/DevForceProductPlatform/DevForceInAzure.aspx

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Exploring2011. 1. 12. 16:27

이 글은 http://www.boutell.com/newfaq/misc/urllength.html 의 내용을 인용하여 서술한 것으로 2006년 이후로 바뀐 내용들이 반영되어있지 않은 것들이 많습니다. 덧붙일 의견이 있으시면 언제든 말씀해주시면 반영하겠습니다. :-)

http://www.w3.org/Protocols/rfc2616/rfc2616.html 에서 설명하는 사양에도 최대 URL 길이에 대한 내용은 언급이 되어있지 않습니다. 하지만 웹 개발을 하면서 누구나 한번즈음은 이런 부분에 대해서 고민을 하게 될 때가 있는데, 그러한 고민을 풀어줄만한 아티클이 있어 소개해 봅니다.

Browser Case No. 1: Microsoft Internet Explorer

http://support.microsoft.com/kb/q208427/ 에서 언급한 것 처럼 Microsoft Internet Explorer는 내부 WININET 헤더 파일 상의 정의를 충실히 따릅니다. URL이 가질 수 있는 최대 길이는 2083자이고, 이 중 프로토콜, 서버 이름 등을 제외한 순수 경로가 2048자까지 허용이 됩니다. 이 글을 작성했던 분의 테스트 결과에 따르면 URL 길이가 긴 경우 브라우저 차원에서 오류 페이지를 띄운다는 것으로 결과가 나왔다고 합니다.

Browser Case No. 2: Firefox

버전 1.5.x의 경우 시각적으로 주소 표시줄은 65536번째 글자 이후로는 주소를 더 표시하지 못한다고 합니다. 그러나 논리적으로 십만글자 이상의 URL도 정상적으로 처리하는 것으로 보이며, 현재 출시되는 Firefox의 경우 이러한 제약이 거의 없지 않겠는가 하는 예상을 해봅니다.

Browser Case No. 3: Safari

적어도 8만자까지는 잘 동작한다고 합니다. :-)

Browser Case No. 4: Opera

긴 URL에 관해서는 종결자라고 해도 틀림없겠네요. 무려 19만자까지, 그것도 인라인 편집이 아닌 여러 행 편집이 가능한 컨트롤로 확장까지 가능하다고 합니다. >_<

Web Server Case No. 1: Apache

기본적으로 약 4000자까지는 허용하지만 그 이후부터는 413 Entity too large 오류가 발생한다고 합니다. 그러나 근래 개발되는 RHEL 기반에서의 Apache는 문서 상으로 약 8000자 이상까지 지원한다고 합니다.

Web Server Case No. 2: Microsoft Internet Information Services (IIS)

기본적으로 16384자까지 지원하며 이는 Microsoft Internet Explorer의 경우와는 상반되는 동작입니다. 게다가 설정도 가능합니다. 특별한 제약은 없겠지만 너무 긴 URL을 받아들이는건 상식적이지 않겠지요.

Web Server Case No. 2-1: ASP.NET

웹 서버 이야기는 아닙니다만 IIS에서 독자적인 처리 규정을 가지고 있는 서버 기반 처리 엔진에 대한 이야기를 하나 하자면, ASP.NET의 이야기를 해야 할 것 같습니다. ASP.NET 3.5 SP1 (내부 ASP.NET 2.0) 까지는 Windows의 시스템 상수 _MAX_PATH가 정의하는 범위 만큼의 URL만을 IIS의 설정과는 관계없이 받아들일 수 있었지만 ASP.NET 4.0부터는 Web.config 파일의 httpRuntime 요소의 maxQueryStringLength 속성에 의하여 확장이 가능합니다.

Web Server Case No. 3: Perl의 HTTP::Daemon

기본적으로 8000자까지 지원합니다. POST 메서드로 수신하게 되는 데이터를 제외하고 순수 HTTP 헤더는 16384바이트까지 지원하며 이 중 헤더에 들어있을 URL에도 이러한 제약이 적용됩니다. 즉, 헤더에 전달되는 내용과의 상관관계도 감안해야하므로 헤더의 양이 많은 경우 8000자보다 안되게 지원이 될 수도 있습니다. 보통은 8000자 이상의 URL로 요청을 하는 경우 413 오류가 발생합니다. 이러한 제약을 넘기위해서 Daemon.pm 파일 내의 16x1024라는 모든 표현식을 더 큰 값으로 수정하면 됩니다. 물론, 이런 동작을 하는 경우 당연한 이야기이지만 Denial of Service (DoS) 공격에 취약해질 수 밖에 없겠지요.

결론

이 글에서는 단순히 fact에 대해서만 살펴보았습니다. 기본적으로 URL이 필요 이상으로 길다고 하는 것 (그 기준이 정확하지는 않지만 상식적인 범위를 벗어나는, 가령 100글자 이상)은 정상적인 상황이 아닐 것입니다. 이 정도로 긴 URL을 보내야 한다면, 대개는 Query String이 그 원인일 것이므로, GET 방식 대신 POST 방식의 전송을 고려해보실 수 있습니다. 하지만 긴 URL을 유지해야 할 필요가 있다면 제가 원본으로 참조한 글의 끝자락에 있는 "The Bookmark Problem" 섹션을 참고하시기 바랍니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

  1. 몬난아

    조사도 안해보고 4096정도가 다른 브라우저들도 한계이거나 쿠키와 비슷한 크기가 한계일꺼라고 생각햇는데 ㅎㅎ
    좋은정보내요 OPERA.. 좀 짱인듯

    2011.01.14 13:34 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 조사를 해 볼 일이 없는 부분이긴 하지요. 4KB도 사실은 크고 1KB만 해도 충분할거라고 생각해요. ㅎㅎ 하지만 워낙에 재미있는 아티클이라 번역 겸 해서 퍼왔습니다. URL이 너무 길게 들어가는 것 자체는 비상식적인 상황이라 생각합니다. :-)

      2011.01.15 15:18 신고 [ ADDR : EDIT/ DEL ]
  2. 브라우저 별로 살펴볼 수 있으니 재미가 있네요.
    말씀하신 것 처럼 긴 URL로 뭔가 얍삽이를 써보려는 것은 좋지 않다는 것에 동의합니다.

    2011.01.17 23:39 신고 [ ADDR : EDIT/ DEL : REPLY ]
  3. 재미있는 내용이에요!!! 잘 보고 갑니다! >_<

    2011.03.03 11:12 신고 [ ADDR : EDIT/ DEL : REPLY ]

이벤트2011. 1. 4. 22:51

등록 사이트로 바로 가기: https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032473907&Culture=ko-KR



쉽고 빠르게 완성하는 Easy My Web Project
세미나 일시 : 2011. 01. 21(금) / 14:00~18:00
세미나 장소 : 섬유센터 이벤트홀(삼성동)
세미나 참석 대상 : Web 개발자 & 디자이너, 그리고 Web 개발에 관심있는 모든 분들

“오늘 다시 웹 개발에 대해 이야기 하자!”

웹개발이 당연한 것이 되었다고 이야기들 하지만,
소셜과 모바일이 찾아 온 지금,
우리에게 웹을 하나씩 갖는 일은 어느 때보다 중요해졌습니다.
더 유연하게, 더 쉽게, 더 빨리, 더 싸게, 웹사이트를, 소셜 사이트를,
앱서버와 앱사이트를, 모바일 사이트를 모두 만들 수는 없을까요?

지금 전혀 새로운 지평이 펼쳐지려 하고 있습니다.
지금까지 우리가 알고 또 다루어 왔던 웹이 전혀 새로운 차원에서 유연하고 쉬워지려 하고 있습니다. ?

1월 21일 이 새로운 매트릭스로 여러분을 초대합니다.


웹개발의 신조류에 대해 이야기하자!
PHP에서 新ASP.NET, 소셜에서 모바일, 오픈소스활용에서 자체개발까지 이보다 쉬울 수 없는 웹개발 신조류
ASP.NET이 PHP보다 쉬워졌다?
ASP.NET 최신 동향과 최신 사례 소개
오픈소스 패키지를 3분만에 요리하고 서빙하기.
웹매트릭스 지원 호스터의 쇼케이스
이제 정말 내일의 웹개발에 대해 이야기하자!
패널 디스커션

 
등록 사이트로 바로 가기: https://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032473907&Culture=ko-KR

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

이벤트2010. 9. 6. 23:45

참가 신청 바로 가기: http://onoffmix.com/event/1787


  • 주최 : 한국 Visual Studio 공식 팀
  • 일시 : 2010년 9월 28일 오후 7시 ~ 10시
  • 장소 : 한국 마이크로소프트 - 포스코 센터 5층
  • 참가비 : 무료
  • 최근 쏟아지는 기술의 홍수 속에서 '아차~' 하고 눈 깜빡할 순간 신기술에 낙오되기 쉽습니다. 한 번은 괜찮지만, 두 번은 기술 트랜드를 따라잡기가 더 힘들어 집니다. 저희 팀에서 기술을 먼저 접해보고, 먼저 고민해본 살아있는 경험을 여러분들에게 전수해 드립니다.
  • 세미나 아젠다

    시간

    세션 내용

    19:00 ~ 19:30

    등록

    19:30 ~ 20:10

    현실적인 클라우드 컴퓨팅 이야기

    남정현 C# MVP

    20:20 ~ 21:00

    Expression Blend 와 함께하는 윈도우 폰 7 개발 입문

    조진현

    21:10 ~ 21:50

    Razor 로 열어가는 새로운 ASP.NET

    김시원 ASP.NET MVP

      

       

    발표 내용 소개

    현실적인 클라우드 컴퓨팅 이야기 / 남정현 C# MVP

    클라우드 컴퓨팅, 말로만 들어봤지 실제로 어디에 어떻게 사용이 될 수 있는지 알려주는 사람이 없어 답답할 때가 많습니다. 이번 세션에서는 클라우드 컴퓨팅에 관한 실질적인 이야기, 그 중에서도 특별히 마이크로소프트의 윈도 애저 플랫폼에 대한 이야기를 나누면서, 클라우드 컴퓨팅의 현실적인 사례를 간단히 들어보기로 하겠습니다.

      

    Expression Blend 와 함께하는 윈도우 폰 7 개발 입문 / 조진현

    윈도우 폰7 개발에 대한 간단한 소개와 방법에 대해서 살펴본다. 그리고 더 쉽고 편한 개발을 위한 고민을 해보며, 이를 위해서 Expression Blend 의 활용에 대해서 고민해 본다.

      

    Razor 로 열어가는 새로운 ASP.NET - 김시원 ASP.NET MVP

    Razor 는 차세대 ASP.NET 의 새로운 View Engine 으로써 , 이것 때문에 요즈음 ASP.NET 이 한창 주목 받고 있습니다. 이번 시간에는 Razor 의 등장배경과 함께 Razor 로 인해 개발 환경이 어떻게 변화하였는지 살펴보고 , 기본적인 Razor 의 사용법을 익혀보도록 하겠습니다.

    발표자 소개

    남정현 C# MVP

    (주)코아뱅크에 재직 중이며, Microsoft Visual C# MVP로 활동 중입니다. DEVPIA C# Forum SYSOP, Windows Azure Cafe SYSOP을 맡고 있습니다. 여러 커뮤니티와 개인 블로그, 트위터 (@rkttu)를 통하여 윈도 애저 플랫폼에 대한 다양한 이야기를 전파하고 있습니다.

    조진현

    현재 게임 개발자로 재직 중이며  Visual Studio 2010 공식 팀 블로그 (http://vsts2010.net) 에서 DirectX 관련 분야에서 활동 중이다. 최근에는 '김탁구'와 '나는 전설이다' 라는 드라마에 빠져서 살고 있다.

      

     

    김시원 ASP.NET MVP
    ASP/ASP.NET MVP를 2009년 부터 계속 유지해오고 있으며 다양한 형태의 웹 어플리케이션 개발 경험과 세미나 경험을 가지고 있다. 현재 Hugeflow 웹 솔루션 개발팀에서 개발의욕을 불사르고 있다. 세상을 풍요롭게 하고 사람들에게 강한 종속성을 부여하는 프로그램을 개발하는 것이 목표이다.

    오시는 길

    한국 마이크로소프트 - 포스코 센터 5층

     

    참가 신청 바로 가기: http://onoffmix.com/event/1787


    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    이벤트2010. 8. 19. 15:13

    Microsoft PDC (Professional Developer Conference)는 매년 Microsoft의 주최로 열리는 세계적인 규모의 개발자 컨퍼런스 행사로, Microsoft의 최신 기술들을 가장 완벽한 형태의 내용으로 접할 수 있는 최고의 리소스입니다. 올해도 어김없이 열립니다. :-D

    Microsoft 본사가 있는 미국 레드먼드에서 2010년 10월 28일부터 10월 29일 이틀간 열리는 이번 PDC10 행사에서는 크게 세 가지 주제를 바탕으로 세션들이 배치되고 트랙이 나뉘어지게 됩니다. Windows Azure Platform에 대한 새로운 업데이트와 고급 응용프로그램 개발 전략을 소개할 Cloud Track, 곧 베타 버전 발표를 앞두고 있는 Windows Internet Explorer 9과 여기에 맞추어 지원될 HTML 5, 그리고 조만간 정식 출시를 눈앞에 두고 있는 Windows Phone 7 Series에 대한 다양한 내용을 소개할 Client Track, 그리고 작년 PDC09 행사에 이어서 ASP.NET MVC 3, Razor, Web Matrix, Visual Studio LightSwitch와 같이 새롭게 소개되는 Framework에 연관되어있는 다양한 기술들을 소개할 Framework Track으로 구성될 예정입니다. 아래는 미국 현지 시간 기준 전체적인 행사 Agenda입니다.

    Wednesday, October 27, 2010 
    7:00pm – 9:00pm: Welcome Reception - Microsoft Visitor's Center, Bldg 92 

    Thursday, October 28, 2010 
    7:00am – 5:00pm: Registration 
    9:00am – 11:00am: Keynote 
    11:00am - 12:00pm: Sessions 
    12:00pm – 1:30pm: Lunch 
    1:30pm – 5:00pm: Sessions 
    6:00pm – 10:00pm: Attendee Party - Lucky Strike, Bellevue, WA 

    Friday, October 29, 2010 
    7:30am – 5:00pm: Registration 
    9:00am – 12:00pm: Sessions 
    12:00pm – 1:30pm: Lunch 
    1:30pm – 5:00pm: Sessions 
    5:00pm: Conference Ends 

    아쉽게도, 이미 행사 좌석이 모두 가득찬 상태라서 오프라인 행사를 직접 즐기실 수는 없겠지만, 온라인 생중계 서비스와 향후 PDC10이 종료된 이후에라도 주문형으로 비디오를 시청할 수 있도록 스트리밍 서비스를 계속 이어 나갈 예정이라고합니다. 생중계 서비스는 키노트 세션이 열리는 2010년 10월 28일 오전 9시부터 시작될 예정이며, 한국 시간으로는 2010년 10월 29일 오전 1시부터 PDC10 웹 사이트에서 보실 수 있습니다.

    좀 더 자세한 정보는 PDC10 행사 홈페이지 (http://www.microsoftpdc.com) 을 방문하시면 되겠습니다. :-)

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    PaaS2010. 8. 10. 00:00

    지난번 글 (2010/07/27 - [Cloud Development] - Hello Windows Azure / Twitter 스타일 방명록 만들기 #1)에 이어서 오늘 시간에는 ASP.NET MVC 2를 사용하는 Web Role 위에서 jQuery, jTemplate을 이용하여 기본적인 방명록 UI를 꾸며보고, 별 다른 Worker Role의 구현 없이 Windows Azure Table Storage를 경유하여 방명록의 글을 삽입, 삭제, 변경하는 기능을 구현해보기로 하겠습니다.

    시작하기 전에 (2010.08.09 Update)

    지난번 코드에서 누락되거나 교정될 필요가 있는 코드를 포함하여 업데이트를 할 부분이 있어 말씀을 전합니다. TwistDataSource.cs 파일의 내용을 다음과 같이 작성해야 하며, 지난번 코드에서 변경된 부분을 밑줄로 표시해두었습니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.WindowsAzure;
    using System.Data.Services.Client;
    using Microsoft.WindowsAzure.StorageClient;

    namespace TwistBook.DataModel
    {
        public class TwistDataSource
        {
            private static CloudStorageAccount storageAccount;
            private TwistDataServiceContext serviceContext;

            static TwistDataSource()
            {
                // 중요: 실제로 응용프로그램을 Cloud 환경에 배포할 때에는
                // Cloud Project 내의 다른 환경 설정 문자열을 이용하도록
                // 호출을 변경해야 합니다.
                storageAccount = CloudStorageAccount.DevelopmentStorageAccount;

                CloudTableClient.CreateTablesFromModel(
                    typeof(TwistDataServiceContext),
                    storageAccount.TableEndpoint.AbsoluteUri,
                    storageAccount.Credentials);
            }

            public TwistDataSource()
            {
                this.serviceContext = new TwistDataServiceContext(storageAccount);
                this.serviceContext.RetryPolicy = RetryPolicies.Retry(
                    3, TimeSpan.FromSeconds(1));
            }

            public DataServiceResponse Insert(TwistModel model)
            {
                this.serviceContext.AddObject(
                    TwistDataServiceContext.TwistModelName,
                    model);

                return this.serviceContext.SaveChangesWithRetries();
            }

            public IEnumerable<TwistModel> Select()
            {
                var results = from eachTwist in this.serviceContext.TwistModel
                              select eachTwist;

                var query = new CloudTableQuery<TwistModel>(
                    results as DataServiceQuery<TwistModel>,
                    RetryPolicies.Retry(3, TimeSpan.FromSeconds(1)));

                return query.Execute();
            }

            public DataServiceResponse Delete(TwistModel model)
            {
                // 이 부분의 코드가 삭제되었습니다.
                this.serviceContext.DeleteObject(model);
                return this.serviceContext.SaveChanges();
            }

            public DataServiceResponse Update(TwistModel model)
           
    {
               
    this.serviceContext.UpdateObject(model);
               
    return this.serviceContext.SaveChanges();
            }

        }
    }

    Web Role 완성하기

    1. ASP.NET MVC 2 응용프로그램의 특성을 잘 살리기 위하여 AJAX 기술을 활용하는 방식으로 예제를 설명하고자 합니다. 이를 위하여 필요한 것이 jQuery와 jTemplate 라이브러리인데, jQuery의 경우 ASP.NET MVC 2 프로젝트를 만들면 자동으로 아래의 Scripts 디렉터리에 1.4 버전이 번들링되어있으니 별도로 받으실 필요가 없습니다.

     

    자바스크립트 라이브러리들의 경우, 근래 들어서는 4GL 개발 도구들의 영향으로 Debug Version과 Release Version 라이브러리를 각기 개별적으로 제공하는 경우가 늘었습니다. jQuery도 이러한 추세를 잘 따르고 있으며, 위의 화면에서 jquery-1.4.1-vsdoc.js 파일은 Debug 목적 + Visual Web Developer용 Intellisense 지원을 위한 버전이고, jquery-1.4.1.js 파일은 원래의 소스 코드가 있는 그대로 (as-is) 제공되는 버전입니다. 그리고 jquery-1.4.1.min.js 파일은 원래의 소스 코드에서 주석과 공백 제거, 변수명 최소화와 같은 Obfuscation Process를 포함한 Minified Process를 거친 전송에 최적화된 버전입니다.

    자바스크립트 전송에 필요한 대역폭을 좀 더 아낄 필요가 있고, 접속하는 브라우저들이 모두 G-ZIP 압축 해제 기능을 지원한다는 점을 확신할 수 있다면, WSFU (Windows Service For Unix)나 Cygwin, GNU for Win32 등을 통해서 액세스할 수 있는 GZIP 압축 유틸리티를 이용하여 Minified Version을 GZIP 파일로 한 번 더 묶어서 이를 다운로드하도록 구성하는 것도 좋은 선택이 될 수 있습니다. WSFU는 http://www.microsoft.com/downloads/details.aspx?FamilyID=896c9688-601b-44f1-81a4-02878ff11778&DisplayLang=en 에서 다운로드 가능합니다.

    2. jTemplate은 jQuery를 기반으로 만들어진 플러그인으로 HTML이나 XML 컨텐츠를 지정된 지시자에 맞추어 반복 생성하거나, 내용을 치환하거나, 수식을 계산하는 등의 복잡한 연산 작업을 가능하게 합니다. 특히 JSON (Java Script Object Notation) 기반의 데이터를 내려보내어줄 것이므로 이러한 기능은 필수적입니다. jTemplate은 http://plugins.jquery.com/project/jTemplates 에서 다운로드받으실 수 있고, 압축 파일을 다운로드받으면 아래와 유사한 형태로 나타납니다.

    3. jquery-jtemplates.js 파일을 선택하여 ASP.NET MVC 2 프로젝트의 Scripts 디렉터리 아래로 복사합니다. jQuery 라이브러리와 같은 위치에 배치하여 불러오기 쉽도록 만들기 위한 선택입니다.

    4. Visual Studio 솔루션 탐색기에서 방금 압축 해제한 jTemplate 라이브러리의 소스 코드를 추가해야 합니다. 솔루션 탐색기에서 Web Role 프로젝트 아래의 Scripts 디렉터리를 아래 그림과 같이 클릭하고 상단 도구 모음의 "모든 파일 표시" 버튼을 클릭하면 아직 등록되지 않은 jTemplate 라이브러리의 파일이 나타납니다.

     

    5. jquery.jtemplates.js 파일을 오른쪽 버튼으로 클릭하고 "프로젝트에 포함" 메뉴를 클릭하면 솔루션의 일부로 편입됩니다. 이 때, jquery.jtemplates.js 파일을 오른쪽 버튼으로 클릭하고 속성 메뉴를 선택하여 나타나는 속성 창에서 빌드 작업이 "내용"으로 선택되어있는지 반드시 확인하여 주세요. "내용"으로 선택되어있지 않은 파일은 실제 배포 때 제외될 수도 있습니다.

    6. 이제 마스터 페이지에 jQuery와 jTemplate 라이브러리를 추가해야 합니다. 여기서 마스터 페이지란 페이지 전반에 걸쳐서 기본 바탕이 되는 ASP.NET 사이트 수준의 골격 템플릿입니다. PowerPoint의 마스터 슬라이드와 비슷한 개념으로 이해해도 됩니다. 마스터 페이지는 Views 폴더 아래의 Shared 폴더 아래의 Site.Master 파일이며 아래와 같은 위치에 나타납니다.

    7. Site.Master 파일을 열어서 아래와 같이 수정합니다. 원래 내용에서 수정된 부분을 굵게 표시하였으며 자세한 내용은 각주를 참조하여 주십시오.

    <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
        <link href="<%= Url.Content("~/Content/Site.css") %>" rel="stylesheet" type="text/css" /> [각주:1]
        <script type="text/javascript" src="<%= Url.Content("~/Scripts/jquery-1.4.1.min.js") %>"></script> [각주:2]
        <script type="text/javascript" src="<%= Url.Content("~/Scripts/jquery-jtemplates.js") %>"></script> [각주:3]

    </head>

    <body>
        <div class="page">

            <div id="header">
                <div id="title">
                    <h1>내 MVC 응용 프로그램</h1>
                </div>
                 
                <div id="logindisplay">
                    <% Html.RenderPartial("LogOnUserControl"); %>
                </div>
               
                <div id="menucontainer">
               
                    <ul id="menu">             
                        <li><%: Html.ActionLink("홈", "Index", "Home")%></li>
                        <li><%: Html.ActionLink("정보", "About", "Home")%></li>
                    </ul>
               
                </div>
            </div>

            <div id="main">
                <asp:ContentPlaceHolder ID="MainContent" runat="server" />

                <div id="footer">
                </div>
            </div>
        </div>
    </body>
    </html>

    8. 웹 페이지를 위한 기본 준비는 끝났습니다. 이제 Twitter Style의 방명록을 입력받을 수 있고 보여줄 수 있는 서비스를 만들기 위하여 서비스의 중심이 되는 Controller를 구성해보도록 하겠습니다. 편의를 위하여 HomeController를 편집하도록 하겠습니다. 솔루션 탐색기에서 TwistBook.WebRole 프로젝트의 Controllers 폴더 아래의 HomeController.cs 파일을 아래 그림과 같이 선택하여 엽니다.

    9. ASP.NET MVC에서 컨트롤러 내에서 Public 접근자로 노출된 각각의 Method는 이전의 ASP.NET Web Form에 비유하였을 때 개별 처리기 (ASHX 파일)에서 웹 페이지를 결정하여 내보내는 것과 같은 개념으로 최초에 사용자가 페이지에 접근할 때나, 페이지의 FORM 태그로부터 응답이 되돌아온 시점에서 모두 사용이 가능합니다. 이러한 특성을 바탕으로, HomeController는 그 자체로 API의 역할을 수행할 수 있으며 역으로 페이지를 렌더링하기 위한 컨텐츠 단위로서의 역할도 수행이 가능합니다.

    HomeController.cs 파일의 내용을 아래와 같이 수정합니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient;
    using TwistBook.DataModel;

    namespace TwistBook.WebRole.Controllers
    {
        [HandleError]
        public class HomeController : Controller
        {
            public HomeController()
                : base()
            {
            }

            public ActionResult Index()
            {
                ViewData["Message"] = "Windows Azure 방명록 예제";
                return View("Index"); [각주:4]
            }

            [HttpPost] [각주:5]
            public ActionResult RetrieveMessages()
            {
                var account = CloudStorageAccount.DevelopmentStorageAccount;
                var dataSource = new TwistDataSource();

                var results = from eachItem in dataSource.Select()
                              orderby eachItem.WrittenDate descending
                              select eachItem;

                return Json(results); [각주:6]
            }

            [HttpPost]
            public ActionResult AddMessage(string name, string message, string imageUrl)
            {
                var account = CloudStorageAccount.DevelopmentStorageAccount;
                var dataSource = new TwistDataSource();
                dataSource.Insert(new TwistModel()
                {
                    WriterName = name,
                    WrittenDate = DateTime.Now,
                    MessageBody = message,
                    ImageUrl = imageUrl
                }); [각주:7]

                return Index(); [각주:8]
            }

            public ActionResult UpdateMessage(string partitionKey, string rowKey) [각주:9]
            {
                var account = CloudStorageAccount.DevelopmentStorageAccount;
                var dataSource = new TwistDataSource();
                var results = from eachItem in dataSource.Select()
                              where eachItem.PartitionKey == partitionKey
                              where eachItem.RowKey == rowKey
                              select eachItem;

                ViewData["PartitionKey"] = partitionKey;
                ViewData["RowKey"] = rowKey; [각주:10]

                if (results.Count() > 0)
                {
                    var result = results.First();
                    ViewData["Name"] = result.WriterName;
                    ViewData["Message"] = result.MessageBody; [각주:11]
                }

                return View();
            }

            [HttpPost]
            public ActionResult UpdateMessage(string partitionKey, string rowKey, string name, string message, string imageUrl) [각주:12]
            {
                var account = CloudStorageAccount.DevelopmentStorageAccount;
                var dataSource = new TwistDataSource();
                var results = from eachItem in dataSource.Select()
                              where eachItem.PartitionKey == partitionKey
                              where eachItem.RowKey == rowKey
                              select eachItem;

                if (results.Count() > 0)
                {
                    var result = results.First();

                    if (result != null)
                    {
                        result.WriterName = name;
                        result.MessageBody = message;
                        result.WrittenDate = DateTime.Now;
                        result.ImageUrl = imageUrl;
                        dataSource.Update(result);
                        return View("PopupUpdateView"); [각주:13]
                    }
                    else
                        return View("PopupUpdateFailView");
                }
                else
                    return View("PopupUpdateFailView"); [각주:14]
            }

            public ActionResult DeleteMessage(string partitionKey, string rowKey)
            {
                var account = CloudStorageAccount.DevelopmentStorageAccount;
                var dataSource = new TwistDataSource();
                var results = from eachItem in dataSource.Select()
                              where eachItem.PartitionKey == partitionKey
                              where eachItem.RowKey == rowKey
                              select eachItem;

                if (results.Count() > 0)
                {
                    dataSource.Delete(results.First());
                    return Index(); [각주:15]
                }
                else
                    return Index();
            }

            public ActionResult About()
            {
                return View();
            }
        }
    }

    10. 방명록의 기본 기능을 만들기 위하여 이제 Views 폴더 아래의 Home 폴더 아래의 Index.aspx 파일을 열어서 편집해야 합니다. 아래 그림과 같은 위치에 존재합니다.

    <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

    <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
        홈 페이지
    </asp:Content>

    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
        <script type="text/javascript">
            $(document).ready(function () {
                $.ajax({
                    type: 'POST', [각주:16]
                    url: '<%= Url.Action("RetrieveMessages") %>', [각주:17]
                    data: '{}',
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json', [각주:18]
                    success: function (data) {
                        var targetDiv = $('#guestbookList');  [각주:19]
                        targetDiv.setTemplate($('#templateContent').html()); [각주:20]
                        targetDiv.processTemplate(data); [각주:21]
                    }
                });
            });
        </script>
       
        <script type="text/html" id="templateContent">
        {#foreach $T as record}
        <div style="padding-bottom: 5px;">
            <img src="{$T.record.ImageUrl}" alt="" style="float: left; width: 100px;" />
            <div style="float: left; margin: 5px 5px 5px 5px;">
                <h3>RT @{$T.record.WriterName} {$T.record.MessageBody}</h3>
                <pre>{$T.record.WrittenDate} via cloud</pre>
                <a href="#" onclick="window.open('<%= Url.Content("~/Home/UpdateMessage") %>?partitionKey={$T.record.PartitionKey}&rowKey={$T.record.RowKey}', 'editWindow', 'location=1,status=1,scrollbars=1,width=300,height=200');">편집</a>
                &nbsp;|&nbsp;
                <a href="<%= Url.Content("~/Home/DeleteMessage") %>?partitionKey={$T.record.PartitionKey}&rowKey={$T.record.RowKey}" target="_self">삭제</a>
            </div>
            <div style="clear: both;"></div>
        </div>
        {#/for}
        </script> [각주:22]

        <h2><%= ViewData["Message"] %></h2>
        <div>
            <div>
                <% using (var form = Html.BeginForm("AddMessage", "Home", FormMethod.Post))
                   { %> [각주:23]

                   <%: Html.Label("이름") %>
                   <%: Html.TextBox("name", "What is your name?") %> [각주:24]
                   <br />

                   <%: Html.TextArea("message", "Type your message here.", 3, 100, null) %>
                   <br /> [각주:25]

                   <input type="submit" value="보내기" />&nbsp;<input type="reset" value="초기화" /> [각주:26]
                   <br />
                <% } %>
            </div>
            <br /><br />
            <div id="guestbookList"></div> [각주:27]
        </div>
    </asp:Content>

    11. 방명록 내용을 편집하기 위한 팝업 창을 위한 뷰와, 댓글 편집이 끝난 뒤 취할 동작을 프로그래밍한 자바스크립트 코드를 위한 뷰는 Partial View로 디자인해야 합니다. 이 중에서 우선 방명록 항목 편집을 위한 Partial View를 추가하기 위해, 솔루션 탐색기에서 Views 디렉터리 아래의 Home 디렉터리를 오른쪽 버튼으로 클릭하고, View 추가 메뉴를 아래 그림과 같이 선택합니다.

    12. View의 이름은 UpdateMessage로 지정하고, Partial View에 체크하여 아래 대화 상자와 같이 옵션을 구성한 후 확인 버튼을 클릭합니다.

    13. UpdateMessage.ascx 파일의 내용을 다음과 같이 작성합니다.

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
    <div>
        <% using (var form = Html.BeginForm("UpdateMessage", "Home", FormMethod.Post))
           { %> [각주:28]

           <%: Html.Hidden("partitionKey", ViewData["PartitionKey"]) %>
           <%: Html.Hidden("rowKey", ViewData["RowKey"]) %> [각주:29]

           <%: Html.Label("이름") %> 
           <%: Html.TextBox("name", (string)ViewData["Name"]) %> [각주:30]
           <br />

           <%: Html.TextArea("message", (string)ViewData["Message"], 3, 100, null) %>[각주:31]
           <br />

           <input type="submit" />&nbsp;<input type="reset" /> [각주:32]
           <br />
        <% } %>
    </div>

    14. 이어서 솔루션 탐색기에서 Views 디렉터리 아래의 Home 디렉터리를 오른쪽 버튼으로 클릭하고, View 추가 메뉴를 11단계에서와 같이 선택합니다.

    15. View의 이름은 PopupUpdateView로 지정하고, Partial View에 체크하여 아래 대화 상자와 같이 옵션을 구성한 후 확인 버튼을 클릭합니다.

    16. PopupUpdateView.ascx 파일의 내용을 다음과 같이 작성합니다.

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
    <script type="text/javascript">
        try {
            window.close(); [각주:33]
            if (window.opener && !window.opener.closed) {
                window.opener.location.href = '<%= Url.Content("~/Home/Index") %>'; [각주:34]
            }
        } catch (ex) {
        }
    </script>

    17. 이어서 솔루션 탐색기에서 Views 디렉터리 아래의 Home 디렉터리를 오른쪽 버튼으로 클릭하고, View 추가 메뉴를 11단계에서와 같이 선택합니다.

    18. View의 이름은 PopupUpdateFailView로 지정하고, Partial View에 체크하여 아래 대화 상자와 같이 옵션을 구성한 후 확인 버튼을 클릭합니다.

    19. PopupUpdateFailView.ascx 파일의 내용을 다음과 같이 작성합니다.

    <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
    <h3>업데이트에 실패하였습니다.</h3>
    <a href="#" onclick="window.close()">창 닫기</a>

    20. 기본적인 방명록 글 남기기와 조회 기능이 올바르게 작동하는지 확인하기 위하여 시뮬레이터를 디버그 모드로 시작해야 합니다. 일반적인 응용프로그램 개발 때와 마찬가지로 F5키를 눌러서 디버그 모드로 시뮬레이터에 패키지를 배포하고 디버거를 연결할 수 있습니다. 이 때, 아래 그림과 같은 오류 메시지가 나타나면 관리자 권한이 아닌 상태에서 Visual Studio를 시작한 것이므로 Visual Studio를 종료한 뒤 "개발 도구 시작하기 및 프로젝트 생성하기" Chapter의 1단계를 참고하여 관리자 모드로 Visual Studio를 다시 시작해야 합니다.

    21. 아래의 그림들에서처럼 기능들이 정상적으로 진행된다면 우선 이번 시간에 진행할 기본 기능들에 대한 소개와 작업이 끝난 것입니다.

    이번 Article을 작성하면서 발견한 Windows Azure SDK 1.2에 대한 문제 한 가지

    좀 더 완성에 가까워질수록 해결될 문제들 중에 한 가지가 될 예정이긴 하겠습니다만 실습하는 도중 불편함이 예상되어 제가 발견한 문제를 블로그 아티클을 통하여 미리 공유하고자 합니다. 간혹 Windows Azure Local Storage의 Table Storage에 아래와 같이 MBCS (Multi-Byte Character Set) 문자가 포함된 데이터를 삽입하려고 할 때 별 다른 까닭없이 HTTP/404 오류가 나타나는 경우가 있습니다.

    사용자 코드에서 System.Data.Services.Client.DataServiceRequestException이(가) 처리되지 않았습니다.
      Message=이 요청을 처리하는 동안 오류가 발생했습니다.
      Source=Microsoft.WindowsAzure.StorageClient
      StackTrace:
           위치: Microsoft.WindowsAzure.StorageClient.Tasks.Task`1.get_Result()
           위치: Microsoft.WindowsAzure.StorageClient.Tasks.Task`1.ExecuteAndWait()
           위치: Microsoft.WindowsAzure.StorageClient.TaskImplHelper.ExecuteImplWithRetry[T](Func`2 impl, RetryPolicy policy)
           위치: Microsoft.WindowsAzure.StorageClient.TableServiceContext.SaveChangesWithRetries(SaveChangesOptions options)
           위치: Microsoft.WindowsAzure.StorageClient.TableServiceContext.SaveChangesWithRetries()
           위치: TwistBook.DataModel.TwistDataSource.Insert(TwistModel model) 파일 d:\users\남정현\documents\visual studio 2010\Projects\TwistBook\TwistBook.DataModel\TwistDataSource.cs:줄 42
           위치: TwistBook.WebRole.Controllers.HomeController.AddMessage(String name, String message, String imageUrl) 파일 d:\users\남정현\documents\visual studio 2010\Projects\TwistBook\TwistBook.WebRole\Controllers\HomeController.cs:줄 44
           위치: lambda_method(Closure , ControllerBase , Object[] )
           위치: System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
           위치: System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
           위치: System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
           위치: System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a()
           위치: System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
      InnerException: System.Data.Services.Client.DataServiceClientException
           Message=<?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
      <code>InvalidInput</code>
      <message xml:lang="ko-KR">One of the request inputs is not valid.</message>
    </error>
           Source=System.Data.Services.Client
           StatusCode=400
           StackTrace:
                위치: System.Data.Services.Client.DataServiceContext.SaveResult.<HandleBatchResponse>d__1e.MoveNext()
           InnerException:



    실제 Windows Azure 실행 환경에서는 이러한 현상이 나타나지 않는 것으로 보입니다. 추후, 이러한 문제점을 해결할 수 있는 방안이 발견되면 별도의 업데이트 소식을 통하여 정보가 전달될 수 있도록 하겠습니다. 예제를 기반으로 테스트 패브릭 위에서 테스트하시는 동안에는 Table Storage에 한글, 히라가나, 카타카나, 번체, 간체, 한자 등의 데이터가 들어가지 않는 범위에서 테스트가 필요할 것 같습니다.

    다음 시간에는

    다음 시간에는 각 Role이 어떤 방법으로 Windows Azure 환경에서 실행되는지, Web Role과 Worker Role이 Cloud Computing 환경에서 상호 작용하고 통신하는 방법을 본격적으로 소개하고, 오늘 만든 Web Role을 어떤 방식으로 수정하게 될 것이고, Worker Role이 어떤 방식으로 데이터를 교환하게 될 것인지를 보여드릴 예정입니다. 그리고 이번 시간에 언급하지 않은 BLOB Storage에 이미지를 저장하고 가져오는 방법에 대해서도 소개하겠습니다. :-)

    더운 여름 날씨에 건강 유의하시고, 활기찬 여름 보내시기 바랍니다. 감사합니다.

    ps. Windows Azure Cafe (http://cafe.naver.com/wazure) 에서 2010년 8월 14일부터 본격적으로 Offline Study를 진행합니다. Windows Azure Platform의 학습에 관심있으신 개발자 여러분들의 많은 관심과 참여 부탁드리며, 아울러 Visual Studio 2010 공식 팀 블로그에서 Cloud Computing 관련 Article을 집필하실 열정적인 Blogger 여러분도 함께 모시고 있습니다. 이에 관련된 모든 상세한 내용은 Windows Azure Cafe를 통하여 저에게 연락 주시면 상세히 안내해드리겠습니다. 감사합니다. :-)

    1. 기본으로 제공되는 템플릿 코드로부터 수정한 부분으로, 마스터 페이지는 처리 과정 도중에 해석되는 파일이지만 브라우저의 입장에서 서비스를 하는 페이지가 아니기 때문에, 기본으로 제공되는 경로인 ../../Content/Stie.css는 잘못 해석될 가능성이 있습니다. 이를 예방하기 위하여 Inline Expression을 사용하여 Url.Content 메서드로 정확한 경로를 다시 가져오도록 만든 것입니다. [본문으로]
    2. 기본으로 제공되는 템플릿 코드로부터 수정한 부분으로, 마스터 페이지는 처리 과정 도중에 해석되는 파일이지만 브라우저의 입장에서 서비스를 하는 페이지가 아니기 때문에, 기본으로 제공되는 경로인 ../../Content/jquery-1.4.1.min.js는 잘못 해석될 가능성이 있습니다. 이를 예방하기 위하여 Inline Expression을 사용하여 Url.Content 메서드로 정확한 경로를 다시 가져오도록 만든 것입니다. [본문으로]
    3. 이번 시간에 JSON 기반의 데이터를 표현하기 위하여 사용할 jTemplate 라이브러리를 여기에서 지정합니다. 앞의 URL들과 마찬가지의 방법을 사용하여 정확하게 경로가 참조될 수 있도록 만들어줍니다. [본문으로]
    4. 기본 Index 메서드에서는 return View(); 로 호출하였지만, 다른 Controller Method에서 이 메서드를 호출하게 되는 경우, Index View가 아닌 Controller 그 자신의 View를 찾도록 기본 설계가 구성되어있기 때문에, 이를 방지하고 재 사용하기 쉬운 형태로 만들기 위해 특별히 "Index"라는 뷰 이름을 찾도록 명시한 것입니다. [본문으로]
    5. POST 요청에 의해서만 메시지가 JSON 형식으로 내려가도록 구성하기 위한 것으로, 필요에 따라이 Attribute를 누락하고, 아래의 Json 메서드 호출에서 AllowGet 인자를 지정하면 GET 요청에 의해서도 조회 결과가 JSON으로 반환될 수 있습니다. [본문으로]
    6. ActionResult 클래스를 상위 클래스로 두는 JSON Serialization Result 객체를 반환합니다. [본문으로]
    7. 데이터 삽입 직후 Commit 연산까지 한번에 처리하도록 설계된 메서드를 부르는 것입니다. [본문으로]
    8. 중요: 이 함수의 결과로 나타나는 View가 AddMessage가 아니라 Index입니다. [본문으로]
    9. 동일한 메서드에 대한 오버로드이지만, GET 방식으로 호출될 수 있고, 인자를 2개를 받도록 구성되어있으므로 이 버전의 메서드에서는 View를 렌더링하는데 사용됩니다. [본문으로]
    10. ViewData 컬렉션에 Update 동작을 구현하기 위해 필요한 정보를 다시 전달합니다. 나중에 View에서 이 정보를 참조하여 페이지를 렌더링하게 됩니다. [본문으로]
    11. 조회된 결과를 페이지 렌더링을 위하여 ViewData 컬렉션에 보관합니다. [본문으로]
    12. 동일한 버전의 UpdateMessage 메서드에 대한 오버로드이지만, POST 요청에만 동작하도록 설계된 버전의 Controller Method입니다. [본문으로]
    13. 편집을 마친 후, 미리 구성된 PopupUpdateView를 찾아 이동합니다. 이 뷰는 팝업창 형태로 열린 편집 창을 닫고, 팝업 창의 부모 (window.opener)를 새로 고침하도록 디자인된 뷰입니다. [본문으로]
    14. 업데이트에 실패할 경우 보여줄 View를 지정합니다. [본문으로]
    15. 데이터 삭제 후 Index 뷰를 다시 로드하도록 만들었습니다. [본문으로]
    16. XmlHttpRequest 객체를 이용하여 전송할 때 POST 방식으로 요청하는 것을 명시하고 있습니다. [본문으로]
    17. RetrieveMessages Controller Method를 정확히 찾을 수 있도록 전체 경로를 반환하는 함수를 사용하여 스크립트 위에 렌더링합니다. [본문으로]
    18. JSON 방식의 결과 집합이 필요함을 명시하고, JSON 방식으로 데이터를 받아들이도록 구성하고 있습니다. [본문으로]
    19. jTemplate 엔진으로 치환된 내용을 렌더링할 대상 div element를 찾습니다. [본문으로]
    20. 기준이 되는 템플릿 컨텐츠를 로드합니다. 이스케이프 문자로 복잡하게 처리하지 않고 편리하게 다룰 수 있도록 만들기 위하여, JavaScript나 VBScript로 해석되지 않도록 처리한 별도의 SCRIPT element로부터 로드하도록 구성하였습니다. [본문으로]
    21. jTemplate 엔진을 이용하여 주어진 데이터를 통해 렌더링을 시작합니다. [본문으로]
    22. 렌더링에 필요한 템플릿 코드가 이곳에 기술됩니다. 이 부분은 스크립트 태그 안에 있지만 스크립트 해석기에 의하여 처리되지는 않으며, 또한 시각적으로 드러나지도 않습니다. (as-is string으로 해석됩니다.) [본문으로]
    23. 메시지를 추가하기 위한 form 데이터를 구성하고 있습니다. [본문으로]
    24. Controller Method의 name 매개 변수와 이름을 같게 지정합니다. [본문으로]
    25. Controller Method의 message 매개 변수와 이름을 같게 지정합니다. [본문으로]
    26. 전송 버튼과 초기화 버튼이 trigger 역할을 하여 데이터를 전송하거나 리셋하는 역할을 합니다. [본문으로]
    27. 방명록 목록은 이 요소 아래에 rendering 될 것입니다. [본문으로]
    28. UpdateMessage의 POST 전송 대상을 찾아 업데이트 작업을 수행하도록 만듭니다. [본문으로]
    29. 링크에 의하여 GET 방식으로 전달된 매개 변수를 다시 렌더링하여 재사용합니다. [본문으로]
    30. ViewData에 저장된 기존 데이터를 꺼내옵니다. [본문으로]
    31. ViewData에 저장된 기존 데이터를 꺼내옵니다. [본문으로]
    32. 전송 버튼과 초기화 버튼이 trigger 역할을 하여 데이터를 전송하거나 리셋하는 역할을 합니다. [본문으로]
    33. 팝업 창을 닫습니다. [본문으로]
    34. 팝업 부모 창이 유효하다면, 정확한 Index View의 URL을 찾아 다시 로드하도록 만듭니다. [본문으로]
    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    PaaS2010. 7. 27. 09:00

    꼭 읽어주세요: 이 글이 작성된 현 시점에 가장 최신 버전의 Azure Tools는 버전 1.2입니다. 이 강좌를 시작하시기 전에 Windows Azure Tools for Visual Studio를 1.2 버전으로 업그레이드하여 주십시오. 이전 버전을 설치하신 경우에는 SDK와 Tools를 모두 완전히 제거한 후 1.2 버전으로 새로 설치하여 주십시오. Windows Azure Tools for Visual Studio 1.2 한글판 다운로드는 http://www.microsoft.com/downloads/details.aspx?displaylang=ko&FamilyID=2274a0a8-5d37-4eac-b50a-e197dc340f6f 에서 가능합니다.

    지난번 글 (2010/06/07 - [Cloud Development] - Hello Windows Azure / Understanding Windows Azure Development Process)에 이어서, 오늘부터는 Twitter 스타일 방명록 만들기 첫 번째 시간입니다. 이번 시간에는 Windows Azure 프로젝트를 만들고, 데이터 모델을 작성하고 파악하는 것을 실습 목표로 정의하고자 합니다.

    빠르고 편리한 실습을 위하여, Visual Web Developer 2010 Express를 사용하여 실습하는 것을 기준으로 하겠습니다. Visual Studio 2010이 이미 설치되어있으신 경우 이를 이용하셔도 됩니다. 어떤 개발 도구를 사용하더라도 반드시 Windows Azure Tools for Visual Studio가 설치되어있어야 하며 설치 방법은 2010/06/03 - [Cloud Development] - Hello Windows Azure / Windows Azure 개발 환경의 구축 에서 소개하는 내용에 따라 완료하여 주시기 바랍니다.

    개발 도구 시작하기 및 프로젝트 생성하기

    1. Visual Web Developer 2010 Express (또는 Visual Studio 2010)를 권한 상승 시킨 상태에서 시작하도록 합니다. 아래의 그림을 참고하세요. 사용자 계정 컨트롤을 사용하고 있을 경우 별도의 경고 대화 상자가 나타날 수 있으며 실행하도록 선택하시면 됩니다.

    2. Visual Web Developer 2010 Express가 실행되면 초기 화면에서 새 프로젝트 만들기 링크를 클릭합니다.

    3. 아래에 표시된 대화 상자에서 왼쪽의 개발 범주를 Cloud로 선택하면 사용 가능한 프로젝트 템플릿 중에서 "Windows Azure 클라우드 서비스"가 나타납니다. 이 항목을 클릭하고, 프로젝트 이름을 원하는 이름 (여기서는 TwistBook이라고 하겠습니다.)을 지정한 후, "솔루션용 디렉터리 만들기"에 체크하고 "확인" 버튼을 클릭합니다.

     

    특별히 솔루션용 디렉터리 만들기에 체크가 되어있는지를 확인하는 이유는, 이 옵션이 Windows Azure Tools로 생성되는 프로젝트의 특성 상 한 솔루션 안에 다수의 프로젝트가 만들어지기 때문에 이를 정확하게 분류하기 위하여 사용하는 옵션으로, 사용하도록 맞추어져있을 때 좀 더 소스 코드 관리가 편리하기 때문입니다.

    4. 배포할 Windows Azure 응용프로그램 내에 배치될 Role의 종류와 유형을 설정하는 추가 프로젝트 마법사가 아래와 같이 나타납니다. (만약 아래 화면 대신 HTML 페이지로 안내 페이지가 나타나는 경우 Azure Tools가 올바르게 설치되지 않은 상태입니다.)

    5. .NET Framework 4 역할 그룹과 클라우드 서비스 솔루션 그룹 사이의 두 개의 버튼을 이용하여 실제로 제작할 프로젝트의 유형을 설정하고 프로젝트의 이름까지 정할 수 있습니다. 우선 ASP.NET MVC 2 웹 역할 프로젝트 한 개와 작업자 역할 프로젝트 한 개를 추가하겠습니다.

    6. 이제 각 프로젝트의 정확한 이름을 설정하기 위하여, 클라우드 서비스 솔루션 그룹 안에 추가된 프로젝트 중 MvcWebRole1 프로젝트 항목을 선택하면 연필 모양의 아이콘이 이름 옆에 나타납니다. 이를 클릭하면 아래와 같이 이름을 바꿀 수 있도록 편집 영역이 나타납니다. 이 예제에서는 다음과 같이 이름을 정하였습니다.

    - MvcWebRole1 => TwistBook.WebRole
    - WorkerRole1 => TwistBook.LinkProcessor

    이름을 편집하고 나면 아래와 같은 화면이 되어있을 것입니다. 확인 버튼을 눌러 프로젝트를 생성합니다.

    7. 프로젝트의 생성을 진행하다보면 Visual Studio 2010 Professional 이상의 버전에서는 다른 ASP.NET MVC 2 프로젝트와 마찬가지로 테스트 프로젝트를 만들것인지를 물어보는 대화 상자가 나타납니다. 빠른 설명과 간결한 진행을 위하여 테스트 프로젝트를 생성하지 않는 방향으로 이 예제에서는 진행하도록 하겠습니다. (필요하신 분들께서는 생성하셔도 됩니다.) Visual Web Developer 2010 Express Edition에서는 이러한 대화 상자가 따로 나타나지 않습니다.

    8. 프로젝트 생성이 끝나면 아래와 같이 솔루션 탐색기에 총 3개의 프로젝트가 열거됩니다.

    TwistBook 프로젝트는 Cloud Application 전체를 총괄하는 프로젝트이며, Cloud 환경에서 하나의 Application으로 분류됩니다. 이 프로젝트 안에 Web Role과 Worker Role이 다수 연결되는 구조로 되어있으며, 나중에 Cloud Service Package 파일 (CSPKG)로 컴파일될 때 이 프로젝트가 기준이 됩니다.

    TwistBook.WebRole 프로젝트는 ASP.NET MVC 2를 사용하도록 프로젝트가 구성되어있으며 여기에 기본적인 트위터 스타일의 방명록 UI를 표시하거나 인증된 사용자로부터 메시지를 입력받아 Worker Role에게 처리를 위임하는 등의 작업을 수행하도록 코드를 구성할 것입니다.

    그리고 TwistBook.LinkProcessor 프로젝트는 Web Role과는 따로 실행되는 개별적인 Role 인스턴스로서, Web Role에서 받아들이는 메시지 중 이미지 파일을 twitpic.com에 게시하여 짧은 URL을 받아온다거나, 본문에 있는 긴 URL을 짧게 만들어 받아오는것과 같이 처리량이 많이 몰렸을 경우 병목 현상을 일으킬 수 있는 기능만을 전담하도록 코드를 구성할 것입니다.

    자료 구조 만들기

    1. 클라우드 환경 내부 및 외부에서 기준이 될 모델 자료 구조를 만들기 위하여, 별도의 클래스 라이브러리를 작성하도록 하겠습니다. 솔루션 탐색기에서 솔루션 항목을 오른쪽 버튼으로 클릭하고 아래 그림처럼 새 프로젝트 추가 메뉴를 클릭합니다.

    2. 일반적인 클래스 라이브러리 프로젝트를 하나 만듭니다. 이름은 TwistBook.DataModel로 지정하고, Cloud 환경 위에서 사용하도록 현재 지정된 .NET Framework 4와 동일한 빌드 타겟이 지정되어있는지 확인한 후 프로젝트를 생성합니다.

    3. TwistBook.DataModel 프로젝트에 Windows Azure Table Storage에서 사용할 Data Context 클래스를 만들도록 하겠습니다.[각주:1]

    Data Context 클래스를 만들기 위해서는 Windows Azure SDK에서 제공하는 클래스 라이브러리 파일들을 TwistBook.DataModel 프로젝트 참조에 포함시켜야 합니다. 아래 그림과 같이 솔루션 탐색기에서 TwistBook.DataModel 프로젝트 아래의 참조 항목을 오른쪽 버튼으로 클릭하고 "참조 추가" 메뉴를 클릭합니다.

    4. 참조 추가 대화 상자가 나타나면, .NET 탭을 클릭합니다. 이 과정에서 비동기적으로 Visual Studio가 관리하는 디렉터리 목록 내에 있는 모든 어셈블리들을 조사하여 실시간으로 리스트 박스에 추가합니다. 이 샘플에서 필요로 하는 SDK의 라이브러리가 목록에 나타나기까지 조금 시간이 걸릴 수 있으며 시스템마다 차이가 있을 수 있지만 약 1분 이내에 나타납니다.

    5. 나타난 항목들 중에서 다음의 항목들을 찾아 키보드의 Ctrl 키를 누른채로 하나씩 클릭하면, 아래 그림과 같이 여러 대상을 선택하고 참조로 추가할 수 있습니다.

    * System.Data.Services.Client
    * Microsoft.WindowsAzure.StorageClient

    6. 아래 그림과 같이 참조 목록이 구성되어있으면 준비가 다 된것입니다. 이제 본격적으로 코드 작성을 시작해 보도록 하겠습니다. :-)

    7. 기본으로 만들어진 클래스가 담겨있는 Class1.cs 파일의 내용을 아래와 같이 작성합니다. 코드에서 핵심이 되는 부분을 굵게 표시하였습니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.WindowsAzure.StorageClient; [각주:2]

    namespace TwistBook.DataModel
    {
        public class TwistModel : TableServiceEntity [각주:3]
        {
            public TwistModel()
            {
                DateTime current = DateTime.Now;
                PartitionKey = current.ToString("yyyyMMdd");
                RowKey = current.ToString("hhmmss"); [각주:4]

            }

            public string WriterName { get; set; }
            public string MessageBody { get; set; }
            public DateTime WrittenDate { get; set; }
            public string ImageUrl { get; set; } [각주:5]
        }
    }

    8. Class1.cs 파일의 이름을 클래스 이름과 동일하게 설정합니다. Windows 탐색기를 열지 않고, 아래의 그림에서처럼 솔루션 탐색기에서 직접 이름을 바꿀 수 있으며, Class1.cs 파일을 TwistModel.cs 파일로 이름을 변경합니다.

    9. TwistBook.DataModel 프로젝트에 Windows Azure Table Storage에서 사용할 Data Context 클래스를 만들도록 하겠습니다. 새 항목을 프로젝트에 추가하기 위하여 아래 그림과 같이 솔루션 탐색기에서 TwistBook.DataModel 프로젝트 항목을 오른쪽 버튼으로 클릭하면 "추가" - "새 항목 추가" 메뉴가 나타나는데 이를 클릭하시면 됩니다.

    10. 새 항목 추가 대화 상자에서 설치된 템플릿 영역에서 "Visual C# 템플릿"을 선택하고, 우측 목록에서 "클래스"를 선택합니다. 그리고 이름에 새로 추가할 클래스의 이름을 지정한 후 "추가" 버튼을 클릭합니다. 9단계와 10단계를 거쳐서 다음의 파일들을 추가로 생성합니다.

    * TwistDataServiceContext.cs
    * TwistDataSource.cs

    11. 솔루션 탐색기 내의 TwistBook.DataModel 프로젝트 항목 아래에 다음 그림과 같이 구성이 되어있으면 정상적으로 추가가 된 것입니다.

    12. 이제 TwistDataServiceContext.cs 파일을 열어서 다음과 같이 코드를 작성합니다. 코드에서 중요한 부분은 굵은 글씨로 표현하였고 여기에 따른 부가적인 설명을 각주로 붙였습니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient; [각주:6]

    namespace TwistBook.DataModel
    {
        internal class TwistDataServiceContext : TableServiceContext [각주:7]
        {
            internal TwistDataServiceContext(CloudStorageAccount account)
                : base(account.TableEndpoint.AbsoluteUri, account.Credentials) [각주:8]
            {
            }

            internal const string TwistModelName = "TwistModel";

            public IQueryable<TwistModel> TwistModel [각주:9]
            {
                get { return this.CreateQuery<TwistModel>(TwistModelName); } [각주:10]
            }

        }
    }

    13. 이어서 TwistDataSource.cs 파일을 열어서 다음과 같이 코드를 작성합니다. 코드에서 중요한 부분은 굵은 글씨로 표현하였고 이에 따른 부가적인 설명을 각주로 붙였습니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.WindowsAzure;
    using System.Data.Services.Client;
    using Microsoft.WindowsAzure.StorageClient; [각주:11]

    namespace TwistBook.DataModel
    {
        public class TwistDataSource
        {
            private static CloudStorageAccount storageAccount;
            private TwistDataServiceContext serviceContext;

            static TwistDataSource()
            {
                // 중요: 실제로 응용프로그램을 Cloud 환경에 배포할 때에는
                // Cloud Project 내의 다른 환경 설정 문자열을 이용하도록
                // 호출을 변경해야 합니다.
               storageAccount = CloudStorageAccount.DevelopmentStorageAccount; [각주:12]

               CloudTableClient.CreateTablesFromModel(
                    typeof(TwistDataServiceContext),
                    storageAccount.TableEndpoint.AbsoluteUri,
                    storageAccount.Credentials); [각주:13]

            }

            public TwistDataSource()
            {
                this.serviceContext = new TwistDataServiceContext(storageAccount); [각주:14]
                this.serviceContext.RetryPolicy = RetryPolicies.Retry(
                    3, TimeSpan.FromSeconds(1)); [각주:15]

            }

            public DataServiceResponse Insert(TwistModel model)
            {
                this.serviceContext.AddObject(
                    TwistDataServiceContext.TwistModelName,
                    model); [각주:16]

                return this.serviceContext.SaveChanges(); [각주:17]
            }

            public IEnumerable<TwistModel> Select()
            {
                var results = from eachTwist in this.serviceContext.TwistTable
                              select eachTwist; [각주:18]

                var query = new CloudTableQuery<TwistModel>(
                    results as DataServiceQuery<TwistModel>,
                    RetryPolicies.Retry(3, TimeSpan.FromSeconds(1))); [각주:19]

                return query.Execute(); [각주:20]
            }

            public DataServiceResponse Delete(TwistModel model)
            {
                this.serviceContext.AttachTo(
                    TwistDataServiceContext.TwistModelName,
                    model, "*"); [각주:21]

                this.serviceContext.DeleteObject(model);
                return this.serviceContext.SaveChanges();
            }
        }
    }

    Preface: ASP.NET MVC 2 Web Role에 대한 이해

    다음 Article의 내용을 올리기 전에, ASP.NET MVC 2에 대한 이해를 돕기 위하여 간단한 단락 하나를 구성하였습니다. ASP.NET MVC 2는 Microsoft의 최신 웹 기술이 적용된 프레임워크로 Windows Azure 개발 환경에서 뿐만 아니라 일반적인 웹 사이트 개발에도 얼마든지 활용될 수 있는 유용한 프레임워크입니다.

    TwistBook.WebRole 프로젝트의 노드를 솔루션 탐색기에서 살펴보면 아래와 같은 구성이 나타납니다. 이 구성은 전형적인 ASP.NET MVC 응용프로그램이며, 고전적인 웹 프로그래밍 모델에서와는 달리 직접 aspx 페이지를 부르지 않고 알기 쉬운 주소를 기반으로하는 것이 특징입니다. ASP.NET MVC 응용프로그램을 처음 접하시는 분들을 위하여 디렉터리 구조에 대한 설명을 잠시 말씀드립니다.

    App_Data: ASP.NET 응용프로그램이 데이터베이스에 연결하기 위하여 필요한 각종 코드 및 데이터베이스 연결 설정 파일들을 보관하는 디렉터리이며, ASP.NET 2.0부터 존재해왔던 디렉터리입니다. 예외적으로 이 디렉터리에는 Microsoft Access 파일 (*.mdb 또는 *.accdb)이나 소규모 웹 사이트를 위한 Embedding 가능한 SQL 데이터베이스 파일 (*.mdf 및 *.ldf)이 배치되기도 합니다.

    Content: ASP.NET MVC 응용프로그램 전반에 걸쳐서 사용되는 공통적인 클라이언트측 구성 요소 (가령 CSS 스타일 시트, XSLT 스타일 시트, 이미지 파일, 오디오 파일 등)가 이 디렉터리에 저장됩니다. 이 디렉터리에 저장된 파일들은 중간 처리기에 의하여 해석되지 않는 고유한 경로를 유지할 수 있습니다.

    [중요] Controllers: ASP.NET MVC 응용프로그램에서 "C"를 대표하는 구성 요소가 저장되는 디렉터리이며 백그라운드에서 웹 페이지를 그리거나, 웹 브라우저로부터 받아온 정보를 해석하거나, 가공하거나, 처리하는 제어 코드를 이곳에 배치합니다.

    [중요] Models: ASP.NET MVC 응용프로그램에서 "M"을 대표하는 구성 요소가 저장되는 디렉터리이며 주로 Controller 간의 통신, 데이터베이스와의 통신, 클라이언트로의 통신 등에서 기본 단위가 되는 데이터나 모델을 표현하는 클래스 코드를 이곳에 배치합니다. 이곳에 배치되는 코드에는 로직이 포함되지 않는 것을 원칙으로하며, 이곳에 배치되는 클래스들의 성격을 일반적으로는 POCO [각주:22] - 또는 - PONO [각주:23] (http://en.wikipedia.org/wiki/Plain_Old_CLR_Object)로 이해하면 쉽습니다.

    Scripts: Content 디렉터리와 유사한 성격의 디렉터리이지만 특별히 JavaScript 라이브러리들을 위하여 할당된 디렉터리로, ASP.NET MVC 2는 오픈 소스 기반의 JavaScript Framework인 jQuery를 기본으로 제공합니다. 만약 jQuery Plugin을 개발하였거나 사용하고자 하는 다른 Plugin이 있을 경우 - 또는 - jQuery 이외의 다른 JavaScript 라이브러리 (예: 네이버 jindo, script.aculo.us, Moo Tools, Google Web Toolkit, extJS, Dojo Toolkit, prototype, Yahoo! UI 등)를 이곳에 추가하면 됩니다.

    [중요] Views: ASP.NET MVC 응용프로그램에서 "V"를 대표하는 구성 요소가 저장되는 디렉터리이며 주로 Controller에 어떤 데이터를 전달할 것인지를 사용자에게 대화형으로 묻거나, Controller에 의하여 발생한 출력 결과를 사용자에게 대화형으로 전달할 때 사용하는 컨텐츠 파일들이 여기에 저장됩니다. ASP.NET MVC 2에서는 Web Forms와 Script Tag Expression을 기반으로 하는 뷰 엔진을 기초로 합니다. [각주:24]

    [중요] Global.asax: ASP.NET MVC에서 매우 중요한 구성 요소로 지금 작업하는 ASP.NET 응용프로그램이 ASP.NET MVC 엔진에 의하여 처리되어야 함을 지정하고 초기 설정을 구성하는 코드가 여기에 포함되어있습니다. 이 파일이 누락되거나 내용이 잘못되어있을 경우 ASP.NET MVC 응용프로그램으로서 동작하지 않음을 유의해야 합니다. 추가적으로 사이트 내에 다른 영역을 구성하거나, 다른 주소 패턴을 확장해야 할 경우에도 이 파일에 내용을 추가해야 설정이 적용됩니다.

    [중요] Web.config: ASP.NET 응용프로그램의 환경 설정 파일로 역시 이 파일의 내용에 문제가 있거나 누락되어있을 경우 ASP.NET MVC 응용프로그램이 올바르게 동작하지 않을 수 있음을 주의해야 합니다.

    [중요] WebRole.cs: ASP.NET 응용프로그램과는 무관하나, Windows Azure 환경에서 Web Role이 초기에 기동될 때 필요한 설정을 포함하고 있으며, 클라우드 컴퓨팅 환경에서의 실질적인 진입점이 됩니다. 이 클래스가 없을 경우 응용프로그램 실행에 문제가 있을 수 있습니다.

    다음 시간에는

    다음 시간에는 ASP.NET MVC 2 기반의 Web Role을 작성하고, 테이블 스토리지에서 실제로 데이터를 조회하거나 추가, 변경, 삭제하는 예시를 들어보도록 하겠습니다. 긴 강좌 읽어주셔서 감사하며, 즐거운 여름 휴가 되십시오. 감사합니다. :-)

    강좌에 대한 고칠 부분, 의견, 제안 등은 남정현의 클라우드 & 닷넷 블로그 (http://www.rkttu.com/), 트위터 (@rkttu), 전자 메일 (rkttu nospam rkttu dot com)을 통하여 항상 받고 있습니다. 언제든 의견 주시면 감사하겠습니다. :-)

    1. 이 샘플에서 Windows Azure Storage를 이용하는 방향으로 설명이 되어있지만, 실제로 여러분이 개발할 Windows Azure 서비스에서는 SQL Azure나 다른 곳에 배치되어있을 고가용성의 관계형 데이터베이스 시스템 (예: SQL Server 2008 R2)을 이용하는 것이 더 좋을 수 있습니다. [본문으로]
    2. Windows Azure SDK와 함께 제공되는 Table Storage를 위한 API가 포함되어있는 네임스페이스입니다. [본문으로]
    3. TableServiceEntity 클래스를 상속받도록 자료 구조를 만들어야 SDK를 이용하여 Table Storage에 데이터를 저장하거나 가져올 수 있습니다. [본문으로]
    4. TableServiceEntity 클래스의 기능을 적용하기 위하여 동일한 시그니처를 가진 생성자를 하나 만듭니다. Table Storage의 접근 효율성을 위하여, 테이블은 여러 개의 파티션으로 구분됩니다. 이 샘플에서 파티션의 분리 단위로 "날짜"를 사용하였습니다. 그리고 파티션 내에서 각각의 Entity가 고유한 의미를 가질 수 있게 하기 위하여 Row Key를 사용하여 구분합니다. Partiton Key와 Row Key가 더해져서 테이블 내에서는 이 Entity가 "유일할 수 있다"는 특성을 보장합니다. [본문으로]
    5. WriterName Property는 작성자의 이름, MessageBody Property는 메시지 본문, WrittenDate Property는 작성한 날짜와 시간을, ImageUrl Property는 같이 첨부하는 사진의 URL을 보관하는 목적으로 사용됩니다. C# 3.0 이후로 지원되는 단축 Property Getter/Setter 선언으로 별도의 private 멤버 변수를 배치하지 않고 이와 같이 단순한 코드를 만들 수 있습니다. [본문으로]
    6. Windows Azure SDK와 함께 제공되는 Table Storage를 위한 API가 포함되어있는 네임스페이스입니다. [본문으로]
    7. LINQ를 이용하여 손쉽게 데이터를 가져오거나 설정할 수 있도록 LINQ의 설정을 확장해주는 기본 추상 클래스입니다. [본문으로]
    8. CSCFG 파일 상의 정보를 표현하는 객체인 CloudStorageAccount를 생성자에서 인자로 받아 이 객체를 초기화하고, Windows Azure Storage와의 연결을 초기화합니다. [본문으로]
    9. 지연 실행을 목적으로 하는 질의 객체를 생성합니다. 지연 실행이란, 각각의 요소를 다룰 필요가 있을 때 식을 계산하고 평가하는 방식으로, 전체의 내용을 미리 메모리에 읽어들여서 처리하는 것과는 차이가 있습니다. 이 객체는 앞서 우리가 정의한 TwistModel 클래스를 트랜잭션의 단위로 사용하도록 SDK 내의 프레임워크에서 생성됩니다. [본문으로]
    10. 주의: 엔티티 클래스의 이름, ServiceContext에서 노출하는 프로퍼티의 이름, CreateQuery 메서드에 전달하는 테이블 명의 이름이 모두 같아야 혼선없이 올바르게 동작할 수 있음을 보증할 수 있습니다. [본문으로]
    11. LINQ to Azure Table Storage를 활용하는데에 필요한 클래스 및 원격 데이터 액세스에 필요한 클래스들이 굵게 강조 표시한 3개의 네임스페이스 안에 모두 포함되어있습니다. [본문으로]
    12. 현재는 실제 Windows Azure Storage 계정을 지정하지 않고 Local Development Storage 계정을 대신 지정합니다. [본문으로]
    13. 테이블 모델을 생성할 때 사용할 기준이 될 DataContext 클래스를 선택하고, 생성을 요청합니다. 이 때 접속할 대상 스토리지의 HTTP 주소와 자격 증명 정보도 한꺼번에 지정합니다. 또한, 이 작업은 TwistDataSource 클래스를 프레임워크에서 로드할 때 한 번만 발생할 수 있도록 유도하기 위하여 정적 생성자에 정의하였습니다. 테이블의 초기 구조를 할당하는 작업은 자주 일어날 필요가 없는 작업이기 때문에 성능 상의 이득을 위하여 이와 같이 작성합니다. [본문으로]
    14. 서비스 객체를 초기화합니다. 앞에서 가져온 계정 정보를 사용하여 복원된 계정 정보 객체를 사용하여 초기화하고 있다는 점을 확인하십시오. [본문으로]
    15. 혹시 있을지 모르는 장애에 대해 좀 더 완벽한 대비를 위하여, 재시도 정책을 설정할 수 있습니다. (이 부분은 매우 중요한 개념입니다.) 첫 번째 인자에는 재시도 횟수, 그리고 두 번째 인자에는 재시도 간격을 TimeSpan 객체를 이용하여 지정할 수 있습니다. 여기서는 처음 실패가 발생한 시점을 기준으로 3회 더 시도하며 각 시도 간격은 1초로 정합니다. [본문으로]
    16. 전형적인 LINQ to Entity 서비스와 마찬가지로 AddObject를 이용하여 객체의 참조를 기반으로 새로운 데이터를 추가할 수 있습니다. [본문으로]
    17. 트랜잭션 개념을 기본적으로 사용하므로 SaveChanges 메서드는 삽입, 변경, 삭제 작업이 있은 직후에는 반드시 병행되어야 합니다. [본문으로]
    18. Windows Azure Table Storage에 전송할 Query를 지연된 실행을 위한 객체로 초기화합니다. 이 문장이 실행되었다고해서 곧바로 데이터가 수집되는 것은 아닙니다. [본문으로]
    19. Windows Azure Table Storage에 실제로 Query를 전송할 클라이언트 객체를 초기화하고, 이 객체의 재시도 정책도 추가로 정의할 수 있습니다. 여기서도 3회 재시도, 매 시도마다 1초 간격을 두기로 설정합니다. [본문으로]
    20. 비로소 이 부분에서야 실제 전송과 데이터 수집이 발생하게 됩니다. [본문으로]
    21. Table Storage에서 객체를 삭제할 때에는 삭제를 위하여 검색할 대상을 지정해야 하며 이 때 사용하는 것이 AttachTo 메서드입니다. 이 메서드를 이용하여 어떤 테이블에서 어떠한 유형의 데이터를 검색할 것인지를 서비스 객체에 지정합니다. [본문으로]
    22. Plain Old CLR Object (Plain Old Java Object; POJO를 응용한 줄임말) [본문으로]
    23. Plain Old .NET Framework Object (Plain Old Java Object; POJO를 응용한 줄임말, POCO와 동일한 의미의 다른말) [본문으로]
    24. 이 글을 작성하는 시점에서 ASP.NET MVC 3에서 기본으로 채택될 예정인 Razor View Engine이 새로 발표되었습니다. Razor View Engine은 Web Form을 대체하는 ASP.NET MVC 전용의 View Engine 시스템을 뜻합니다. [본문으로]
    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    이벤트2010. 6. 25. 23:44

    ASP.NET AJAX와 더불어서 ASP.NET MVC를 비롯하여 거의 모든 웹 사이트와 웹 개발 프레임워크들이 채택하는 jQuery에 대한 세미나가 오는 2010년 7월 10일에 열립니다. 이번 세미나에서는 jQuery에 대한 고급 기법을 다루고, jQuery를 어떤 방법으로 확장할 수 있는지에 대한 다양한 테크닉을 "실전! jQuery CookBook"의 역자 분들께서 꼼꼼히 짚어주실 것입니다. 많은 참여 부탁드립니다. :-)

    주의 사항: 세미나 참석 등록을 아래의 주소에서 제공하는 댓글 달기 기능을 이용하여 등록해 주십시오. 아래는 세미나 소개 글을 발췌해 온 것입니다.

    세미나 등록하러 가기: http://taeyo.net/Forum/Content.aspx?TBL=NOTICE&SEQ=383&PGN=1

    7월 10일 기다리던 jQuery 세미나가 시작됩니다.
    실전! jQuery CookBook의 역자들이 모두 모여서 jQuery 고급기법에 관한 세미나를 진행합니다.
    경품으로 신간 "실전! jQuery CookBook"도 드리니 많이 참석하셔서 즐겨주세요.

    이번 세미나는 닷넷 개발자이던, 자바 개발자이던 무관하게 누구나 참석이 가능합니다.
    현장등록도 가능하지만, 사전 준비를 위해서 반드시 리플로 참석 등록을 해주시기 바랍니다.
    미리 참석등록을 한 분에 한해서 경품 추첨에 참여하실 수 있습니다.
    (난 좀 샤이한 사람이다 하시는 분은 등록없이 그냥 오셔도 됩니다만, 그 경우 경품추첨에서 배제됩니다)

    장소 : 한국 마이크로소프트 세미나실(선릉 포스코빌딩 서관 5층)
    일시 : 2010년 7월 10일 토요일 오후 1시 (접수는 1시, 시작은 2시)


    등록방법 : http://taeyo.net/Forum/Content.aspx?TBL=NOTICE&SEQ=383&PGN=1 에 리플로 참석여부와 이름, 개발분야를 남겨주시면 됩니다.

    세션1 : jQuery의 Event 다루기

    • 시간 : 2:00 - 3:00
    • 발표자 : 김경균
    • 내용 :
      jQuery가 지원하는 이벤트에 대한 효과적인 사용방법과 고급 이벤트 기법에 대해서 다룹니다.
      이미 jQuery가 제공하고 있는 이벤트를 사용하는 방법 뿐만 아니라,
      자체적인 이벤트를 작성 및 사용하는 방법 및 이벤트 통지를 받는 방법에 대해서까지 심도 있게 이야기합니다.

    세션2 : jQuery와 QUnit을 이용한 단위 테스트

    • 시간 : 3:15 - 4:15
    • 발표자 : 최지훈
    • 내용 :
      jQuery로 작성한 코드에 대해 단위 테스트하는 방법을 소개합니다.
      Qunit 프레임워크를 사용하여 결과를 어설션하고, 동기/비동기 콜백을 테스트하는 방법을 설명합니다.
      또한, 다양한 테스트를 그룹으로 묶어서 처리하는 방법에 대해서도 다룹니다.

    세션3 : jQuery 확장 플러그인 만들기

    • 시간 : 4:30 - 5:30
    • 발표자 : 김태영
    • 내용 : jQuery를 확장하기 위한 방법들을 설명하고 그를 기반으로 플러그인을 제작해 봅니다.
      기본적인 플러그인 개발 규칙에 대해 다룬 후, 좀 더 완성된 형태의 플러그인 제작을 위해 필요한
      Option Hash 기법 및 $.extend()을 이용한 매개변수 초기화 방법 그리고 클로저 기법을 설명합니다.
      그리고, 그들을 모두 혼합하여 보편적인 형태의 플러그인을 직접 제작하고 활용하는 방법에 대해 이야기합니다.

    경품 : BJ퍼블릭 협찬 - 실전! jQuery CookBook 5권
    - 원하시면 역자들이 사인을 해드립니다.

    * 세션 주제는 좀 더 나은 세미나를 위해 통지없이 변경될 수 있습니다.

    tweet : @taeyo

    세미나 등록하러 가기: http://taeyo.net/Forum/Content.aspx?TBL=NOTICE&SEQ=383&PGN=1

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    Windows + .NET2010. 5. 29. 17:18
    닷넷 프로그래밍 커뮤니티에서 요즈음 제일 큰 이슈는 바로 .NET Framework 4와 Visual Studio 2010일 것입니다. 어느새 버전 4에 이르렀고, 정말로 많은 변화와 개선이 있었고, 그 현주소가 바로 지금 시점일 것입니다. 오늘은 .NET Framework 4에 대한, 그 중에서도 핵심 API 및 기술들에 대한 변화를 살펴보는 블로그 아티클을 올려봅니다.

    진단 기능 및 성능 측정

    .NET Framework 4에 들어서면서부터, CPU 사용량과 메모리 사용량을 프로세스 단위가 아닌, 응용프로그램 도메인 단위에서 측정하는 일이 가능해졌습니다. 응용프로그램 도메인은, 닷넷 프레임워크에서 사용하는 실제 실행 단위이며, 무엇보다도 중요한 것은 응용프로그램 도메인은 프로세스와 달리 닷넷 프레임워크의 관리 아래에서 통제할 수 있는 자원이라는 점입니다. (프로세스는 운영 체제의 커널에 의하여 귀속되고 관리되는 자원입니다. 따라서, 비 관리 영역에 속하는, 기본적으로는 권외 영역인 셈입니다.)

    AppDomain 클래스에 추가된 새 멤버인 AppDomain.MonitoringIsEnabled 프로퍼티를 이용하여 (http://msdn.microsoft.com/ko-kr/library/system.appdomain.monitoringisenabled.aspx 참고) 현재 실행 중인 응용프로그램 도메인에 모니터링 기능이 부여되어있는지를 파악할 수 있습니다. 그리고, 이 설정을 바탕으로 CLR ETW 이벤트 (Common Language Runtime Event Tracing for Windows, http://msdn.microsoft.com/ko-kr/library/dd264810.aspx) 기능을 사용하여 오버헤드없이 성능 측정을 면밀하게 수행할 수 있게 되었습니다.

    향상된 가비지 컬렉션

    .NET Framework 4에 들어서면서부터 백그라운드 가비지 수집 기능이 제공되는데, 이는 이전 버전의 동시 가비지 수집을 대체하고, 좀 더 향상된 가비지 수집 처리 서비스를 제공합니다. 자세한 내용은 http://msdn.microsoft.com/ko-kr/library/ee787088.aspx 페이지의 Background Garbage Collection 섹션을 참고하시기 바랍니다.

    병렬 컴퓨팅 패러다임의 지원
     
    이제 .NET Framework 4에서도 병렬 컴퓨팅의 패러다임을 손쉽게 가져다 사용할 수 있게 되었습니다. 이제까지 .NET Framework에서 사용하던 비동기 프로그래밍은 Thread 클래스를 직접 사용하거나, Begin/End의 Pair로 구성된 비동기 버전의 연산, 나중에 이벤트로 결과를 통지 받는 패턴, ThreadPool 클래스의 활용과 같이 다중 Threading 작업의 세밀한 부분과 상호 작용을 고려해야 하는 패턴들이었습니다.
     
    http://msdn.microsoft.com/ko-kr/library/dd460693.aspx 에서 소개하는 것 처럼 .NET Framework 4는 병렬 프로그래밍에 대한 새로운 개념들을 제공합니다. .NET Framework 4 환경에서 병렬 프로그래밍은 Task Parallel Library (TPL)에 의한 Action과 PLINQ (Parallel LINQ)에 의한 Action으로 구분됩니다.
     
    Task Parallel Library의 경우, 데이터를 중심으로 비동기/병렬 연산을 수행하기 위한 시나리오, 작업 자체에 집중하여 작업의 실행 순서를 제어하고 관리하는 시나리오, 기존의 전통적인 비동기 패턴과 TPL을 통합하는 시나리오 등 다양한 시나리오를 MSDN 내에서 제공하고 있습니다. TPL을 어떻게 활용할 지를 고민하고 효율적으로 선택해야 하는 어려움이 있지만, 여러분의 응용프로그램이 Cloud Ready 응용프로그램이 될 수 있도록 도와주는 지름길로도 활용할 수 있을 것입니다.
     
    그리고 PLINQ는 이미 여러 닷넷 관련 전문가분들의 블로그에서 수차례 .AsParallel() Extension Method로 소개되었던 LINQ의 Extension입니다. PLINQ에 대한 좀 더 자세한 이해는 http://msdn.microsoft.com/ko-kr/library/dd997425.aspx 에서 참고하실 수 있습니다.
     
    향상된 네트워킹과 암호화
     
    .NET Framework 4에서는 HttpWebRequest, HttpListener, SmtpClient, SslStream, NegotiateStream 등 여러 클래스에서 Windows 인증의 보안이 강화되었습니다. Windows 7 및 Windows Server 2008 R2에서 응용 프로그램에 대한 확장된 보호 기능을 사용할 수 있습니다. 그리고, IPv6 및 Teredo를 사용한 NAT(Network Address Translation) 통과를 지원합니다. 자세한 내용은 IPv6 및 Teredo를 사용한 NAT 통과를 참조하십시오.

    HttpWebRequest 클래스에서 AddRange 메서드에 대한 새 오버로드를 통해 큰 바이트 범위 헤더(64비트 범위)를 사용할 수 있도록 지원합니다. HttpWebRequest 클래스의 새 속성을 통해 응용 프로그램에서 여러 개의 HTTP 헤더를 설정할 수 있습니다. Host 속성을 사용하여 요청 URI에 종속되지 않은 HTTP 요청에 호스트 헤더 값을 설정할 수 있습니다. 그 외에, SmtpClient 및 관련 클래스에 대한 SSL(Secure Sockets Layer) 지원 기능이 추가되었으며, MailMessage 클래스의 메일 헤더 지원 기능이 향상되었습니다.

    암호화에 null 암호화를 사용할 수 있도록 지원합니다. ServicePointManager 클래스와 EncryptionPolicy 속성을 사용하여 암호화 정책을 지정할 수 있습니다. SslStream 클래스의 생성자에서 EncryptionPolicy 클래스를 매개 변수로 사용합니다.
     
    ASP.NET 4
     
    ASP.NET Caching을 확장할 수 있게 하는 새 API, Session State의 압축 지원 및 Application Preload 기능이 추가되어 더욱 개선된 Performance를 제공하게 되었습니다. Web Forms의 경우, 보다 통합된 ASP.NET 라우팅 지원, 향상된 웹 표준 지원, 업데이트된 브라우저 지원, 데이터 컨트롤을 위한 새 기능 및 새로운 뷰 상태 관리 기능 등이 포함됩니다. 그리고, 새로운 차트 컨트롤 등이 포함됩니다.

    ASP.NET MVC 2에서는 뷰를 위한 새 도우미 메서드, 분할된 MVC 응용 프로그램에 대한 지원 및 비동기 컨트롤러 등이 포함됩니다. ASP.NET AJAX 라이브러리의 클라이언트 기반 AJAX 응용 프로그램에 대한 추가 지원 등이 포함됩니다.
    그 외 변경 사항들
     
    WPF 4는 이제 Silverlight 4와 동등한 컨트롤들을 제공합니다. 특히 데이터 그리드, 달력, 날짜 선택 컨트롤이 제공되고 실버라이트 응용프로그램을 거의 그대로 있는 그대로의 상태 (as-is)로 마이그레이션하는 것을 고려해 볼 수 있습니다. 자세한 내용은 http://msdn.microsoft.com/ko-kr/library/bb613588.aspx 를 참고하여 주십시오.
     
    ADO.NET의 경우 ADO.NET Entity Framework에 대한 향상이 많이 있었습니다. http://msdn.microsoft.com/ko-kr/library/ex6y04yf.aspx 의 내용을 참고하여 주십시오. WCF의 경우 ASP.NET 호환 모드에서 ASP.NET Routing과 잘 통합됩니다. WCF의 새로운 기능은 http://msdn.microsoft.com/ko-kr/library/dd456789.aspx 에 잘 설명되어있으며, WF의 경우 http://msdn.microsoft.com/ko-kr/library/dd489410.aspx 의 내용을 참고하십시오.
     
    지금 시작하기
     
    .NET Framework 4.0의 기능을 지금 사용해보기 원하시나요? http://www.microsoft.com/express 에 방문하셔서 최신 버전의 Visual Studio 2010 Express Edition을 설치하고 지금 시작해보세요. 그리고, 2010년 6월 1일에 있을 REMIX'10 행사는 Visual Studio 2010과 함께 최신 웹 기술을 집중적으로 조명합니다. 관심있으신 개발자 여러분들의 적극적인 참여를 기대합니다. :-)
     
    REMIX'10 행사 바로가기: http://www.visitmix.co.kr/remix10/index.html
    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    PaaS2010. 4. 18. 03:38

    실제 Windows Azure OS는 어떤 구성을 사용하고 어떤 설정을 바탕으로 움직이는것일까요? 물론, 충분한 양의 문서와 SDK와 API로 모든 이론적인 설명은 가능합니다. 하지만 좀 더 깊이 들어가서 알아볼 필요가 있을 때도 있습니다. 인터넷 서핑 중에 찾은 흥미로운 블로그 아티클 하나를 소개하고자 합니다.

     

    출처: Windows Azure Team에서 Senior Program Manager로 근무 중인 David Lemphers의 블로그 (http://blogs.msdn.com/davidlem)에서 찾은 아티클 (http://blogs.msdn.com/davidlem/archive/2009/07/06/looking-inside-windows-azure.aspx) 입니다.

     

    엄밀하게 말해서, Windows Azure OS를 실행하는 VM의 상황은 사실 블랙박스나 다름없습니다. 정상적으로 프로그래밍하고 테스트했다면 반 정도의 확률은 정상적으로 실행되지 않을 가능성도 있는 셈입니다. (기동에 실패하는 일보다는, 원하는 대로 서비스가 동작하지 않을 가능성을 의미합니다.) 특히, Worker Role의 경우 Web Role과는 달리 Custom Configuration에 강한 의존을 할 수 밖에 없는데요, 네트워크 서비스 등이 예상대로 동작하지 않으면 굉장히 큰 고민속에 빠지게 됩니다. 이런 곤란한 상황을 빠져나가려면 어떻게 하면 좋을까요?

     

     

    배포할 Windows Azure 프로젝트의 .CSDEF 파일에 enableNativeCodeExecution 어트리뷰트의 값을 "true"로 명시적으로 설정하는 것으로부터 솔루션을 시작할 수 있습니다. (최근의 SDK와 OS의 경우, 이 설정은 기본적으로 'true'이지만 명시적으로 설정하는 것도 좋을것 같습니다.)

     

    그리고 아래와 같이 간단한 asp.net 페이지에 사용할 코드 비하인드를 만듭니다.

     

    newProc.StartInfo.UseShellExecute = false;
    newProc.StartInfo.RedirectStandardOutput = true;
    newProc.StartInfo.FileName = "cmd";
    newProc.StartInfo.Arguments = "/c " + txtCommand.Text;
    
    newProc.EnableRaisingEvents = false;
    newProc.Start();
    
    sr = newProc.StandardOutput;
    
    txtStatus.Text += String.Format("{0}\r\n", sr.ReadToEnd());
    
    newProc.Close();
    

    위의 코드가 하는 역할은 단순합니다. Windows 명령줄 인터프리터를 대신 실행해주고 대신 결과를 출력해주는 것입니다. 그리고, Native Code의 실행을 허용했으므로 거의 대부분의 명령이 정상적으로 실행될 수 있을 것입니다. (관리자 권한 아래에서 실행되지는 않습니다.)

     

    아래의 스크린 샷들은 실제 명령의 수행 결과들을 보여주는 것입니다. 그리고 이 블로그 아티클의 저자는 NETSTAT 명령을 원격에서 실행해보고, Tomcat Instance가 필요로하는 8080포트가 이미 점유된 상태이기 때문에 원하는대로 작동하지 않음을 확인할 수 있었다고 합니다.

     

    ps. 이와 같은 도구는 확실히 디버깅이나 문제 진단에는 유용할 수 있지만, 아무리 클라우드 환경이라고 할지라도 이와 같은 도구가 개방되어있을 경우, 악용될 소지가 크기 때문에, 실제 배포 단계에서는 이러한 도구가 포함되지 않도록 유의할 필요가 있겠습니다.

     

    샘플 페이지의 예시

    샘플 페이지의 예시

    NETSTAT 명령 실행 결과

    NETSTAT 명령 실행 결과

    TASKLIST 명령 실행 결과

    TASKLIST 명령 실행 결과

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    PaaS2010. 3. 11. 23:23

    Windows Azure는 Windows Server의 검증된 기술과 성능을 바탕으로 운영되는 클라우드 컴퓨팅 플랫폼입니다. 그리고, 이러한 조건을 바탕으로, 기존에 이 블로그를 읽어주시는 독자 여러분들께서 운영하시던 ASP.NET 기반의 웹 사이트들도 Windows Azure 위에서 호스팅이 가능하도록 수정하는 것도 웹 사이트의 규모나 복잡도에 따라서 다소 차이는 있을 수 있지만 비교적 손쉽게 이식할 수 있습니다.

     

    Windows Azure로 기존의 ASP.NET 웹 사이트를 이관하면서 생각해보아야 할 이슈 사항들을 이번 개요 Chapter에서 하나씩 살펴보도록 하겠습니다.

     

    1. 데이터베이스에 의존하는 웹 어플리케이션의 경우

     

    대부분의 경우, ASP.NET 웹 사이트들은 Microsoft SQL Server나 기타 다른 유형의 RDBMS와 상호작용하면서 서비스를 제공합니다. 클라우드 환경 위에서 응용프로그램을 구동하기 위해서는, 데이터베이스를 어떤 형태로 이관할 것인지 구상할 필요가 있습니다.

     

    웹 사이트에서 필요로 하는 데이터베이스는 대체로 소규모 데이터베이스이고, 단독으로 이관이 가능한 데이터베이스이므로 SQL Azure로 이관하여 클라우드 환경에 대응이 가능한 데이터베이스로 구현을 바꾸는 것이 유리합니다.

     

    만약, 데이터베이스 도입 비용을 줄이고, 핵심적인 데이터 조회/저장 기능만을 사용하고자 한다면, Windows Azure의 Table Storage로 저장 방식을 변경하는 작업도 고려해볼 수 있습니다. 테이블 간의 외래 키 제약 조건이나, 특수한 인덱스 설정을 이용하거나, 저장 프로시저와 같은 RDBMS 전용의 기술을 사용하지 않는 경우 클라우드 서비스 비용을 줄이는데에 도움이 될 수 있습니다.

     

    2. 설정 파일의 수정이 빈번한 웹 어플리케이션의 경우

     

    Windows Azure 위에 게시되는 응용프로그램은 CSPKG와 CSCFG 파일의 형태를 띕니다. CSPKG 파일은 Windows Azure 위에서 사용할 수 있도록 포장된 ZIP 형식의 패키지이며, CSCFG 파일은 Windows Azure 위에서 구동될 응용프로그램의 일반적인 설정을 포함하는 XML 문서입니다. ASP.NET 웹 사이트의 경우, 관련된 클래스 라이브러리를 포함하여 모두 CSPKG 파일 안에 포장되어 들어가게 됩니다.

     

    기존 ASP.NET 웹 사이트를 운영하면서, web.config이나 web.config에서 branch를 만들어 별도의 XML 파일을 자주 수정하였던 경우, 이러한 방식을 그대로 사용하면 설정이 바뀔 때 마다 매번 새로운 패키지를 만들어서 업데이트해야 하는 문제가 수반됩니다. 이를 피하기 위하여, Windows Azure 런타임 어셈블리를 ASP.NET 웹 사이트 프로젝트의 참조에 추가하고, Windows Azure Application의 설정을 대신 사용하도록 구성하는 것이 유리합니다.

     

    CSCFG 파일의 정보를 읽기 위하여 아래의 도우미 코드를 활용할 수 있습니다.

     

    public class SettingsManager
    {
       private static Settings _settings = new Settings();
       public static Settings Settings
       {
          get
          {
             return _settings;
          }
       }
    }
    
    public class Settings
    {
       public string this[string key]
       {
          get
          {
             if (RoleManager.IsRoleManagerRunning)
             {
                return RoleManager.GetConfigurationSetting(key);
             }
             else if (System.Web.HttpContext.Current != null)
             {
                return WebConfigurationManager.AppSettings[key];
             }
             return string.Empty;
          }
       }
    }
    

    위의 코드를 활용하는 예시는 다음과 같습니다. RoleManager.IsRoleManagerRunning 프로퍼티를 이용하여 클라우드 위에서 실행 중인 응용프로그램인지의 여부를 결정할 수 있습니다.

     

    if (RoleManager.IsRoleManagerRunning)
    {
       // we're in the cloud
       message.Text = RoleManager.GetConfigurationSetting("messageText");
    }
    else if (System.Web.HttpContext.Current != null)
    {
       // we're NOT in the cloud, but we're still in a Web application
       message.Text = WebConfigurationManager.AppSettings["messageText"];
    }
    else
    {
       // not in the cloud, not in the web... desktop app maybe?
       message.Text = ConfigurationManager.AppSettings["messageText"];
    }
    

     

    위의 샘플 코드는 http://blogs.itmentors.com/bill/2009/11/04/configuration-files-and-windows-azure 에서 발췌하였습니다.

     

    3. IIS의 다른 기능 (SMTP, FTP)에 관한 이슈

     

    Windows Azure의 Web Role이 IIS를 사용하기는 하지만, 있는 그대로의 기능을 모두 제공하는 것은 아닙니다. 대표적으로 SMTP와 FTP를 사용해야 하는 웹 사이트의 경우, Windows Azure로 있는 그대로의 상태를 유지하여 이관하는것은 어려울 수 있습니다. Windows Azure에서 SMTP와 FTP를 활용하기 위해서는 Worker Role을 이용해야 하며, 더 나아가서는 Windows Azure Storage를 응용해야 할 수 있습니다.

     

    결론

     

    이번 Chapter에서는 ASP.NET 웹 사이트를 Windows Azure로 이관하기 위하여 고려해야 할 사항들을 살펴보았습니다. 다음 Chapter에서는 ASP.NET 웹 사이트를 Windows Azure로 이관하는 과정에서 추가하는 EntryPoint 클래스에 대한 구체적인 분석을 해보도록 하겠습니다.

     

    감사합니다.

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    Visual Studio2010. 3. 9. 13:17

    FIX: Visual Studio 2010 Release Candidate crashes when the IntelliSense window appears or is dismissed in Text Editor 라는 이름으로 KB980610 문서로 등록된 Visual Studio 2010 RC 패치가 나왔습니다. Visual Studio 2010 RC 버전을 통하여 프로그래밍할 때, ASPX 페이지의 인텔리센스를 사용할 때 발생할 수 있는 프로그램 충돌 현상을 수정하는 것으로 RTM 버전에서는 수정될 것으로 보입니다.

     

    Windows Azure를 이용하여 샘플 프로그래밍을 할 때에도 자주 경험할 수 있는 불편 사항이므로 Windows Azure SDK를 설치하여 테스트 중이신 분들도 모두 아래의 페이지에서 제공되는 패치를 다운로드하여 설치하실 것을 권합니다. 패치 설치 작업 도중에는 관리자 권한을 필요로 합니다.

     

    http://support.microsoft.com/kb/980610

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    Exploring2010. 2. 26. 10:53

    Stackoverflow.com
    Stackoverflow.com은 우리에게 "조엘 온 소프트웨어"로 잘 알려져있는 "조엘 스폴스키"와 "코딩 호러"로 잘 알려져있는 "제프 앳우드"가 함께 만든 웹 사이트로, Experts-Exchange 웹 사이트에 대한 Alternative Website로 많은 인기를 얻고 있습니다. 구글 검색 결과를 자주 접하시는 분들은 모두 동감하시겠지만, Experts-Exchange 웹 사이트의 검색 결과는 항상 "비용 지불"을 요구합니다.

     

    Stackoverflow.com에는 실로 유용한 질문과 답변들이 가득한데, 정말 어려운 문제에 봉착했을 때 시원한 답변을 얻을 수 있는 경우가 많습니다. 이번에 제가 맡았던 씨티은행 외국환업무시스템의 닷넷 기반 프로젝트에서도 많은 도움을 얻을 수 있었습니다.

     

    Stackoverflow.com은 2010년 2월 현재 약 13만 5천여명의 회원과 함께 약 51만 5천개의 Q&A 목록을 보유하고 있으며, C#, 자바, 닷넷, ASP.NET, PHP, 자바스크립트, C++, jQuery, 파이썬 및 아이폰에 대한 내용을 토론하는 스레드들로 채워져있으며 지금 이 시간에도 다양한 질문과 답변이 오고 가고 있습니다. Windows Azure에 대한 내용도 자주 회자되곤 합니다. (위키피디아 설명 인용 - http://en.wikipedia.com/wiki/Stackoverflow)

     

    구글 검색 결과를 살펴보실 때, 사이트 주소에 Stackoverflow.com에서 검색한 결과가 있다면 놓치지 말고 꼭 살펴보시기를 권합니다. :-)

     

    http://www.stackoverflow.com/

     

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    PaaS2010. 2. 21. 02:47

    이전 글 보기: Windows Azure 개발: 간단한 방명록 만들기 [Step 2] / 소스 코드 수정

     

    이전 시간에 이어서, 오늘은 방명록에 업로드한 이미지를 백그라운드에서 실시간으로 처리하는 Worker Role을 작성해보도록 하겠습니다. 방명록에 업로드할 수 있는 이미지의 종류가 다양하고, 간혹 디지털 카메라에서 촬영한, 웹에 업로드하기에는 적합하지 않은 고해상도의 이미지를 처리한다는 시나리오를 세워볼 수 있을 것입니다.

     

    만들었던 Windows Azure 프로젝트를 솔루션 탐색기에서 찾아, Roles 노드를 오른쪽 버튼으로 클릭하여 새 Worker Role 추가 메뉴를 클릭한 후, 아래와 같이 Worker Role의 이름을 Guestbook_WorkerRole로 지정하고 새로 생성합니다.

     

     

    Worker Role을 추가한 후에는, Storage에 만든 Table 자료를 Worker Role에서도 동일하게 액세스할 수 있도록, GuestBook_WorkerRole 프로젝트를 솔루션 탐색기에서 오른쪽 버튼으로 클릭한 후, "참조 추가" 메뉴를 클릭하여 참조 추가 대화 상자를 엽니다.

     

    1. 참조 추가 대화 상자에서, "프로젝트" 탭을 선택하고, 기존에 만들어두었던 GuestBook_Data 프로젝트를 지정합니다.

    2. 이미지를 처리해야 하므로, GDI+ API를 포함하는 System.Drawing 어셈블리가 필요합니다. 마찬가지로 참조 추가 대화 상자에서 System.Drawing 어셈블리를 추가합니다.

     

    참조 추가를 끝낸 후에는 WorkerRole.cs 파일 상단에 네임스페이스 참조를 아래와 같이 추가합니다.

     

    using System.IO;
    using System.Drawing;
    using GuestBook_Data;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient;
    

     

    그리고 Worker Role 클래스의 멤버 변수로 아래와 같이 추가합니다.

     

    private CloudQueue queue;
    private CloudBlobContainer container;
    

     

    그리고 OnStart 메서드에는 다음과 같이 구현합니다.

     

    public override bool OnStart()
    {
      DiagnosticMonitor.Start("DiagnosticsConnectionString");
    
      // Restart the role upon all configuration changes
      RoleEnvironment.Changing += RoleEnvironmentChanging;
    
      // read storage account configuration settings
      CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
      {
        configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
      });
      var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
    
      // initialize blob storage
      CloudBlobClient blobStorage = storageAccount.CreateCloudBlobClient();
      container = blobStorage.GetContainerReference("guestbookpics");
    
      // initialize queue storage 
      CloudQueueClient queueStorage = storageAccount.CreateCloudQueueClient();
      queue = queueStorage.GetQueueReference("guestthumbs");
    
      Trace.TraceInformation("Creating container and queue...");
    
      bool storageInitialized = false;
      while (!storageInitialized)
      {
        try
        {
          // create the blob container and allow public access
          container.CreateIfNotExist();
          var permissions = container.GetPermissions();
          permissions.PublicAccess = BlobContainerPublicAccessType.Container;
          container.SetPermissions(permissions);
    
          // create the message queue
          queue.CreateIfNotExist();
          storageInitialized = true;
        }
        catch (StorageClientException e)
        {
          if (e.ErrorCode == StorageErrorCode.TransportError)
          {
            Trace.TraceError("Storage services initialization failure. "
              + "Check your storage account configuration settings. If running locally, "
              + "ensure that the Development Storage service is running. Message: '{0}'", e.Message);
            System.Threading.Thread.Sleep(5000);
          }
          else
          {
            throw;
          }
        }
      }
    
      return base.OnStart();
    }
    
    

     

    위의 코드에서, BLOB 저장소와 큐 저장소에 대한 정보를 초기화 단계에서 확보하는 것을 볼 수 있습니다. Worker Role의 관점에서 보면, BLOB 저장소는 처리 대상 이미지와 처리 결과 이미지를 입력받거나 출력하는 대상이고, 큐 저장소를 통하여 작업을 지시받고 결과를 반환할 수 있습니다.

     

    그리고 아래와 같이 Run 메서드를 작성합니다.

     

    public override void Run()
    {
      Trace.TraceInformation("Listening for queue messages...");
    
      while (true)
      {
        try
        {
          // retrieve a new message from the queue
          CloudQueueMessage msg = queue.GetMessage();
          if (msg != null)
          {
            // parse message retrieved from queue
            var messageParts = msg.AsString.Split(new char[] { ',' });
            var uri = messageParts[0];
            var partitionKey = messageParts[1];
            var rowkey = messageParts[2];
            Trace.TraceInformation("Processing image in blob '{0}'.", uri);
    
            // download original image from blob storage
            CloudBlockBlob imageBlob = container.GetBlockBlobReference(uri);
            MemoryStream image = new MemoryStream();
            imageBlob.DownloadToStream(image);
            image.Seek(0, SeekOrigin.Begin);
    
            // create a thumbnail image and upload into a blob
            string thumbnailUri = String.Concat(Path.GetFileNameWithoutExtension(uri), "_thumb.jpg");
            CloudBlockBlob thumbnailBlob = container.GetBlockBlobReference(thumbnailUri);
            thumbnailBlob.UploadFromStream(CreateThumbnail(image));
    
            // update the entry in table storage to point to the thumbnail
            var ds = new GuestBookEntryDataSource();
            ds.UpdateImageThumbnail(partitionKey, rowkey, thumbnailBlob.Uri.AbsoluteUri);
    
            // remove message from queue
            queue.DeleteMessage(msg);
    
            Trace.TraceInformation("Generated thumbnail in blob '{0}'.", thumbnailBlob.Uri);
          }
          else
          {
            System.Threading.Thread.Sleep(1000);
          }
        }
        catch (StorageClientException e)
        {
          Trace.TraceError("Exception when processing queue item. Message: '{0}'", e.Message);
          System.Threading.Thread.Sleep(5000);
        }
      }
    }
    
    

     

    while 구문을 통하여, 큐로부터 메시지를 수신하고, BLOB 스토리지로부터 이미지 데이터를 로드하여 처리하는 과정을 코드로 작성한 것입니다. 처리가 끝난 후에는, 큐에 쌓여있는 메시지를 제거하고 다음 메시지를 수신할 때 까지 대기하게 됩니다.

     

    만약 윗 부분의 코드를 비동기 패턴으로 작성한다면, 좀 더 효율적으로 동작하는 Worker Role 인스턴스를 만들 수도 있을 것입니다. (Worker Role 하나가 처리할 수 있는 가용성의 범위는 VM Size에 따라 달라질 수 있지만 보통의 경우, 많은 사용자가 접속을 하게 되더라도 거의 무리 없이 소화가 가능할 것입니다.)

     

    그리고, 위의 코드에서 실제 썸네일 생성을 담당하는 코드는 아래와 같습니다.

     

    private Stream CreateThumbnail(Stream input)
    {
      var orig = new Bitmap(input);
      int width;
      int height;
    
      if (orig.Width > orig.Height)
      {
        width = 128;
        height = 128 * orig.Height / orig.Width;
      }
      else
      {
        height = 128;
        width = 128 * orig.Width / orig.Height;
      }
    
      var thumb = new Bitmap(width, height);
    
      using (Graphics graphic = Graphics.FromImage(thumb))
      {
        graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        graphic.DrawImage(orig, 0, 0, width, height);
        var ms = new MemoryStream();
        thumb.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
        ms.Seek(0, SeekOrigin.Begin);
        return ms;
      }
    }
    

     

    이로서, Worker Role에 대한 구현도 끝이 났습니다. 아직 한 가지가 더 남았는데, 바로 Web Role과 Worker Role을 이어주기 위하여 Web Role에도 큐에 대한 처리가 들어가야 한다는 점입니다. 이제 다시 Web Role 프로젝트로 돌아가서 코드를 조금 수정해보도록 하겠습니다.

     

    메인 웹 페이지 (Default.aspx)의 코드 비하인드에, 아래와 같이 정적 변수를 추가합니다.

     

    private static CloudQueueClient queueStorage;
    

     

    그리고, 파일을 업로드할 때의 버튼 클릭 이벤트에, 기존에 작성하였던 BLOB에 이미지를 저장하는 코드 아랫 부분에, 큐에 메시지를 넣는 부분을 좀 더 추가합니다. 아래와 같을 것입니다.

     

    protected void SignButton_Click(object sender, EventArgs e)
    {
      if (FileUpload1.HasFile)
      {
        InitializeStorage();
    
        ...
    
        // create a new entry in table storage
        GuestBookEntry entry = new GuestBookEntry() { GuestName = NameTextBox.Text, Message = MessageTextBox.Text, PhotoUrl = blob.Uri.ToString(), ThumbnailUrl = blob.Uri.ToString() };
        GuestBookEntryDataSource ds = new GuestBookEntryDataSource();
        ds.AddGuestBookEntry(entry);
        System.Diagnostics.Trace.TraceInformation("Added entry {0}-{1} in table storage for guest '{2}'", entry.PartitionKey, entry.RowKey, entry.GuestName);
    
    
    
        // added code
    
        // queue a message to process the image
        var queue = queueStorage.GetQueueReference("guestthumbs");
        var message = new CloudQueueMessage(String.Format("{0},{1},{2}", uniqueBlobName, entry.PartitionKey, entry.RowKey));
        queue.AddMessage(message);
    
    
        System.Diagnostics.Trace.TraceInformation("Queued message to process blob '{0}'", uniqueBlobName);
      }
    
      NameTextBox.Text = "";
      MessageTextBox.Text = "";
    
      DataList1.DataBind();
    }
    
    

     

    그리고, InitializeStorage 메서드도 조금 수정하면 끝이 납니다.

     

    private void InitializeStorage()
    {
      ...
    
        try
        {
          ...
    
          // configure container for public access
          var permissions = container.GetPermissions();
          permissions.PublicAccess = BlobContainerPublicAccessType.Container;
          container.SetPermissions(permissions);
    
    
    
          // added code
    
          // create queue to communicate with worker role
          queueStorage = storageAccount.CreateCloudQueueClient();
          CloudQueue queue = queueStorage.GetQueueReference("guestthumbs");
          queue.CreateIfNotExist();
        }
        catch (WebException)
        {
           ...
        }
    
        storageInitialized = true;
      }
    }
    
    

     

    이제 완성된 Cloud Application을 직접 테스트해보겠습니다. F5 키를 눌러서 디버그를 시작합니다. 코드 상에 오류가 있을 경우 컴파일 오류나 경고가 발생할 수 있으며, 이러한 부분들을 모두 해결해야 합니다. 정상적으로 디버그 모드에 들어가게 되면, 작업 표시줄의 트레이 아이콘 영역에 아래와 같이 Development Fabric 트레이 아이콘이 나타납니다.

     

     

    Web Role 프로젝트가 있으므로, Internet Explorer 또한 같이 시작될 것입니다. Web Role의 실행 결과를 보여주는 Internet Explorer 창이 아래와 같이 나타나는지 확인합니다.

     

     

    방명록을 작성하고, 첨부할 사진으로 고해상도의 사진을 업로드한 후, 연필 모양의 이미지를 클릭하면 업로드가 됩니다. 테스트해볼만한 고해상도 사진을 찾으려면, Windows XP 이상의 운영 체제들은 모두 %windir%\Web\Wallpapers 폴더의 이미지를 사용하면 됩니다.

     

     

    이미지를 업로드한 직후에는 이미지가 있는 그대로 표시됩니다. 하지만 타이머를 이용하여 주기적으로 Refresh 하도록 페이지를 구성하였기 때문에, 잠시 후 (약 5초 후)에는 아래와 같이 알맞게 크기 조절된 이미지가 대신 표시되는 것을 볼 수 있습니다.

     

     

    세 번의 포스팅에 걸쳐서 Windows Azure로 만드는 간단한 방명록 예시를 살펴보았습니다. 2010년 2월 27일에 있을 Exploring Windows Azure 세미나 ([세미나] Exploring Windows Azure)를 통하여 실제로 프로그래밍하는 모습을 보여드릴 수 있을 것이니 많은 참석 부탁드립니다.

     

    좀 더 다양한 Windows Azure 관련 예제를 필요로 하신다면, Windows Azure Hands-on-Lab을 이용하실 수 있습니다. Windows Azure Hands-on-Lab은 http://go.microsoft.com/fwlink/?LinkID=130354 에서 다운로드 가능합니다.

     

    긴 글을 읽어주셔서 감사드리며, 궁금하신 점은 rkttu nospam rkttu dot com을 통하여 연락하여 주십시오. 2월 27일 세미나에서 뵙겠습니다. 감사합니다. :-)

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    PaaS2010. 1. 4. 00:02

    Windows Azure Platform의 정식 서비스 시작이 이제 얼마 남지 않았습니다. Windows Azure Platform은 시중에 알려진 대로, 올해 2월 1일부터 서비스 요금을 책정하기 시작하여 본격적으로 운영에 들어가게 될 것으로 보입니다.

     

    Windows Azure Platform은 일반적으로 우리가 쉽게 신청하여 사용하는 웹 호스팅 서비스와는 달리, 철저히 서비스 기반의 응용프로그램만을 위한 특별한 플랫폼입니다. 그리고, 이에 따라, 서비스 사용량 측정 방식이나 과금 체계가 웹 호스팅과는 전혀 다르게 이루어지게 됩니다.

     

    Platform Training Kit을 비롯하여 많은 자료들이 소개되고 있지만, 국내 웹 사이트에서 Windows Azure Platform을 본격적으로 다루고 소개하는 자료는 아직 많이 없는 듯 합니다. 이러한 배경을 바탕으로, 조금씩, 이해하기 쉽고 접근하기 쉬운 주제를 기초로 정식 서비스 시행 이전까지 Windows Azure Platform 개발에 관련된 내용들을 소개하고자 합니다.

     

    Windows Azure 응용프로그램을 개발하기 위해서는, Windows Azure Tools를 다운로드받아서 설치해야 합니다. Windows Azure Tools는 Visual Studio 2008과 Visual Studio 2010을 위한 Add-On으로, Windows Azure 어플리케이션을 로컬 컴퓨터에서 시뮬레이션하고, Windows Azure Platform에 게시할 수 있도록 패키지를 작성하는 도구를 포함합니다.

     

    다운로드: http://www.microsoft.com/downloads/details.aspx?FamilyID=6967ff37-813e-47c7-b987-889124b43abd&displaylang=en

     

    오늘 강좌에서 다루어볼 예제는 방명록입니다. Windows Azure Platform의 Compute 기능과 Table Storage 기능을 사용하여 만들어 보도록 하겠습니다.

     

     

    Windows Azure Tools를 설치한 후, Visual Studio 2008을 열어서 새 프로젝트를 만들면, 위와 같이 Windows Azure 프로젝트 템플릿이 설치되어있는 것을 볼 수 있습니다.

     

     

    기존의 프로젝트/솔루션과는 달리 대상 언어와 프로젝트의 세부 종류를 추가적으로 선택할 수 있는 대화 상자가 나타납니다. 화면에서 왼쪽에 나열된 것이 언어 별로 선택할 수 있는 프로젝트 템플릿이고, 오른쪽에 나열된 것이 추가할 프로젝트 템플릿입니다.

    • Web Role: ASP.NET 기반의 응용프로그램입니다.
    • WCF Service Role: WCF 서비스를 독립적으로 실행할 수 있도록 합니다.
    • Worker Role: 백그라운드에서 실행되는 서비스 응용프로그램입니다.
    • CGI Web Role: FastCGI 기반의 응용프로그램을 작성할 수 있게 합니다.

     

    프로젝트를 추가한 후, 솔루션 탐색기의 구성 내역을 살펴보면, 위와 같이 나타납니다.

     

    위의 그림에서 GuestBook 프로젝트는 Windows Azure Platform에 게시될 응용프로그램에 대한 프로젝트입니다. Roles 폴더 안에, 포함될 실제 응용프로그램에 대한 참조를 관리하게 되며, CSCFG 파일에 게시될 응용프로그램에 대한 설정을 넣게 됩니다.

     

    만약, 기존에 개발한 ASP.NET 응용프로그램이 있다면 솔루션에 프로젝트 사본을 추가하고, Roles 폴더 안에 참조를 추가하여 쉽게 패키지로 구성할 수 있습니다.

     

    이제, Windows Azure Table Storage에 데이터 모델을 정의해 보도록 하겠습니다. 방명록에 어떤 형태로 데이터가 저장되어야 하는지를 정의하기 위하여 데이터베이스 대신 코드 수준에서 손쉽게 정의할 수 있습니다.

     

    이번에는, 단순한 클래스 라이브러리 프로젝트를 아래와 같이 생성합니다. Azure 서비스에 포함되어야 하는 프로젝트 임을 명시하기 위하여 _Data 라는 접미사를 프로젝트 이름에 붙였습니다.

     

     

    그리고, 프로젝트 참조 추가 대화 상자를 열어, System.Data.Services.Client 어셈블리를 추가합니다.

     

     

    그리고, Windows Azure Table Storage에 데이터를 저장하거나 가져올 수 있는 LINQ Data Context를 3개의 클래스로 구성하여 작성합니다.

    • GuestBookEntry 클래스: Table Storage에 데이터를 저장하거나 가져올 수 있는 기본 단위 (Atom)를 구성하는 클래스입니다.
    • GuestBookDataContext 클래스: Table Storage에 어떤 테이블을 저장할 것인지를 모델링하는 클래스로, LINQ를 위한 Data Context 클래스의 역할도 수행합니다.
    • GuestBookEntryDataSource 클래스: Table Storage에 자료 구조를 생성하고, 실제로 데이터를 Create/Read/Update/Delete 하는 것을 관여하는 클래스이며, 상속을 받는 대상이 없는 평이한 클래스입니다.

    [code csharp]
    using System;
    using Microsoft.WindowsAzure.StorageClient;
    // 방명록에 대한 엔티티를 정의합니다.
    public class GuestBookEntry : TableServiceEntity
    {
      public GuestBookEntry()
      {
        // 같은 종류의 데이터를 묶어서 관리하기 위한 키를 지정합니다.
        // 아래와 같이 지정함으로서, 연/월/일 별로 방명록 데이터를 묶게 됩니다.
        PartitionKey = DateTime.ToString("MMddyyyy");
        // RDBMS에서 Primary Key를 설정하는것과 마찬가지로, 데이터를 정렬하고, 고유성을 부여하기 위하여
        // RowKey를 지정합니다.
        RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, uid.NewGuid());
      }
      // 모델 정의 시작
      public string Message { get; set; }
      public string GuestName { get; set; }
      public string PhotoUrl { get; set; }
      public string ThumbnailUrl { get; set; }
      // 모델 정의 끝
    }
    [/code]

     

    [code csharp]
    using System;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient;
    // 방명록에 대한 데이터 컨텍스트를 정의합니다.
    public class GuestBookDataContext : TableServiceContext
    {
      public GuestBookDataContext(string baseAddress, StorageCredentials credentials)
        : base(baseAddress, credentials)
      {
      }
      public IQueryable<GuestBookEntry> GuestBookEntry
     {
        get
        {
          return this.CreateQuery<GuestBookEntry>("GuestBookEntry");
        }
      }
    }
    [/code]

     

    [code csharp]
    using System;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient;

    public class GuestBookEntryDataSource
    {
      private static CloudStorageAccount storageAccount;
      private GuestBookDataContext context;
      static GuestBookEntryDataSource()
      {
        // 나중에 여기에 Windows Azure Storage 계정에 대한 연결 문자열이 설정되어야 합니다.
        storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
        CloudTableClient.CreateTablesFromModel(
            typeof(GuestBookDataContext),
            storageAccount.TableEndpoint.AbsoluteUri,
            storageAccount.Credentials); // Context 클래스를 통하여 자료 구조 생성
      }
      public GuestBookEntryDataSource()
      {
        this.context = new GuestBookDataContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
        this.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
      }
      public IEnumerable<GuestBookEntry> Select()
      {
        var results = from g in this.context.GuestBookEntry
                      where g.PartitionKey == DateTime.UtcNow.ToString("MMddyyyy")
                      select g;
        return results;
      }
      public void AddGuestBookEntry(GuestBookEntry newItem)
      {
        this.context.AddObject("GuestBookEntry", newItem);
        this.context.SaveChanges();
      }
      public void UpdateImageThumbnail(string partitionKey, string rowKey, string thumbUrl)
      {
        var results = from g in this.context.GuestBookEntry
                      where g.PartitionKey == partitionKey && g.RowKey == rowKey
                      select g;
        var entry = results.FirstOrDefault<GuestBookEntry>();
        entry.ThumbnailUrl = thumbUrl;
        this.context.UpdateObject(entry);
        this.context.SaveChanges();
      }
    }
    [/code]

     

    이와 같이 코드를 작성하여, Windows Azure Table Storage에 데이터 모델을 정의하는 작업까지 끝났습니다. 다음 강좌에서는, 방명록의 웹 인터페이스를 작성하는 부분과 함께, Windows Azure BLOB Storage의 사용 방법을 살펴보도록 하겠습니다.

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    PaaS2009. 10. 25. 02:16

    요즈음 클라이언트 측 운영 체제는 Windows 7으로, 서버 측 운영 체제는 Windows Server 2008 R2로 모든 이목이 집중되고 있습니다. 양쪽 모두 획기적으로 개선된 기능들로 중무장하여 IT 업계를 흔들고 있고, 오랫만에 "이것이 Windows다" 라고 이야기할 수 있을만큼 선전하고 있습니다.

     

    이런 추세와는 별개로, 꾸준히 Microsoft가 공을 들여서 선보이고 있는 기술이 하나 있는데, 바로 Windows Azure에 관한 것입니다. Windows Azure는 클라우드 컴퓨팅 기술에 대한 Microsoft의 구현 (Implementation)입니다.

     

    Windows Azure는 지난 PDC (Professional Developer Conference) 2008 행사에서 처음 선보였고 현재는 지속적으로 CTP (Community Technology Preview)의 형태로 관련 개발 도구를 제공하고 있습니다. Windows Azure는 Visual Studio 2010과 함께 완전한 개발 도구가 출시될 것으로 현재는 예견되고 있습니다.

     

    이야기로는 Windows Azure가 클라우드 컴퓨팅 플랫폼이라는 말이 참 많이 알려져있지만, 구체적으로 어떤 내용들이 포함되고 어떻게 활용될 수 있는지에 대해서 정리해볼 필요가 있다는 생각으로 글을 써봅니다.

     

    Windows Azure는 다음의 세 가지 구성 요소로 이루어집니다.

     

    Windows Azure: Windows Azure는 클라우드 컴퓨팅 환경 위에서 구동되는 클라우드형 운영 체제입니다. 기존에 우리가 학술적으로 배우고 이해하였던 운영 체제의 개념은 실제 물리적인 컴퓨터 하드웨어 한 대와 실제 사용자 한 명 사이의 창구 개념이었습니다만, Windows Azure에서 소개하는 클라우드형 운영 체제는 조금 다릅니다. 기존 운영 체제의 역할과는 달리, 서비스와 사용자 사이를 중계하는 데에 사용하는 것이 클라우드형 운영 체제의 의미가 될 것입니다.

     

    Windows Azure는 다음과 같은 구조를 가지고 있습니다.

     

     

    위의 그림은 Windows Azure Fabric의 구조를 설명하고 있습니다. Fabric은 사전적인 의미로 천조각을 뜻합니다만, 여기서의 의미는 사용하고자 하는 컴퓨터의 인스턴스 개체 수를 뜻합니다. 그렇게 보았을 때, Windows Azure 개발자는 Fabric을 필요한 수만큼 할당받아, Fabric Agent와 통신하면서 실제 응용프로그램을 작성하게 됩니다.

     

    할당받은 Fabric을 활용하게 되면, 모든 작업은 계산 작업 (Compute)과 저장 작업 (Storage)으로 구분할 수 있습니다. 계산 작업에서는 웹 서비스를 처리하는 것과 백그라운드 작업을 수행하는 것을 가상 머신을 통해서 처리하며, 저장 작업에서는 흔히 생각할 수 있는 BLOB (일반 바이너리 파일이나 데이터)이나 간단한 테이블, 데이터 큐 같은 것들을 저장할 수 있습니다.

     

    Windows Azure를 사용한다는 것은 쉽게 생각하면, 기존의 웹 호스팅과 유사합니다. 실제로 Windows Azure를 이용하여 개발하는 응용프로그램 모델은 HTTP를 통하여 통신하기 때문에 더욱 그러합니다. 하지만 어떻게 개발하는지에 따라서 확장 가능성이 더욱 커지고, 이전보다 더욱 풍부한 소프트웨어를 마음껏 개발할 수 있는 것이 중요한 차이점입니다.

     

    Windows Azure로 호스팅할 수 있는 응용프로그램의 종류는 생각보다 다양한데, 내부적으로 IIS 7.0과 .NET Framework 3.5 SP1을 사용하기 때문입니다. 더불어서, FastCGI를 지원하므로 PHP와 같은 웹 프로그래밍 언어로 작성된 웹 응용프로그램도 얼마든지 호스팅이 가능합니다. 그리고, 이 환경 안에서 실행되는 .NET Framework 코드들은 Full Trust 환경에서 실행이 가능하므로 비관리 코드 (C/C++ 등으로 작성한 DLL이나 운영 체제의 API들)를 자유롭게 호출할 수도 있습니다.

     

    자세한 내용은 http://www.microsoft.com/windowsazure/windowsazure/ 를 참고하십시오.

     

    SQL Azure: SQL Azure는 Microsoft SQL Server를 기반으로 제공되는 클라우드형 RDBMS 서비스입니다. 데이터 보안을 완벽하게 유지해야 하는 시나리오가 아니라면, 급증하는 데이터베이스에 대한 요구 사항을 손쉽게 수용할 수 있는 것이 가장 큰 매력입니다.

     

    참고로, Windows Azure가 제공하는 Storage 서비스와는 차이가 있습니다. Windows Azure 서비스의 Storage 서비스는 RDBMS와는 무관한 것이며, 응용프로그램에 영속성을 부여하기 위한 목적이 강합니다.

     

    SQL Azure가 SQL Server를 기반으로 제공되는 서비스이므로, 당연히 우리가 기존에 사용해 오던 SQL Server Management Tool을 그대로 SQL Azure에서도 사용할 수 있습니다. 그리고 보안 패치나 각종 성능 향상이 자동으로 이뤄지므로 많은 고민 거리들을 머릿속에서 지울 수 있습니다. 그리고 기존에 사용하던 ODBC도 연동이 가능하므로, 일반 데스크톱 응용프로그램에서도 환경에 가변적이지 않은 완벽한 데이터베이스 솔루션을 사용할 수 있습니다. (심지어 VC++ 6.0으로 개발했던 프로그램일지라도 말입니다.) 그리고 PHP 개발자들의 경우, 멀리가서 DB를 찾지 않아도 됩니다. (PHP 전용 프로바이더가 제공됩니다.)

     

    자세한 내용은 http://www.microsoft.com/windowsazure/sqlazure/ 를 참고하십시오.

     

    Microsoft .NET Services: Microsoft .NET Services는 Windows Azure 위에서 구현된 서비스로, 서로 다른 응용프로그램 사이에 통일된 커뮤니케이션 채널을 만들어서 같은 내용을 공유하고, 송신하거나, 수신할 수 있도록 도와주는 서비스입니다. 여기에는 보통의 텍스트, XML 문서, 그래픽, BLOB과 같이 일상적으로 많이 사용하는 데이터 종류들이 모두 포함됩니다. 다음은 상세한 구조에 대한 그림입니다.

     

     

    그림에서 보여지는것처럼, Windows Azure 플랫폼을 기초로 하는 .NET Service Bus는, 서로 다른 응용프로그램을 현대 IT 환경에서 사용하는 다양한 제약 사항들 (방화벽, NAT 등)을 건너뛰고 응용프로그램 사이에 커뮤니케이션 채널을 만드는 과정을 보여주고 있습니다.

     

    뿐만 아니라, .NET Service Bus는 아래와 같이 Access Control Service에 대한 내용도 소개하고 있습니다. Access Control Service를 통하여 보안 정책을 설정하고 관리한다면, 의도하지 않았거나 차단 정책에 포함해야 할 상대를 정확히 파악하고 관리하여 서비스 보안에 만전을 기할 수 있습니다. 그리고 무엇보다도, Windows Azure 플랫폼 위에서 실행되므로 다른 Windows Azure 플랫폼과 연동하기가 편리합니다.

     

     

    자세한 내용은 http://www.microsoft.com/windowsazure/dotnetservices/ 를 참고하십시오.

     

    향후에도 더욱 편리하고 클라우드 컴퓨팅 환경에 필요한 솔루션들이 더 등장할 것입니다만, 이 글을 작성하는 현 시점에서는 이와 같은 서비스들이 선을 보이고 있습니다. 앞으로의 발전 방향이나 추세가 더욱 기대되는 플랫폼입니다.

     

    Windows Azure는 현재 CTP 단계에 있으며, 이에 따라 다음과 같은 제한 사항이 있습니다.

    • 총 컴퓨터 사용 가능 시간: 총 2000 시간 (가상 머신 기준)
    • 총 사용 가능 저장소 용량: 총 50GB
    • 총 트래픽 허용량: 매일 20GB 이내

    그리고 실제로 서비스가 상용화되면 다음과 같이 가격이 매겨질 것임을 발표한 바 있습니다.

    Windows Azure를 테스트해보고 싶으신 분들은 http://www.microsoft.com/windowsazure/getstarted/ 의 내용을 참고하시어 필요한 SDK와 서비스 신청을 완료하실 수 있을 것입니다.

     

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    1. 우와 멋진데요?
      대략적으로만 알고있었지 이렇게 멋진건지는 이제야 알았어요 ^^
      감사합니다 ^^

      2009.11.01 18:18 [ ADDR : EDIT/ DEL : REPLY ]
      • 도움이 되셨다니 기쁩니다. :-)

        윈도 애져를 비롯해서 아마존 EC2 컴퓨팅 플랫폼도 알아두시면 유익한 점이 많이 있으실 것입니다.

        2009.11.01 18:23 [ ADDR : EDIT/ DEL ]

    Windows + .NET2009. 9. 14. 10:19

    ASP.NET 2.0 이후로는 코드 비하인드에서 주로 사용하는 C# 언어 말고도 동시에 Visual Basic .NET, C++ CLR, JScript.NET 등의 프로그래밍 언어를 사용할 수 있습니다. 그러나 App_Code 폴더의 경우 동시에 여러 프로그래밍 언어를 사용하여 컴파일하려고 할 경우 아래와 같은 오류 메시지를 만나게 됩니다.

    위와 같은 오류가 발생하였을 경우 어떻게 처리하면 좋을까요? 이 때에는 App_Code 밑에 별도의 분리된 Sub Directory를 구축하여 언어 별로 달리 구성하는 것이 가능합니다.

    web.config 파일에서 <system.web> 요소 아래에 <codeSubDirectories> 컬렉션 요소에 별도로 구분하고 싶은 서브 디렉터리의 이름을 지정하고, 솔루션 탐색기의 디렉터리 구조에서처럼 App_Code 폴더 밑에 같은 이름의 디렉터리를 생성하여, 여기에 다른 프로그래밍 언어의 코드를 지정해두면 설정은 끝납니다.

    이렇게 변경함으로서, App_Code 폴더의 코드는 C#만을, App_Code 폴더 내의 SubDir 폴더의 코드는 VB.NET만을 사용하면서도, 단일 웹 사이트 내에 모두 연결되는 어셈블리들이기 때문에 Public으로 노출하는 어셈블리들은 프로젝트에서 사용이 가능합니다. 만약 Reflection을 활용해야 하는 경우 주지해야 할 것이 하나 있는데 서브 디렉터리로 분리한 경우 이것은 App_Code라는 어셈블리와는 또 다른 별개의 어셈블리가 된다는 점입니다. 같은 방법으로 Phalanger (PHP의 .NET Framework 구현), JScript.NET, IronPython, C++ CLR 등의 코드를 쉽게 ASP.NET 사이트 안으로 통합할 수 있습니다.

    동적으로 생성되는 어셈블리임을 감안하여 Assembly에 적용할 수 있는 Attribute를 사용하여 식별이 편리하도록 구성하면 Reflection을 필요로 하는 경우 도움이 될 수 있습니다.

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요

    Web Programming2009. 9. 13. 12:27

    dojo와 더불어서 jQuery는 요즈음 웹 상에서 널리 사용되고 인기도가 높은 자바스크립트 프레임워크들 중 하나입니다. 작은 Foot-print를 유지하면서 무엇하나 모자람이 없는 기능을 제공하고 있고, 또한 ASP.NET 개발자들 사이에서는 ASP.NET MVC에서 공식 채택하기 이전부터 널리 사용되어온 자바스크립트 프레임워크입니다.

    jQuery는 AJAX 기능 뿐만 아니라 비동기적으로 자바스크립트를 로드하고, 직렬화된 JSON 컨텐츠를 복원하여 메모리 상에 되살려놓을 수 있는 기능까지 내장하고 있습니다. 하지만 딱 한 가지 아쉬운 점이 있었는데 그 점은 바로 WCF가 노출하는 Contract들 중에서 POST 방식으로 호출해야 할 때 사용이 불편하다는 점입니다.

    REST (GET) 방식으로 호출하는 방법은 대개 유용합니다. URL을 이용하여 호출하는 것이므로 프로그래밍하기에는 훨씬 간단한 방법일 수 있습니다. 하지만 경우에 따라서 전달해야 하는 매개 변수의 수가 많거나 복잡한 자료 구조를 전달해야 하는 경우 적절하지 않을 수 있습니다.

    이 Article에서는 jQuery를 이용하여 POST 방식의 WCF 서비스를 호출하는 방법을 다뤄보기로 하겠습니다. 이 Article에서 사용하는 Code의 원본은 http://www.west-wind.com/weblog/posts/324917.aspx 에서 가져온 것임을 밝혀둡니다.

     public static void NoCaching(WebOperationContext context)
     {
         if (context == null)
             return;

         context.OutgoingResponse.Headers["Pragma"] = "no-cache";
         context.OutgoingResponse.Headers["Cache-Control"] = "no-cache";
     }

     [OperationContract]
     [WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
     public int CreateArticle(int boardID, string title, string contents)
     {
            NoCaching(WebOperationContext.Current);

            if (!Security.IsLoggedOn)
                return (-1);

            int? newArticleID = null;
            this.dataContext.CreateArticle(
                (int?)boardID,
                title,
                (int?)Security.CurrentUserID,
                contents,
                ref newArticleID);

            return newArticleID.HasValue ? newArticleID.Value : (-1);
     }

    위의 코드는 Internet Explorer가 내장하는 XMLHttpRequest의 캐싱 기능을 사용하지 않도록 응답을 내보내는 POST 방식의 WCF Contract 코드 예제입니다. [WebGet] 대신 [WebInvoke]가 사용된 것을 확인하면 됩니다. 그리고 입력과 출력 형식을 모두 JSON으로 지정하였습니다.

    이제 아래의 코드를 별도의 JavaScript 파일로 저장합니다.

    jQuery.invokeWcf = function(serviceUri, method, data, callback, error, bare) {
        var json = JSON.stringify(data);
        var url = serviceUri + '/' + method;

        $.ajax({
            url: url,
            data: json,
            type: 'POST',
            processData: false,
            contentType: 'application/json',
            timeout: 10000,
            dataType: 'text',
            success: function(rawResult) {
                if (!callback) {
                    return;
                }

                var result = JSON.parse(rawResult);

                if (bare) {
                    callback(result);
                    return;
                }

                for (var eachProperty in result) {
                    callback(result[eachProperty]);
                    break;
                }
            },
            error: function(xmlHttpRequest) {
                if (!xmlHttpRequest) {
                    return;
                }

                if (xmlHttpRequest.responseText) {
                    var errorMessage = JSON.parse(xmlHttpRequest.responseText);
                    if (errorMessage) {
                        error(errorMessage);
                    } else {
                        error({ Message: 'Unknown server error found.' });
                    }
                }

                return;
            }
        });
    };

    그리고 위의 코드를 사용하기 위하여 JSON2.js 파일이 별도로 필요합니다. JSON2.js는 http://www.json.org/js.html 페이지에서 다운로드할 수 있습니다. 마지막으로, jQuery 플러그인으로 개발된 위의 코드를 사용하기 위하여 jQuery를 추가해야 합니다. 위의 코드는 1.3.2 버전에서 테스트하였습니다.

    이제 위의 코드를 호출해보기로 하겠습니다.

    var editorInstance = FCKeditorAPI.GetInstance('<%= this.articleBody.ClientID %>');
    var data = {
        boardID: parseInt(boardID),
        title: $('#' + '<%= this.articleTitle.ClientID %>').attr('value'),
        contents: editorInstance.GetXHTML()
    };

    $.invokeWcf('Board.svc', 'CreateArticle', data, function(result) {
        result = result.toString();
        if (result == '-1') {
            window.alert('글 쓰기 도중 오류가 발생하였습니다.');
            return;
        }
        if ($('#fileQueue > .uploadifyQueueItem').size() > 0) {
            $('#fileUploads').uploadifySettings('script', 'UploadHandler.ashx?ID=' + result.toString());
            $('#fileUploads').bind('uploadifyAllComplete', function(event, data) {
                window.location.replace('ViewArticle.aspx?ID=' + result.toString());
            });
            $('#fileUploads').uploadifyUpload();
        } else {
            window.location.replace('ViewArticle.aspx?ID=' + result.toString());
        }
    }, function(result) { window.alert(result); });

    실제 WCF가 제공하거나 입력시 필요로 하는 JSON 코드의 경우 jQuery가 내장하는 getJSON 함수로 다루기에는 까다로운 부분이 많았습니다. 하지만 위의 코드에서처럼 매개 변수를 동적으로 프로그래밍하고 함수 인자를 전달하는 것 만으로 모든 처리가 이루어지게 됩니다.

    많은 도움이 되었기를 바라며 글을 마무리합니다.

    ps. jQuery를 활용하는 RIA 기반 File Upload 솔루션을 찾고 있다면 uploadify (http://www.uploadify.com) 의 소스 코드를 활용해 보실 것을 권합니다. 무료로 사용 가능하며 약간의 테스트와 개발을 통하여 손쉽게 적용할 수 있습니다.

    Posted by Cloud Developer 남정현 (rkttu.com)

    댓글을 달아 주세요