Search

'VSTS 2010'에 해당되는 글 73건

  1. 2011.09.13 ASP.NET과 IIS 7을 위한 로드 밸런싱 전략과 기초적인 이야기, 그리고 Azure Platform (6)
  2. 2011.06.17 [Visual Studio 2010 SP1] HTML5, CSS3 지원 (1)
  3. 2011.06.16 [Visual Studio 2010 SP1] ASP.NET DEPLOYABLE DEPENDENCIES
  4. 2011.06.15 [Visual Studio 2010 SP1] Razor 지원 및 WEB PLATFORM INSTALLER 통합
  5. 2011.06.14 [Visual Studio 2010 SP1] IIS EXPRESS 기능 추가
  6. 2011.06.13 [Visual Studio 2010 SP1] 실버라이트 성능 프로파일 지원
  7. 2011.06.10 [Visual Studio 2010 SP1] .NET FRAMEWORK 3.5 단위 테스트 호환
  8. 2011.06.09 [Visual Studio 2010 SP1] 실버라이트 4 지원
  9. 2011.06.08 [Visual Studio 2010 SP1] Help Viewer 1.1
  10. 2011.05.30 [STL] 13. <algorithm>에 추가된 새로운 함수들 minmax_element
  11. 2011.05.30 Visual Studio Korea 팀의 무료 온라인 백서 공개
  12. 2011.05.11 [STL] 11. <algorithm>에 추가된 새로운 함수들 is_heap, is_heap_until
  13. 2011.04.25 [STL] 10. <algorithm>에 추가된 새로운 함수들 is_sorted, is_sorted_until (1)
  14. 2011.03.25 [StartD2D-2] 왜 GPU 인가? (13)
  15. 2011.03.17 [StartD2D-1] Good-bye~~ GDI… (2)
  16. 2011.01.18 VSS 마이그레이션 전략
  17. 2010.10.18 RValue Reference에 의한 STL의 성능향상 테스트
  18. 2010.08.16 M, V 그리고 C의 각방생활(12) - 테스팅 그거, 아무나 하나? (1)
  19. 2010.08.11 M, V 그리고 C의 각방생활(11) - jqGrid로 데이터 추가,편집,삭제해보기 (28)
  20. 2010.07.28 ASP.NET MVC 3 Preview 1 이 릴리즈 되었습니다. (1)

요즈음 클라우드 서비스들을 이용하다보면, 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를 구축해보는 것도 의미가 있을 것입니다.

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

처음 Visual Studio 2010 릴리즈 되었을 때는 HTML5 기능이 추가가 되지 않았습니다. 그래서 XML Schema 를 이용하는 방법으로 HTML 텍스트 에디터에서 HTML5 구문을 사용하기도 하였습니다. 하지만 이번 Visual Studio 2010 SP1에는 정식으로 HTML5 인텔리센스와 유효성을 검사할 수 있는 기능이 추가가 되었습니다.

이 기능을 활성화하기 위해서 도구->옵션의 텍스트 에디터->HTML->유효성에서 HTML5 유효성 검사를 지정할 수 있습니다.

HTML5가 지원하는 여러 구문을 인텔리센스에서 자연스럽게 보여줍니다.

더불어 CSS3 를 완벽하게 지원하지는 않지만, 일부분 CSS3를 지원해 줍니다. CSS3 기능은 앞으로 그 기능을 보강할 수 있는 확장 기능으로 Visual Studio Gallery 에서 배포가 되길 기대해봅니다.


저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

배포 가능한 종속성(Deployable Dependencies) 는 이번 Visual Studio 2010 SP1 에서 새롭게 추가된 기능입니다. 웹 응용 프로그램을 서버로 배포하기 위해서는 필수 구성 요소들이 설치가 되어 있어야 하는데, 배포 가능한 종속성 기능을 이용하면 웹 응용 프로그램이 동작에 필요한 일부 컴포넌트를 바로 배포할 수 있도록 도와줍니다.

웹 응용 프로그램에서 마우스 오른쪽 버튼을 클릭하여 컨텍스트 메뉴를 활성화하면 다음과 같은 메뉴 항목이 추가가 되어 있습니다.

메뉴 항목을 선택하면 아래와 같은 창이 나타납니다. 이 창에서는 ASP.NET MVC3 에서 사용하는 Razor 컴포넌트와 SQL Server Compact 를 선택할 수 있습니다.

위와 같이 배포 시 포함할 종속된 어셈블리/컴포넌트를 선택하여 확인 버튼을 클릭하면, 다음과 같이 웹 응용 프로그램 프로젝트에 _bin_deployableAssemblies 폴더가 생성이 되고, 이 하위에 관련된 어셈블리가 추가가 됩니다.

웹 응용 프로그램을 게시를 하게 되면, 위의 _bin_deployableAssemblies 폴더의 어셈블리는 웹 응용 프로그램의 bin 폴더로 배포가 됩니다.

물론, 웹 배포 패키지로 .ZIP 파일로 생성을 하여도 종속성을 추가한 어셈블리는 BIN 폴더에 추가가 되며, 이 패키지를 이용하여 배포할 서버에 컴포넌트의 설치 없이 바로 배포할 수 있습니다.

다만 현재는 여러 가지 배포 어셈블리/컴포넌트를 지원하지 않고 아래의 3개지의 컴포넌트만 배포를 지원해 줍니다.

  • ASP.NET Web Pages / Razor
  • SQL Server Compact 4.0
  • ASP.NET MVC 3

저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Razor 지원

ASP.NET MVC3 가 릴리즈 되면서 이에 발맞추어 Visual Studio 2010 SP1이 개발 도구에서 ASP.NET MVC3를 지원합니다. 특히 ASP.NET MVC3 Beta 버전에서는 지원하지 않았던, ASP.NET MVC3의 중요한 기능 중의 하나인 Razor View Engine인데, Razor View Engine의 Syntax 및 Intellisence 도 함께 지원합니다.

새로운 프로젝트를 만들 때 ASP.NET MVC3 프로젝트 템플릿에서 Razor 뷰를 선택하면 Razor View Engine을 사용할 수 있습니다.

더불어 일반 ASP.NET MVC3의 ASPX 페이지 또한 새로운 뷰를 추가할 때 Razor 뷰로 추가하면, 기존 ASP.NET MVC3의 Razor Engine을 그대로 사용할 수 있습니다.

Web Platform Installer 통합

Visual Studio 2010과 Web Platform Installer(WPI) 가 통합이 되었습니다. Visual Studio 2010에서 WPI를 바로 실행할 수 있는 툴바가 추가 되었습니다.

WPI를 통해 아래의 최신 제품을 다운로드 받을 수 있습니다.

  • SQL Server Compact 4.0
  • IIS 7.5 express
  • ASP.NET MVC3
  • WebMatrix
  • 기타…


저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

기본적으로 웹 응용 프로그램을 개발할 경우 로컬에서 동작하는 ASP.NET Development Server 가 활성화가 됩니다.

그림 1 로컬 ASP.NET Development Server 가 동작하는 화면

웹을 개발할 때 Visual Studio가 제공하는 로컬에서 동작하는 ASP.NET Development Server 로 충분히 어려움 없이 개발을 할 수 있으나 웹 개발의 여러 가지 상황을 고려해 보면 기능이 충분하지는 않았습니다.

예를 들면, 기존의 로컬에서 동작하는 ASP.NET Development Server는 특정 웹 페이지나 XML 웹 서비스, WCF 서비스가 SSL(Secure Sockets Layer)로 동작한다거나 WCF의 NET.TCP, NET.PIPE 등의 바인딩을 사용할 수 없었습니다.

이런 여러 가지 기능적으로 IIS Express 를 사용할 경우 얻을 수 있는 이점이 많고, 기존 웹 응용 프로그램을 IIS Express에서 동작하도록 변경하기 위한 절차 또한 매우 간단합니다.

IIS Express가 설치되어 있다면, 웹 응용 프로그램에서 마우스 오른쪽 버튼을 클릭하여 IIS Express 사용을 선택하면 즉시 IIS Express 에서 웹 응용 프로그램이 동작하도록 할 수 있습니다.

그리고 다음의 확인 메시지에서 '예'를 클릭하면 바로 IIS Express로 웹 응용 프로그램을 개발할 수 있습니다.

IIS Express는 윈도우의 알림 영역에서 찾을 수 있으며 이 아이콘을 이용하여 여러 개의 호스팅 되고 있는 웹 응용 프로그램을 관리할 수 있습니다.

IIS Express를 사용하여 Visual Studio 2010에서 여러 가지 설정을 즉시 변경해 줄 수 있습니다.

그림 2 IIS Express 설치시 웹 응용 프로그램 속성

그림 3 기존 ASP.NET Development Server 속성

IIS 7과 IIS Express 버전의 비교표:

Area

IIS 7

IIS Express

Shipping mechanism

Ships with the OS.

Ships out-of-band. It is automatically included with WebMatrix but can also be installed separately.

Supported Windows editions

Limited number of Windows Vista and Windows 7 editions

Most editions of Windows Server 2003, 2008 and 2008 R2

All editions of Windows XP, Vista, Windows 7

All editions of Windows Server 2008 and 2008 R2

Supported .NET Framework versions

v2.0 SP1 and above

v2.0 SP1 and above (.NET 4.0 is required).

Supported programming languages

Classic ASP, ASP.NET, and PHP

Classic ASP, ASP.NET, and PHP

Process model

Windows Process Activation Service (WAS) automatically manages configured sites.

User launches and terminates sites.

Hosted WebCore (aka Hostable Web Core) support

Yes

Yes. IIS Express is implemented as a layer over HWC.

Supported protocols

HTTP, FTP, WebDAV, HTTPS, and WCF (including over TCP, Named Pipes, and MSMQ)

HTTP, HTTPS, and WCF over HTTP

Non-admin support

WAS must run with administrator user rights.

A standard user is allowed to complete most tasks.

Multi-developer support

None

Yes. Configuration files, settings, and Web content are maintained on a per-user basis.

Visual Studio support

Yes

VS 2010 SP1 Beta allows IIS Express to be used instead of Cassini. VS 2008 can also be manually configured to use IIS Express.

Runtime extensions

See http://www.iis.net/download/All for a complete list.

URL Rewrite and FastCGI. These extensions are built into IIS Express.

Management tools

IIS Manager, appcmd.exe

Appcmd.exe. Common IIS Express management tasks are also built into WebMatrix and Visual Studio 2010 SP1 Beta.

System tray support

None

Yes

Includes built-in IIS 7x modules for authentication, authorization, compression, etc.

Yes

Yes

IIS Express를 설치하기 위해 WPI(Web Platform Installer) 다운로드 페이지

http://www.microsoft.com/web/gallery/install.aspx?appid=iisexpress

그림 4 Web Platform Installer 초기 설치 화면

그림 5 기본적인 구성 요소인 IIS Express 설치 화면


저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

실버라이트 4 이전의 버전에서 Visual Studio에서 성능 프로파일을 지원하지 않은 것은 아닙니다. 다만, 개발 도구에서 지원하지 않았을 뿐이고, Command Line을 이용하여 브라우저를 Attached 하여 성능 프로파일을 할 수 있었습니다.

물론, 예전에도 실버라이트에서 성능 프로파일링을 위해 커맨드 라인으로 프로파일링을 할 수 있었습니다. 아래와 같은 순서대로 커맨드를 실행하면 되었습니다.

  1. VSPerfClrEnv /sampleon
  2. "c:\Program Files (x86)\Internet Explorer\iexplore.exe" C:\Breakout\Breakout\Bin\Release\TestPage.html
  3. VSPerfCmd /start:sample /output:MyFile /attach:<PID of iexplore.exe process>
  4. Run your scenario
  5. VSPerfCmd /detach
  6. VSPerfCmd /shutdown
  7. VSPerfClrEnv /off

이번 Visual Studio 2010 SP1에서는 개발 도구에서 직접 성능 프로파일을 지원합니다. 번거로이 Command Line을 사용할 필요 없이, 기존의 성능 프로파일의 사용 경험을 그대로 실버라이트 4에 적용할 수 있습니다.

Visual Studio 2010의 분석->성능 마법사 시작 메뉴를 클릭하여 실버라이트 응용 프로그램을 프로파일링 할 준비를 합니다.

아래와 같이 성능 프로파일을 시작하면 성능 마법사 페이지가 실행됩니다.

  • CPU 샘플링
    예를 들어, 많은 데이터 작업이나 UI요소 핸들링에서 CPU에 얼만큼의 부담을 주는지 측정할 수 있는 방법입니다.

  • 계측
    관리되는 응용 프로그램이 런타임에 얼마만큼의 리소스와 실행 시간을 갖는지 측정할 수 있습니다. 모듈/클래스/메서드 수준에서 성능을 측정할 수 있는 방법입니다.

  • .NET 메모리 할당
    관리되는 응용 프로그램이 얼만큼의 메모리를 소비하고, 가비지 컬렉션(Garbage Collection) 되는지 등의 수준 높은 메모리 정보를 제공합니다.

  • 동시성
    운영체제 차원에서 메모리의 교착 및 컨텍스트 스위칭(Context Switching)을 관찰하고 다른 프로세스에 어떤 영향을 받는지 Low Level의 정보를 제공합니다.


필자는 CPU 샘플링을 선택하였고, 2단계 페이지에서는 어떤 응용 프로그램을 프로파일링 할 지 선택합니다. 만약 솔루션 탐색기에 로드 되지 않은 프로젝트는 실행 파일(.EXE) 형태의 파일을 선택하면 소스 코드 없이 다음 단계로 이동할 수 있습니다.

3단계 마법사 페이지는 즉시 프로파일링을 시작할지 여부를 선택합니다. 기본 설정으로 마침을 선택하면 선택한 프로젝트 또는 실행 파일을 실행하고 프로파일링을 시작하게 됩니다.

응용 프로그램이 실행되면 다양한 테스트 시나리오로 테스트를 진행하고, 응용 프로그램을 마치면 수집된 프로파일링 정보로 프로파일링 결과 페이지를 볼 수 있습니다.

화면의 좌측 상단의 뷰를 변경하면서 성능 구간을 다양한 측면에서 분석을 할 수 있습니다.


저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Visual Studio 2010에서 단위 테스트 프로젝트를 생성하면 .NET Framework 4.0 의 단위 테스트 프로젝트를 지원했습니다. 단위 테스트 프로젝트를 .NET Framework 3.5 로 변경을 하게 되면 올바로 단위 테스트가 수행되지 않았던 문제가 있었습니다. 바로 아래와 같이 .NET Framework 버전을 변경하게 되면 발생하는 오류 메시지입니다.

그림 1 Visual Studio 2010에서 .NET Framework 3.5 로 변경할 경우

때문에 MSBuild 4.0으로 .NET Framework 3.5 빌드 및 테스트를 하게 되면 올바르게 빌드가 되지 않는 문제가 있었습니다.

필자 또한 이러한 문제로 인하여 다음과 같은 불편한 과정을 겪어야 했습니다.

참고

VS2008 을 VS2010 에서 동시에 개발하기

http://blog.powerumc.kr/314

VS2008 과 VS2010 동시에 개발하기 : 테스트 프로젝트가 포함 될 경우

http://blog.powerumc.kr/315

Visual Studio 2010 SP1은 이제 .NET Framework 3.5 버전의 단위 테스트도 지원이 가능하게 되었습니다.

그림 2 Visual Studio 2010에서 .NET Framework 3.5, 4.0 모두 단위 테스트 지원

다만, Visual Studio 2010 SP1은 .NET Framework 3.5까지 단위 테스트 프로젝트를 지원하며, 그 이하(.NET Framework 2.0, 3.0) 단위 테스트는 지원하지 않습니다.

저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Visual Studio 2010 SP1 의 실버라이트 4 개발 환경

Visual Studio 2010 SP1은 실버라이트 4 개발자 툴 킷이 포함이 되어 바로 실버라이트 4 개발을 할 수 있습니다.

그림 4 실버라이트 프로젝트 템플릿 선택

기존의 실버라이트 프로젝트 템플릿을 선택하여 프로젝트를 생성하면, 실버라이트 버전을 선택하여 원하는 실버라이트 버전으로 개발을 할 수 있습니다.

그림 5 실버라이트 버전 선택

실버라이트 4는 많은 사용자의 요구 사항과 코어의 변화가 있습니다. 자세한 내용은 아래의 링크를 ㅋ통해 MSDN 을 참고하십시오

참고

Silverlight 4의 새로운 기능 http://msdn.microsoft.com/ko-kr/library/dd772166(v=vs.95).aspx

실버라이트 4 의 새로운 기능

  • 컨트롤
  • 브라우저 외부에서 실행
  • 미디어
  • 네트워킹
  • 인쇄
  • 사용자 인터페이스
  • XAML
  • 데이터
  • 응용 프로그램 모델
  • 코어
  • Silverlight 디자이너
  • Windows Forms 플랫폼 지원
  • 관련 항목
저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[Visual Studio 2010 SP1] Help Viewer 1.1

Visual Studio 2010 2011.06.08 08:30 Posted by POWERUMC

웹 브라우저 도움말이 데스크탑 응용 프로그램으로 변경

Visual Studio 2010 이전의 도움말 설명서(Help Documentation) 은 별도의 클라이언트 응용 프로그램으로 구동되었습니다. 하지만 Visual Studio 2010버전에서는 웹 브라우저를 통해 MSDN Online과 같은 화면으로 도움말 설명서가 로컬 웹 서버를 통해 구동이 되었습니다.

그림 1 Visual Studio 2008 도움말 설명서

그림 2 Visual Studio 2010 로컬 웹 도움말 설명서

두 가지 방식의 장단점은 다르겠지만, Visual Studio 2010 로컬 웹 도움말 설명서는 입력한 내용의 인덱스를 보여주지 않아 매우 불편했었습니다. 클래스 이름이나 네임스페이스 이름으로 검색할 때 AJAX 기술로 키워드의 인덱스를 보여주었더라면 그나마 좋았을 텐데 하고 불편함을 감수하기도 하였습니다.

Visual Studio 2010 SP1 에서는 로컬 웹이 구동되고 키워드가 인덱스 되지 않는 부분을 개선하여 기존의 로컬 도움말 설명서로 개선이 되었습니다.

그림 3 Visual Studio 2010 SP1 의 로컬 도움말 설명서

기존의 Visual Studio 2008 과 유사한 로컬 도움말 설명서 응용 프로그램으로 구동이 됩니다. 다만, 필자는 색인 창을 오른쪽에 도킹하여 쓰는데, 현재 Visual Studio 2010 SP1 에서는 도킹 기능은 제공하지 않습니다.

개선해야 할 점

기존의 웹 브라우저 방식보다 Help Viewer 1.1 이 낫긴 하지만, 여전히 사용자의 측면에서 불편하기는 마찬가지 입니다.

첫 번째, 여전히 로컬 웹 서버가 동작하여 도움말이 구동됩니다. 닫아버리고 싶은 왠지 모를 강박감…!

두 번째, 도움말의 폰트 크기가 제각각 입니다. 폰트도 작은데, 크게 키우면 너무 크고...
좌측은 Help Viewer 1.1, 우측은 MSDN 온라인 도움말.


세 번째, 샘플 코드 구조가 사정없이 깨집니다.
좌측, Help Viewer 1.1, 우측은 MSDN 온라인 도움말

네 번째, 개인적으로 인덱스 창을 오른쪽에 도킹하는데, 도킹 기능이 없네요^^;

다섯 번째, MSDN Documentation 2008 에서는 고유 URL 이 있는데, 지금은 도움말 에이전트의 URL 도 보여주지 않네요.
좌측은 MSDN Documentation 2008, 우측은 Help Viewer 1.1

그 밖에, 사용자 경험은 여러분께 맡기겠습니다.

저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

C++03까지의 STL에는 데이터셋에서 가장 작은 요소를 찾을 때는 min_element, 가장 큰 요소를 찾을 때는 max_element를 사용하였습니다.

그런데 만약 최소와 최대를 동시에 찾을 때는 어쩔 수 없이 min_element max_element를 각각 호출해야 하는 불필요한 불편한 점이 있었습니다.

 

C++0x에서는 이런 불편함을 개선하기 위해 한번에 최소와 최고를 찾아주는 minmax_element 알고리즘이 새로 생겼습니다.

 

 

minmax_element

template<class ForwardIterator>

    pair< ForwardIterator, ForwardIterator >

        minmax_element( ForwardIterator _First, ForwardIterator _Last );

template<class ForwardIterator, class BinaryPredicate>

    pair< ForwardIterator, ForwardIterator >

        minmax_element( ForwardIterator _First, ForwardIterator _Last, BinaryPredicate _Comp );

 

minmax_element 알고리즘에는 조건자를 사용하는 버전과 조건자를 사용하지 않은 버전 두 가지가 있습니다. 데이터셋의 자료형이 유저 정의형(class struct를 사용한)이라면 조건자가 있는 버전을 사용합니다.

 

< 예제 코드 >

#include <iostream>

#include <algorithm>

using namespace std;

 

 

int main()

{

           int Numbers[10] = { 50, 25, 20, 7, 15, 7, 10, 2, 1, 3 };

          

           pair<int*, int*> MinMaxValue = minmax_element( &Numbers[0], &Numbers[10] );

 

           cout << "최소 값 : " << *MinMaxValue.first << endl;

           cout << "최대 값 : " << *MinMaxValue.second << endl;

          

           return 0;

}

 

< 결과 >


 

저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

그간 저희 Visual Studio Korea 팀에서 2010년 6월 1일 REMIX10 무료 온라인 백서를 참석 전원에게 드린 적이 있었습니다.

http://vsts2010.net/338
Visual Studio 2010 최신 PDF 자료를 MSDN 에서 다운로드 받으세요

그리고 지난 2011년 4월 18일, 그 두 번째 온라인 무료 백서를 공개하게 되었습니다.

VISUAL STUDIO KOREA 팀의 온라인 백서 다운로드 사이트

http://msdn.microsoft.com/ko-kr/gg620748

Visual Studio 응용 프로그램 모델링 완전 정복 백서

엄준일 MVP (엔씨소프트) – 다운받기

"Visual Studio 응용 프로그램 모델링 완전 정복 백서" 개발자에서 뛰어난 개발자로 안내하는 효과적인 백서입니다. 최종 산출물인 동작하는 소스 코드를 위해, 모델링에 대한 배경과 방법을 개발자의 관점에서 설명합니다. 그리고 Visual Studio 2010 이용하여 개발자가 효과적으로 모델링을 있는 환경을 제시합니다.

개발자들이여, 이제는 "개발자는 코드로 말한다" 관념을 버리십시오.현대의 소프트웨어 개발에서는 언제까지 당신의 코드가 나오기까지 기다려주지 않습니다.선택과 집중의 개발 생태계에서 당신이 올바른 방향을 바라보고 발을 내딛는다는 것을 아무도 믿어주지 않습니다.

코드로 말하기 이전에 자신의 목적과 목표를 명확하게 시각화하여 말하는 것이야 말로 우리 시대가 원하는 뛰어난 개발자임이 확신합니다.

ASP.NET MVC - M, V 그리고 C 각방생활

박세식 (유니위스) - 다운받기

ASP.NET 가려운 곳을 긁어줄 대안의 프레임워크가 나왔으니 바로 ASP.NET MVC 프레임워크입니다. MVC 각각 담당하고 있는 일이 있습니다. 컨트롤러는 사용자 요청의 흐름을 제어하고 그에 따른 모델과 뷰를 선택하는 , 모델은 데이터와 유효성 검사, 비즈니스 로직을 담당하는 , 뷰는 컨트롤러에서 전달받은 데이터를 UI에서 처리하는 일을 합니다. 이렇게 모델, , 컨트롤러로 명확하게 분리된 구조가 여느 복잡한 어플리케이션도 구조적으로 쉽게 개발할 있도록 도와줍니다. 여기 백서를 통해 개발의 도움을 주는 M, V 그리고 C 각방생활을 소개합니다.

남자의 Visual Studio 2010 TDD(Test Driven Development)이야기

강보람 MVP (IT Flow 선임 컨설턴트), 박세식 (유니위스) - 다운받기

TDD(Test Driven Development), 테스트 주도 개발은 애자일한 개발을 지원하기 위한 하나의 실천적 도구입니다. 하지만, 단순히 세부적으로 어떻게 해야 되는 것인지를 묻는 'How'만으로는 TDD 제대로 이해할 수가 없습니다. 어째서 TDD 소개되었으며, TDD 통해서 어떤 장점을 얻을 있는지를 이야기 하는 'Why' 'What' 동반되어야 TDD 이해할 있는 기반을 마련하는 것이시죠. 여기 개발자가 TDD 대해 나눈 대화를 흥미롭게 재구성해 기록한 백서가 있습니다. 백서를 통해서 TDD 대한 'Why', 'What' 그리고 Visual Studio 2010 개발에 TDD 적용한 'How' 같이 얻으시기 바랍니다.


저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

is_heap is_heap_until는 앞서 소개했던 is_sorted, is_sorted_until과 비슷한 알고리즘입니다. 차이가 있다면 is_heap is_heap_until는 정렬이 아닌 Heap을 다룬다는 것만 다릅니다.

 

is_heap은 데이터셋이 Heap으로 되어 있는지 아닌지, is_heap_until는 데이터셋에서 Heap이 아닌 요소의 첫 번째 위치를 반환합니다.

 

is_heap

template<class RandomAccessIterator>

    bool is_heap(

        RandomAccessIterator _First,

        RandomAccessIterator _Last

    );

template<class RandomAccessIterator, class BinaryPredicate>

    bool is_heap(

        RandomAccessIterator _First,

        RandomAccessIterator _Last,

        BinaryPredicate _Comp

    ); 

 

 

is_heap_until

template<class RandomAccessIterator>

    bool is_heap_until(

        RandomAccessIterator _First,

        RandomAccessIterator _Last

);

template<class RandomAccessIterator, class BinaryPredicate>

    bool is_heap_until(

        RandomAccessIterator _First,

        RandomAccessIterator _Last,

        BinaryPredicate _Comp

);

 

 

is_heap is_heap_until는 각각 조건자를 사용하는 버전과 사용하지 않는 버전 두 개가 있습니다. 조건자를 사용하지 않는 경우는 operator< 를 사용합니다.

 

 

그럼 is_heap is_heap_until을 사용한 아주 간단한 예제 코드를 봐 주세요^^

#include <iostream>

#include <algorithm>

using namespace std;

 

 

int main()

{

           int Numbers1[10] = { 50, 25, 20, 7, 15, 7, 10, 2, 1, 3 };

           int Numbers2[10] = { 50, 25, 20, 7, 15, 7, 10, 6, 11, 3 };

           int Numbers3[10] = { 50, 25, 20, 7, 15, 16, 12, 3, 6, 11 };

          

          

           bool IsResult = false;

           IsResult = is_heap( &Numbers1[0], &Numbers1[10], [](int x, int y) { return x < y; } );

           cout << "Numbers1 Heap인가 ? " << IsResult << endl;

 

           IsResult = is_heap( &Numbers2[0], &Numbers2[10], [](int x, int y) { return x < y; } );

           cout << "Numbers2 Heap인가 ? " << IsResult << endl;

 

           IsResult = is_heap( &Numbers3[0], &Numbers3[10] );

           cout << "Numbers3 Heap인가 ? " << IsResult << endl;

 

           cout << endl;

           int* NumIter = is_heap_until( &Numbers2[0], &Numbers2[10], [](int x, int y) { return x < y; } );

           cout << "Numbers2에서 Heap되지 않은 첫 번째 위치의 값 : " << *NumIter << endl;

 

           return 0;

}

 

< 결과 >

 

 

 

ps : 자료구조 Heap에 대해서 잘 모르시는 분들은 아래의 글을 참고해 주세요

http://blog.naver.com/ctpoyou/105423523


저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

is_sorted는 데이터셋이(컨테이너나 배열) 정렬되어 있다면 true를 반환하고, 그렇지 않다면 false를 반환 합니다.

is_sorted_until는 데이터셋에서 정렬되어 있지 않는 요소의 첫 번째 위치를 반환합니다.

 

is_sortedis_sorted_until의 원형은 아래와 같습니다.

is_sorted

template<class ForwardIterator>

    bool is_sorted( ForwardIterator _First, ForwardIterator _Last );


template<class ForwardIterator, class BinaryPredicate>

    bool is_sorted( ForwardIterator _First, ForwardIterator _Last, BinaryPredicate _Comp );

 

 

is_sorted_until

template<class ForwardIterator>

    ForwardIterator is_sorted_until( ForwardIterator _First, ForwardIterator _Last);

 

template<class ForwardIterator, class BinaryPredicate>

    ForwardIterator is_sorted_until( ForwardIterator _First, ForwardIterator _Last,

               BinaryPredicate _Comp );

 

위의 is_sortedis_sorted_until의 원형을 보시면 알겠지만 조건자(함수객체)를 사용하는 버전과 사용하지 않는 버전 두 가지가 있습니다.

조건자를 사용하지 않는 경우 기본으로 operator<가 적용됩니다.

 

프로그래머는 코드로 이해하죠? ^^ 그럼 바로 예제 코드 들어갑니다.

이번 예제는 간단하게 만들기 위해 정수 배열을 사용해 보았습니다. 아마 STL을 이제 막 공부하고 있는 분들은 알고리즘을 STL의 컨테이너에만 사용할 수 있는 것으로 알고 있는 분들도 있을텐데 그렇지 않습니다. 아래 예제는 int 형 배열을 사용하였습니다.

 

< 예제 코드 >

#include <iostream>

#include <algorithm>

using namespace std;

 

 

int main()

{

           int Numbers1[5] = { 1, 2, 3, 4, 5 };

           int Numbers2[5] = { 5, 4, 3, 2, 1 };

           int Numbers3[5] = { 1, 2, 4, 3, 5 };

           bool IsResult = false;

 

          

           IsResult = is_sorted( &Numbers1[0], &Numbers1[5], [](int x, int y) { return x < y; } );

           cout << "Numbers1. 오름 차순 ? " << IsResult << endl;

 

           IsResult = is_sorted( &Numbers2[0], &Numbers2[5], [](int x, int y) { return x > y; } );

           cout << "Numbers2. 내림 차순 ? " << IsResult << endl;

 

           IsResult = is_sorted( &Numbers3[0], &Numbers3[5], [](int x, int y) { return x < y; } );

           cout << "Numbers3. 오름 차순 ? " << IsResult << endl;

 

           cout << endl;

           cout << "is_sorted에서 조건자(함수객체)를 생략한 경우 " << IsResult << endl;

           IsResult = is_sorted( &Numbers1[0], &Numbers1[5] );

           cout << "Numbers1 is_sorted의 결과는 ? " << IsResult << endl;

           IsResult = is_sorted( &Numbers2[0], &Numbers2[5] );

           cout << "Numbers2 is_sorted의 결과는 ? " << IsResult << endl;

 

           cout << endl;

           int Numbers4[8] = { 1, 2, 3, 5, 4, 5, 7, 8 };

           int* NumIter = is_sorted_until( &Numbers4[0], &Numbers4[5], [](int x, int y) { return x < y; } );

           cout << "Numbers4에서 정렬되지 않은 첫 번째 위치의 값 : " << *NumIter << endl;

 

           return 0;

}

 

< 결과 >


 

 

저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[StartD2D-2] 왜 GPU 인가?

DirectX 11 2011.03.25 08:00 Posted by 조진현

 

우리가 예전에 생각했던 PC는 어떤 모습 이였을까요?

앞서 언급했듯이, 아주 오래 전의 PC들은 하나의 CPU를 통해서 연산을 수행하고

결과를 저장하는 구조를 가지고 있었습니다.

또한 오늘 날의 그래픽 처리를 위한 GPU라는 개념도 초창기에는 상상하기 힘든 개념 이였습니다.

하지만, 오늘 날의 PC는 CPU는 여러 개이며, GPU의 성능 또한 아주 막강합니다.

거기다 멀티 GPU인 상황이기도 합니다.

이런 변화들은 Windows 운영체제 차원에서 많은 변화를 요구하게 되었습니다.

사실 현재의 개발 환경은 굉장히 과도기적인 상태라고 할 수 있습니다.

이제 막 이러한 패러다임의 변화들에 대해서 많은 소프트웨어적인 기술들이 공개되고,

개발자들의 선택을 기다리고 있는 상황입니다.

( 대표적으로는, TBB나 CUDA 같은 기술들이 있을 것입니다.^^ )

 

XP 시대까지는 많은 부분들이 전통적인 아키텍쳐 구조들을 기반으로 해서 구현되었고,

꾸준히 개선되어 왔습니다.

즉, XP 시대까지는 싱글코어 기반으로 대부분의 아키텍쳐들이 설계되었습니다.

그래서 Windows XP가 안정적이고 훌륭한 운영체제로 평가 받는 것입니다.

 

하지만, Windows 7 운영체제를 시작으로 앞으로는 많은 수의 CPU를 활용한 구조와

GPU를 활용하는 구조로 변경되고 있으며, 빠르게 XP세대를 대체해 나갈 것입니다.

( 정확하게는 Windows Vista 운영체제부터 시작되었습니다.^^ )

 

앞서 DirectX의 탄생의 과정에 대해서 짧게 살펴보았습니다.

DirectX의 가장 큰 장점은 그래픽 하드웨어의 지원을 받아서

빠른 성능으로 고품질의 결과를 처리할 수 있다는 것이다.

마이크로소프트는 DirectX를 이용해서 고속으로 드라이버에 접근할 수 있는 구조를 만들었습니다.

이를 HAL 이라고 합니다.

 

결론을 얘기하자면,

DirectX 이용한 렌더링( rendering ) 작업이 GDI를 이용한 작업보다 훨씬 더 빠르고 뛰어납니다.

품질은 비교해 보면, 아래와 같습니다.

 

 

현 세대의 PC들은 막강한 성능의 GPU를 탑재하고 있으며,

이들은 대부분 게임과 같은 멀티미디어 관련 애플리케이션을 실행하지 않는 이상은

거의 사용되지 못하고 있었습니다.

그래서 Windows 7 운영체제는 이를 활용하기 위해서 화면에 그리는 작업 패러다임을

완전히 변경해 버렸습니다.( 물론 비스타도 포함됩니다.^^ )

아래의 그림이 이제는 윈도우즈 운영체제 환경의 기본 추상화 계층입니다.

 

 

 

위의 그림에서 보이는 것처럼, 이제 화면에 무엇인가를 그리는 모든 작업은

DirectX를 이용해서 수행하게 되었습니다.( DXGI가 바로 DirectX 입니다. )

이 말은 즉, 기본적으로 GPU를 활용한 한다는 의미입니다.

그렇다고 현재 GDI 가 당장 사라져 버린 것은 아닙니다.

아직까지는 호환성 유지를 위해서 상당기간 공존할 것입니다.

하지만 DirectX 를 활용하는 이 방법은 빠르게 GDI를 대체해 나갈 것이다.

 

 

CPU는 범용 목적으로 설계되었기 때문에,

렌더링 목적으로 설계된 GPU 보다는 렌더링에 대한 작업만큼은 느릴 수 밖에 없습니다.

왜냐하면 GPU는 복잡하고, 많은 수치 연산에 특화된 구조이기 때문입니다.

 

이 DirectX를 강력함을 사용하기 때문에 XP 세대의 운영체제보다 Windows 7이 좋습니다.

( 왠지 홍보하는 것처럼 들리겠지만, 부인할 수 없는 사실이랍니다. ^^ )

 

앞으로 윈도우 프로그래밍에서도 이 DirectX를 이용하는 것이 보편화 될 것입니다.

이제 윈도우 프로그래밍 세계도 큰 변화가 예고되고 있습니다.

 

왜 GPU인가?

 

오늘 날, 프로세싱 유닛의 관점에서 컴퓨터를 바라보면 아래와 같습니다.

 

 

위의 그림에서 CPU는 4개입니다. 이 말은 연산 처리가 가능한 유닛이 4개라는 얘기입니다.

오른쪽 그림은 그래픽 카드를 표현한 것인데,

그래픽 카드는 SIMD 형태로 데이터를 병렬적으로 처리할 수 있는 유닛이 매우 많이 존재합니다.

직관적으로 평가해도 좌측의 CPU 4개 보다는 훨씬 많아 보입니다.

컴퓨터에 CPU 3GHz 가 4개 구동되고 있다면, 초당 연산을 하는 횟수가 48~96GFlops 라고 합니다. ( GFlops 는 109 Flops입니다. )

반면 1GHz GPU 1개가 처리할 수 있는 연산 횟수는 1TeraFlops 입니다. ( TeraFlops는 1012 Flops 입니다. )
GPU는 실수(float) 처리와 병렬처리에 이미 최적화 된 유닛이기 때문에 이것이 가능합니다.

반면 CPU는 범용 목적으로 설계된 유닛입니다.

그래서, If 문과 같은 조건 분기 명령어들은 GPU보다 CPU가 훨씬 빠르게 처리할 수 있습니다.

지금까지는 GPU는 그래픽 처리만을 위해서 존재했었습니다.

특히나 게임과 같은 대용량의 그래픽 처리를 필요로 하는 경우에는
이들의 역할이 절대적 이였습니다.

하지만, 그 이외의 경우는 사용되고 있었을까요?

대답은 '아니다' 입니다.

게임과 같은 경우 DirectX를 통해서 이들을 활용할 수 있었지만,

일반 애플리케이션의 경우에는 이 GPU를 활용할 방법이 없었습니다.

즉, 일반 애플리케이션에서 GPU는 거의 아무 일도 하지 않고 방치되어 있는 것입니다.

CPU의 일을 GPU에게 분담해서 CPU의 부담을 줄이고,

GPU의 활용 능력을 극대화 하면 자연스럽게 최적화가 가능합니다.

그래서 GPU를 활용하는 것이 현재 Windows 7 운영체제에서는

하나의 중요한 이슈로서 자리 잡고 있습니다.

신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[StartD2D-1] Good-bye~~ GDI…

DirectX 11 2011.03.17 08:00 Posted by 조진현

 

'윈도우즈 7 운영체제가 왜 좋은 것일까?'

 

이 물음에 프로그래머라면, 어떤 대답을 할 수 있을까요?

여러 가지 대답들이 존재하겠지만, 그 중에 하나인 부분을 지금부터 진행하려 합니다.

지금부터 언급하는 내용은 모니터에 무엇인가를 표현하는 것과 관련이 있습니다.

즉, 드로잉( Drawing ) 작업에 관한 내용입니다.

 

혹시 여러분들은 'GDI' 와 'DirectX' 이들 단어에 대해서 들어본 적이 있습니까?

컴퓨터를 가지고 작업을 경험했던 이들이라면, 들어봤을 법한 용어들입니다.

 

여러분들이 사용하는 컴퓨터의 모니터는 어떤 과정을 거쳐서 우리에게 전달되는 것일까요?

분명히 이것은 하드웨어적인 영역일 수도 있습니다.

조금 더 애플리케이션 프로그래머 관점으로 이 호기심을 확장해 보겠습니다.

'어떻게 하면 모니터 화면을 제어할 수 있을까?'

'어떻게 하면 내가 원하는 모습으로 모니터의 화면에 나타낼 수 있을까?'

'윈도우즈 운영체제에서 화면을 무엇인가를 그리는 시스템은 어떻게 구성되어 있을까?'

 

 

위의 그림은 XP를 포함한 이전 세대의 Windows 운영체제( 이하 XP세대 )가

화면을 제어하는 시스템 구조입니다.

즉, 하드웨어 추상화 계층이라고도 합니다.

XP세대의 운영체제에서는 화면에 무엇인가를 그리기 위해서는

GDI 와 DirectX API, 이 두 가지를 통해서 제어가 가능했습니다.

최종적으로 GDI 와 DirectX API 는 드라이버와 통신을 하면서,

우리의 명령어를 처리해서, 하드웨어로 결과를 보내주게 됩니다.

 

그런데 왜 동일한 일을 하는 구조가 2개씩이나 존재하는 것일까요?

그것은 컴퓨터의 탄생과 발전이 예상을 벗어났기 때문에 생긴 일입니다.

초창기 컴퓨터의 구조는 굉장히 간단했습니다.

아래의 그림을 살펴보겠습니다.

 

 

컴퓨터라는 것은 결국 CPU 에게 연산을 부탁해서 처리된 결과를 메모리에 저장을 합니다.

그리고 이들에 대한 제어를 우리는 I/O 장치들을 통해서 수행하고 확인합니다.

초창기 컴퓨터는 프로세싱 유닛이 CPU 오직 하나였습니다.

그래서 API들은 프로세싱 유닛이 CPU 하나임을 전제로 개발되었습니다.

우리가 지금 배우고 있는 Windows API 역시 CPU가 한나인 경우에

포커스를 두어서 개발되었던 API 였습니다.

 

하지만 오늘날의 컴퓨터는 어떠합니까?

컴퓨터에서 CPU의 수는 2개 이상이고, 앞으로도 그 개수는 증가할 것입니다.

거기다 이제는 프로세싱 유닛이 CPU 뿐만 아니라, GPU 도 활용이 가능한 시대입니다.

메모리는 또 얼마나 발전하고 있습니까?

굉장히 방대한 용량의 메모리를 여러 개 꽂아서 사용하고 있으며,

그래픽 카드에는 비디오 메모리라는 것도 별도로 존재합니다.

컴퓨터의 큰 구조는 변한 것이 없지만, 기능이 점점 세분화 되고 있는 것입니다.

 

이런 하드웨어들의 변화들은 결국 API를 만드는 사람들의 개발 패러다임을 변화시킵니다.

그러한 패러다임의 변화는 애플리케이션 개발자들에게 새로운 학습을 요구합니다.

즉, 여러분들은 그런 변화에 맞추어서 더 많은 공부를 해야 하는 것입니다.T.T

 

 

초창기 Windows 운영체제 차원에서 화면에 그리기 위한 방법은,

GDI 관련 API 를 사용하는 것뿐 이였습니다.

운영체제 차원에서 모든 것을 관리하고 싶었기 때문에,

MS측에서도 별다른 문제를 느끼지 못했을 것입니다.

그런데 예측을 빗나간 부분이 있었는데, 그것은 게임 이였습니다.

게임 개발자들은 GDI 라는 훌륭한 모델이 있음에도 불구하고,

여전히 MS-DOS 기반으로 화면을 제어하고 있었던 것 이였습니다.

이유는 간단했습니다.

GDI 를 활용하면 분명히 쉬운 방법으로 개발을 할 수 있었지만,

DOS 기반의 방법보다 상대적으로 느렸습니다.

MS-DOS를 활용하면 하드웨어를 개발자가 직접 제어할 수 있기 때문에,

Windows 운영체제의 관리를 받는 GDI 보다는 훨씬 빨랐던 것입니다.

( 이 당시만 해도, CPU 사이클을 줄이는 것이 큰 최적화 이슈였습니다. )

MS-DOS를 빨리 벗어나려 했던 MS 입장에서는 적지 않은 충격(?)을 받게 됩니다.

물론 이런 문제는 게임뿐만 아니라,

멀티미디어 관련 개발에서도 나타났던 문제였습니다.^^

 

그렇게 해서 등장한 대한이 바로 DirectX 입니다.

처음 명칭이 GameSDK 였음에서 알 수 있듯이 게임 개발자를 위한 API 였습니다.

이 DirectX는 Windows 95 운영체제부터 추가되어서 활용되기 시작했습니다.

어쩌면, GDI 모델을 완전히 수정할 여유나 계획은 없었을지도 모릅니다.

어찌되었든 현재까지 GDI 와 DirectX는 이렇게 공존하면서 XP 운영체제까지 이르게 되었습니다.

 

XP 세대까지는 화면에 무엇인가를 그리는 작업을 기준으로 봤을 때는,

애플리케이션은 DirectX를 활용하는 애플리케이션과 GDI를 활용하는 애플리케이션으로 나눌 수 있었습니다.

 

GDI( Graphics Device Interface ) 라는 용어에서 보듯이,

일반적인 윈도우 애플리케이션에서 모니터 화면에 무엇인가를 출력하기 위해서는

GDI 라는 것을 이용해서 구현합니다.

이는 2D API 라고 볼 수 있습니다.

GDI를 통해서 애플리케이션과 디바이스 드라이버( Device driver ) 사이를
제어
할 수 있습니다.

XP 세대에서 화면에 보여지는 대부분의 구성은 바로 이 GDI 를 활용한 것입니다.

GDI는 소프트웨어적으로 처리되기 때문에,

그래픽 하드웨어와 상관없이 처리할 수 있다는 큰 장점이 있습니다.

즉, CPU가 그래픽 처리에 필요한 연산을 수행합니다.

 

일반적인 윈도우 애플리케이션은 그래픽 하드웨어를 직접적으로 접근( access )할 수 없습니다.

반드시 GDI를 통해서 디바이스 드라이버에 접근해야 합니다.

GDI 의 최대 강점은 바로 디바이스 독립적( device-dependent ) 이라는 것입니다.

세상의 모든 PC가 동일한 사양을 갖추고 있으면 좋겠지만,

PC들은 저마다 다른 성능과 사양을 갖추고 있기 때문에,

이를 모두 제어하는 것은 굉장히 어렵고 힘든 일입니다.

하지만, GDI 코드는 어떠한 장치에 상관없이 화면에 공통된 그래픽을 표현할 수 있습니다.

왜냐하면 CPU가 이들에 대한 처리를 모두 수행하기 때문입니다.

GDI는 Windows 운영체제의 매우 오래된 기술 중 하나이며,

현재까지도 가장 널리 이용되는 윈도우 그래픽 API 라고 할 수 있습니다.

하지만 최근의 멀티코어 환경과 GPU의 발전은 많은 변화들을 가져왔으며,

GDI도 이러한 변화에 예외가 될 수 없었습니다.

급기야 이제는 DirectX가 GDI를 서서히 대체해 나가는 방향으로
가는 길이 정해지고 말았습니다.T.T

Good-bye!! GDI~~

신고
크리에이티브 커먼즈 라이선스
Creative Commons License

VSS 마이그레이션 전략

Team Foundation Server 2011.01.18 08:30 Posted by POWERUMC

Visual Source Safe 마이그레이션 이전에

많은 분들이 예전에 Visual Source Safe(이하 VSS) 를 사용하시면서, 현재는 이 VSS가 많은 골치거리라고 느끼시는 분들이 많이 계실 겁니다. 사실 소스 제어를 떠나서 VSS는 안정성 면에서 굉장히 불리하죠. 가장 흔하게 겪는 안전성의 문제는 파일 시스템 기반의 소스 제어 데이터베이스가 꼬이는 겁니다. 왜 꼬이는지는 알고 싶지 않지만, 오래 쓰면 쓸수록 꼬입니다.

제가 겪었던 꼬이는 대표적인 문제가 체크인 상태가 다른 사람에겐 체크인 상태가 아니라는 것이죠. 아무리 다른 사람이 최신 버전을 가져와도 그 소스 코드는 예전에 체크인 되었던 소스 코드이고, 불가피하게 강제로 다시 체크인해야 하기도 합니다. 뭐, 여기까지는 정말 가벼운 일상적인 문제이죠? 더 심한 경우는 복구 불능..!

최근 들어서, VSS의 이런 문제 때문에 많이 고생하시는 분들이 다른 소스 제어 제품으로 갈아타려는 준비를 많이 하십니다.

   

왜 VSS에서 이런 문제가 발생하나…?

사실 어쩔 수 없습니다. 지금에야 VSS가 실컷 얻어터질 수 밖에 없지만, 사실 예전에도 뚜렷한 대안이 있었던 것도 아닙니다.

VSS아니면 CVS(Concurrent Versions System) 인데, 이 CVS도 그 기능 자체의 구현이 충실하지 않아 문제점을 얘기하자면 VSS나 크게 별반 다를 것이 없었습니다. 참고로 Wikipedia 의 과거 소스 제어 제품을 보면 다음과 같지요. 즉, 당시에 VSS 보다 더 뛰어난 제품도 찾기 힘들었고, 현대의 이슈인 안정성과 성능, 보안의 요소는 어디를 뒤져봐도 없었습니다. 즉, 당시에는 어떤 제품을 선택하든 똑같은 문제를 겪었을 테니까요.

   

다만, VSS 제품은 VSS 2005 버전까지 오면서 많은 부분에서 보완이 되었지만, 사용자의 요구사항에 매우 소극적으로 대응했던 점에서 아쉬움이 남습니다.

아래는 조만간 나오게 될 백서의 내용 중의 일부이니 참고하세요.

   

 

일반적으로 '형상관리'라는 의미의 소스 제어는 소스 제어(Source Control), 버전 컨트롤(Version Control), 소프트웨어 환경 관리(Software Configuration Management)라고 불립니다. 향후 소스제어는 서버/클라이언트 아키텍처로 변경되면서 개발 조직에서 소스를 공동으로 개발하고 공유할 수 있게 되었습니다.

초기 Microsoft 에서는 소스 제어를 위한 소프트웨어로 Visual SourceSafe(비주얼 소스세이프) 를 내놓게 되었습니다. Visual SourceSafe는 처음 One Tree Software 라고 불리는 회사에서 여러 운영체제를 지원하는 소스 제어 솔루션을 만들었는데, Microsoft 는 이를 1994년에 인수하여 즉시 Visual SourceSafe 3.1 버전을 내놓았습니다. 그 이후로, Visual SourceSafe 4.0, 5.0, 6.0, 2005 버전까지 지속적으로 지원을 하다가, Visual SourceSafe 2005버전을 마지막으로 이 제품의 업데이트는 이루어 지지 않고 있습니다.

Microsoft는 그 이후에 내부적으로 소스 제어 뿐만 아니라 버그 추적/품질 관리/제품 계획에 사용되는 솔루션을 만들었고, 그 이름은 "Product Studio" 라는 제품입니다. 이 제품은 Microsoft 내부적으로 사용하기 위한 제품이었고, 이 제품을 통해 노하우를 발전시켜 비즈니스 프로세스, 개발 등 전반적인 모든 개발 활동을 아우를 수 있는 "Visual Studio Team System, Team Foundation Server" 를 시장에 내놓게 되었습니다.

   

VSS to TFS2010 마이그레이션 전략

일단 아쉽지만 VSS와 같은 제품 군은 TFS(Team Foundation Server)에 100% 마이그레이션이 힘들 수 있습니다. 왜냐하면 VSS는 파일 시스템의 파일 단위 체크인 방식인데, TFS제품은 변경 집합(ChangeSet) 기반의 소스 제어 구조를 가집니다. 변경 집합은 변경이 일어난 묶음의 세트를 얘기하며, 이 변경 집합 덕분에 분기(Branch)/병합(Merge)/이력/관리가 매우 용이합니다. 덕분이 3-ways 방식의 병합이 매우 안정적으로 동작할 수 있고요.

VSS to TFS로 마이그레이션이 100% 보장할 수 없는 예를 들자면, 고객의 데이터베이스 스키마에 "주소"가 없는데, "주소" 컬럼이 생겼다고 주소를 가짜 데이터로 입력할 수 는 없는 노릇입니다. 게임을 예로 들면, 게임 시스템에 새로운 스킬이 생겼다고 종족/레벨/서버를 막론하고 모두가 이 스킬을 습득할 수 없는 것과 마찬가지입니다.

기존의 VSS는 레이블(Labeling) 방식의 이력 관리를 하였기 때문에, 이것을 변경 집합(ChangeSet) 기반으로 바꿀 수는 없습니다. 그래서 100% 마이그레이션이 힘든 한 가지 원인이기도 합니다. 그렇게 때문에 VSS to TFS로 마이그레이션을 결심하였다면, "퀑 대신 닭", "짜장면 대신 짬뽕","아이폰 대신 블랙베리" 라는 심정으로 100%를 기대하시면 오히려 독이 될 수 있답니다.^^

아래는 VSS to TFS 마이그레이션 전략을 메트릭스로 표현해 보았습니다. 물론, 이것 보다 더 많은 고려 사항이 있습니다만, 대략 아래의 정보에 답할 수 있다면 마이그레이션은 가능하다고 말씀 드리고 싶네요.

   

   

Team Foundation Server 및 .NET 플랫폼 기술 문의

언제든지 저희 Visual Studio Korea 공식 팀 블로그에 문의를 주시기 바랍니다. 저희가 모든 것을 가이드해 드릴 수는 없지만, 저희 팀의 다양한 분야의 기술 전문가들이 성의껏 여러분들을 도와드리고 있습니다. 저희 팀은 언제나 새로운 기술에 목말라있고, 먼저 고민하고 뼈저리고 값진 노하우를 경험한 컨설팅/개발/교육 및 강사 출신의 분들과 Microsoft MVP 활동을 하고 계신 많은 분들이 계십니다.

더불어, Microsoft 의 Social Forums 인 http://social.msdn.microsoft.com/Forums/ko-kr/categories/ 에 오시면 많은 전문가들의 생생한 고급 답변을 들을 수 있습니다.


저작자 표시 비영리 동일 조건 변경 허락
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

트위터에서 @All2one님을 통해서 GCC 컴파일러에서 RValue Reference Move Semantics를 사용했을 경우와 그렇지 않은 경우 STL에서 얼마만큼의 성능 차이가 나는지 테스트를 한 결과를 보았습니다.

사이트 주소는 http://cpp-next.com/archive/2010/10/howards-stl-move-semantics-benchmark/

입니다.

 

이것은 GCC 컴파일러를 사용한 경우라서 저는 VC++을 사용하여 어떤 결과가 나오는지 궁금해서 테스트 해 보았습니다.

RValue Reference을 사용하지 않는 가장 최신의 컴파일러는 VC++ 9(VS2008)이므로 VC++10 VC++9를 같은 코드로 컴파일한 후 실행하였습니다.

 

먼저 테스트한 컴퓨터의 하드웨어 사양은 아래와 같습니다.


 

테스트 코드는 아래와 같습니다(GCC로 테스트한 것과 같은 코드입니다).

#include <vector>

#include <iostream>

#include <time.h>

#include <set>

#include <algorithm>

 

const unsigned N = 3001;

 

extern bool some_test;

 

std::set<int>

get_set(int)

{

    std::set<int> s;

    for (int i = 0; i < N; ++i)

        while (!s.insert(std::rand()).second)

            ;

    if (some_test)

        return s;

    return std::set<int>();

}

 

std::vector<std::set<int> >

generate()

{

    std::vector<std::set<int> > v;

    for (int i = 0; i < N; ++i)

        v.push_back(get_set(i));

    if (some_test)

        return v;

    return std::vector<std::set<int> >();

}

 

float time_it()

{

    clock_t t1, t2, t3, t4;

    clock_t t0 = clock();

    {

    std::vector<std::set<int> > v = generate();

    t1 = clock();

    std::cout << "construction took " << (float)((t1 - t0)/(double)CLOCKS_PER_SEC) << std::endl;

    std::sort(v.begin(), v.end());

    t2 = clock();

    std::cout << "sort took " << (float)((t2 - t1)/(double)CLOCKS_PER_SEC) << std::endl;

    std::rotate(v.begin(), v.begin() + v.size()/2, v.end());

    t3 = clock();

    std::cout << "rotate took " << (float)((t3 - t2)/(double)CLOCKS_PER_SEC) << std::endl;

    }

    t4 = clock();

    std::cout << "destruction took " << (float)((t4 - t3)/(double)CLOCKS_PER_SEC) << std::endl;

    std::cout << "done" << std::endl;

    return (float)((t4-t0)/(double)CLOCKS_PER_SEC);

}

 

int main()

{

    std::cout << "N = " << N << '\n';

    float t = time_it();

    std::cout << "Total time = " << t << '\n';

}

 

bool some_test = true;

 

 

< 결과 >


 


 


이 결과를 보면 생성과 알고리즘을 사용했을 때 많은 차이가 나는 것을 알 수 있습니다.

기존에 STL의 알고리즘을 자주 사용한 경우라면 VC++ 10으로 컴파일만 해도 어느 정도의 성능 향상을 얻을 수 있을 것 같습니다.

 

저작자 표시
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
정말이지, 테스팅 그거 아무나 하는거 아니죠. 특히 저처럼 게으른 놈은 발을 들여놓기가 무서울때도 있습니다.
고객분들은 빠른 결과물을 얻길 원하시고, 그 고객이 여럿이면 모두가 자기의 일이 우선이니 빨리 좀 해달라고 아우성 거릴때가 많습니다. 가뜩이나 개발로도 벅찬 시간인데, 테스트라뇨.. 에잇!
하지만, 그렇게 작업을 한 후 스테이징(Staging Server - 라이브 서버에 반영하기 전 배포하여 테스트하는 서버입니다^^) 에 적용해놓으면 테스트팀에서는 온갖 방법으로(정말 어처구니 없는 입력값으로 마구 공격(?)해 들어오시죠) 테스트를 한 후 결과물들을 전달해주시죠. 그것 예외처리하는 것으로 인해 또한번의 시간이 소비되고 다시 테스트하고 다시 결과물 받고, 계속 반복되는거죠. 그렇게되면, 처음에 빨리 개발했던 시간이 무용지물이 되어버리는 것이죠.

신입시절에(지금도 신입 짬밥이죠;;) 과장님 한 분이, '야, 어떻게 너는 일을 주면 생각없이 컴퓨터로 바로 달려들어 개발하냐?' 라고 한 말씀 해주셨습니다. 먼저 그림을 그려보라고, 이면지 많잖아. 없어? 내가 줄까? 그러시며,  흐름을 생각하며, 어떤식으로 해야할지 먼저 그림을 그리라고요.
테스팅하는 것도 먼저 그림을 그려보는 작업 같습니다. 이렇게 개발을 하면 원하는 결과값이 나오겠지하며, 테스트와 병행하며 원하는 결과값이 맞게 나오는지 확인해가며 개발을 해나가는 거죠.



단위 테스트 프레임워크를 사용해보자


닷넷 프레임워크를 위한 테스트 프레임워크가 많습니다. 다들 아시는 NUnit, xUnit, MbUnit 등이 있죠. 하지만, 저 게으른 것 다들 아실겁니다. 그래서! 비주얼 스튜디오 단위 테스트를 이용하겠습니다. 위 단위 테스트 사이트들 들어가서 다운받고 설치하고, 에휴~^^;

ASP.NET MVC 프로젝트를 생성하게 되면 아래의 화면과 같이 단위 테스트를 할지 여부를 묻는 대화상자가 나옵니다. 예(Yes)를 선택하면, 프로젝트가 생성될때 테스트 프로젝트도 같이 생성하게 됩니다.


테스트 프로젝트에는 Controllers라는 폴더가 있고, 그 안에는 샘플프로젝트의 Home컨트롤러와 Account컨트롤러를 테스트하기 위한 HomeControllerTest.cs와 AccountControllerTest.cs 가 있습니다. HomeControllerTest를 열어보면 다음과 같습니다.


Microsoft.VisualStudio.TestTools.UnitTesting 네임스페이스가 임포트 되어 있는 것이 보이고, [TestClass], [TestMethod] 가 눈에 띄네요. 주석을 보니,

TestClass : 테스트 메서드가 포함된 클래스를 식별하는데 사용됩니다.
TestMethod : 테스트 메서드를 식별하는데 사용됩니다.

이렇다네요.^^



테스트와 함께 하시겠습니까?


다음은 TelDirController 소스입니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace UsingTest.Controllers
{
    public class TelDirController : Controller
    {
        //
        // GET: /TelDir/

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

        //
        // GET: /TelDir/Details/5

        public ActionResult Details(int id)
        {
            return View();
        }       
    }
}

아무것도 처리하지 않은 깨끗한(?) 소스입니다. Index(), Details() 라는 두 액션메쏘드가 있고, 두 메쏘드 모두 View를 리턴하고 있습니다.

그럼, TelDirController를 위한 테스트를 생성해보겠습니다.



테스트 만들기


테스트 프로젝트의 Controllers를 오른쪽 버튼으로 클릭한 후 추가 -> 새 테스트를 선택합니다.


테스트하려는 컨트롤러 이름 뒤에 Test 만 붙여서 이름을 만들겠습니다. TelDirControllerTest 처럼요.^^;


확인 버튼을 클릭하면 다음의 소스가 보이실겁니다^^


지금으로선 불필요한 것들을 모두 닫아놓긴 했는데요, 물론 삭제하셔도 됩니다. 이런 것도 싫다 하시면, Controllers 폴더에서 클래스를 생성한 후 TestClass와 TestMethod 속성, 그리고 UnitTesting 네임스페이스를 임포트시키시면 됩니다.



맛보기 테스트


정말 맛만 보여드리겠습니다.^^;

TelDirController.Details 메쏘드가 정말 "Details" 뷰를 리턴하는지 테스트 해보도록 하겠습니다.
먼저 테스트 메쏘드를 만들어보겠습니다.

[TestMethod]
public void DetailsTest()
{
    var controller = new TelDirController();
    var result = controller.Details(1) as ViewResult;
    Assert.AreEqual("Details", result.ViewName);
}

Assert.AreEqual 은 비교대상의 두 값이 같은지 여부를 나타냅니다. 같으면 성공, 다르면 실패.
ViewResult.ViewName은 컨트롤러에서 리턴받은 뷰명을 나타냅니다.
자~ 테스트를 진행해볼까요?


'솔루션의 모든 테스트 실행' 버튼을 클릭합니다. 단축키는 Ctrl+R,A 라고 친절히 알려주네요^^ 물론 지금은 테스트 케이스가 하나라 이렇게 하지만 모든 테스트 실행 좌측에 있는 버튼인 '현재 컨텍스트의 테스트 실행'은 현재 선택받은 곳, 즉 커서가 위치한 곳의 테스트를 진행합니다.


엥?! 실패하였습니다. 예상 값이 Details 인데 실제값은.. 실제값은.. 없네요;;

TelDirController의 Details 메쏘드를 살펴보죠.

public ActionResult Details(int id)
{
    return View();
}

이렇게 되어 있네요. 잘못된 것은 없어보이는데요. 

Details 뷰를 리턴하려면 두 가지 방법이 있습니다. 위처럼 Details 액션 메쏘드에서 return View() 를 하는 방법(이것은 액션 메쏘드의 이름에서 유추가 됩니다), 다른 하나는 명시적으로 return View("Details") 와 같은 방법입니다.

그럼, 또다른 방법을 택해서 테스트를 돌려보죠.

public ActionResult Details(int id)
{
    return View("Details");
}

결과는


통과~.
이래서, 아~ 테스트시에는 뭐든지 확실하게 명시적으로 표현해줘야하는구나~ 라는 것을 알 수 있습니다.^^



마무리요



이번 포스팅은 간단하게 테스트하는 방법에 대해서 알아봤는데요, 다음은 이 테스팅에 대해서 좀더 자세하게 알아보는 시간을 가져보겠습니다.

맛이 어떠셨나요? 다음에는 더 화끈한 맛을 보여드리도록 하겠습니다^^



참고자료 : http://www.asp.net/mvc/tutorials/creating-unit-tests-for-asp-net-mvc-applications-cs
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
잊고 계셨을지도 모를 jqGrid 마지막편입니다.
이번 시간은 jqGrid를 이용하여 데이터를 추가, 편집, 삭제해보는 시간을 가져보도록 하겠습니다.


뷰페이지부터 보죠


지난 포스팅에 이어나갑니다. 먼저 가장 중요한 스크립트 부분을 보시면,

var updateDialog = {
                url: '<%= Url.Action("Update", "Home") %>'
                , closeAfterAdd: true
                , closeAfterEdit: true
                , modal: true
                , onclickSubmit: function (params) {
                    var ajaxData = {};
                    var list = $("#list");
                    var selectedRow = list.getGridParam("selrow");
                    rowData = list.getRowData(selectedRow);
                    ajaxData = { dirId: rowData.dirId };
                    return ajaxData;
                }
                , width: "400"
            };
            $.jgrid.nav.addtext = "추가";
            $.jgrid.nav.edittext = "편집";
            $.jgrid.nav.deltext = "삭제";
            $.jgrid.edit.addCaption = "전화번호부 추가";
            $.jgrid.edit.editCaption = "전화번호부 편집";
            $.jgrid.del.caption = "전화번호부 삭제";
            $.jgrid.del.msg = "정말 삭제하실거에요?";
            $("#list").jqGrid({
                url: '<%= Url.Action("EntityGridData", "Home") %>',
                datatype: 'json',
                mtype: 'POST',
                colNames: ['No', '이름', '전화번호', '이메일', '단축다이얼'],
                colModel: [
                  { name: 'dirId', index: 'dirId', width: 40, align: 'center', editable: true, editrules: { edithidden: false }, hidedlg: true, hidden: true },
                  { name: 'name', index: 'name', width: 200, align: 'left', editable: true, edittype: 'text', editrules: { required: true }, formoptions: { elmsuffix: ' *'} },
                  { name: 'phone', index: 'phone', width: 200, align: 'left', editable: true, edittype: 'text', editrules: { required: true }, formoptions: { elmsuffix: ' *'} },
                  { name: 'email', index: 'email', width: 300, align: 'left', editable: true, edittype: 'text', editrules: { required: true, email: true }, formoptions: { elmsuffix: ' *'} },
                  { name: 'speedDial', index: 'speedDial', width: 200, align: 'center', editable: true, edittype: 'text', editrules: { required: true }, formoptions: { elmsuffix: ' *'}}],
                pager: $('#pager'), 
                emptyrecords: "Nothing to display",             
                rowNum: 3,
                rowList: [3, 10, 20, 50],
                sortname: 'dirId',
                sortorder: "desc",
                viewrecords: true,
                caption: '전화번호부',
                ondblClickRow: function (rowid, iRow, iCol, e) {
                    $("#list").editGridRow(rowid, updateDialog);
                }
            }).navGrid('#pager',
                {
                    edit: true, add: true, del: true, search: false, refresh: true
                },
                updateDialog,
                updateDialog,
                updateDialog

            );

너무 많이 바뀌었나요? 그래도 알아보시죠? :) 굵은거~굵은거~

먼저 보이는것은 updateDialog가 보이네요. url도 보이고 submit 하고 ajax도 보이고.
데이터의 추가,편집,삭제시에 뜨는 팝업창에서 할일들이죠. Home 컨트롤러의 Update라는 액션메쏘드를 호출할거고요.
추가, 편집 후에는 창을 닫을 것이고(closeAfterAdd: true, closeAfterEdit: true), 모달창이고(modal: true), submit시 ajax를 사용하는 것 같아보이네요^^

다음으로 보이는게 $.jgrid.nav... 입니다. 이것은 지난 시간에도 말씀드렸던  grid.locale-en.js 을 수정하는 부분입니다. 이런 언어파일에는 디폴트값이 들어가 있다고 말씀드렸었죠? 기억하시죠? ;;

$.jgrid.edit = {
    addCaption: "Add Record",
    editCaption: "Edit Record",
    bSubmit: "Submit",
    bCancel: "Cancel",
    bClose: "Close",
    processData: "Processing...",
    msg: {
        required:"Field is required",
        number:"Please, enter valid number",
        minValue:"value must be greater than or equal to ",
        maxValue:"value must be less than or equal to",
        email: "is not a valid e-mail",
        integer: "Please, enter valid integer value",
        date: "Please, enter valid date value"
    }
};
$.jgrid.del = {
    caption: "Delete",
    msg: "Delete selected record(s)?",
    bSubmit: "Delete",
    bCancel: "Cancel",
    processData: "Processing..."
};
$.jgrid.nav = {
    edittext: " ",
    edittitle: "Edit selected row",
    addtext:" ",
    addtitle: "Add new row",
    deltext: " ",
    deltitle: "Delete selected row",
    searchtext: " ",
    searchtitle: "Find records",
    refreshtext: "",
    refreshtitle: "Reload Grid",
    alertcap: "Warning",
    alerttext: "Please, select row"
};

뷰페이지에서 수정한 부분은 두껍게 표시하였습니다.

$.jgrid.edit 의 msg중 required:"Field is required", email: "is not a valid e-mail" 이 부분이 뷰페이지의 colModel의 editrules: { required: true, email: true } 값과 매치가 되는 거죠.
또, grid의 네비게이션바에서 추가, 편집, 삭제 표시가 이미지로만 되어있었던 것을( $.jgrid.nav 의 add,edit,del 텍스트값이 빈값으로 되어있죠?) 뷰페이지에서 타이틀을 달아본겁니다.

나머지 부분도 재미있게 수정해서 테스트해보세요^^ 버튼 이름 변경, 필수값 에러 메시지, 경고메시지 등이 수정가능하네요. 



데이터를 처리하자


컨트롤러의 액션메쏘드가 추가되었겠죠? 다음은 HomeController의 추가된 Update 액션메쏘드입니다.

public ActionResult Update(TelDir telInfo, FormCollection formCollection)
{
    var operation = formCollection["oper"];
    if (operation.Equals("add"))
    {
       TelDir telData = new TelDir();
       telData.name = telInfo.name;
       telData.phone = telInfo.phone;
       telData.speedDial = telInfo.speedDial;
       telData.email = telInfo.email;
       _db.AddToTelDirSet(telData);
       _db.SaveChanges();
    }
    else if (operation.Equals("edit"))
    {
       var telData = _db.TelDirSet.First(m => m.dirId == telInfo.dirId);
       telData.name = telInfo.name;
       telData.phone = telInfo.phone;
       telData.speedDial = telInfo.speedDial;
       telData.email = telInfo.email;
       _db.SaveChanges();
    }
    else if (operation.Equals("del"))
    {
       var telData = _db.TelDirSet.First(m => m.dirId == telInfo.dirId);
       _db.DeleteObject(telData);
       _db.SaveChanges();
    }
    return Content("ok");
}

각 요청(add,edit,del) 대로 분기하여 처리하도록 하였습니다.



이제야 보는구나


실행을 해서 결과화면을 보면


멋드러지게 지난시간과는 다른 모습의 grid 가 있는 것을 확인할 수 있습니다. 추가,편집,삭제 버튼이 들어가 있고 옆에 리프레쉬 버튼도 있네요.

추가 버튼을 누르면


깔끔한 박스가 뜨네요. 전 슈퍼맨을 등록해보도록 하겠습니다. 값을 입력하지 않고 그냥 Submit 버튼을 살짝 눌러보시면 이름 입력하라고, 전화번호 입력하라고 아우성일겁니다. editrules: { required: true } 이것때문이죠. 매치된 메시지는 언어 스크립트에 있는 required:"Field is required" 이고요. 값을 정상적으로 입력후에 Submit을 하면...
바로바로 처리가 가능하네요^^ 모달창이 닫히는 부분은 위에서 설명드렸던 closeAfterAdd: true 때문인거죠. 편집하는 부분도 해볼까요? closeAfterEdit: truefalse로 하여 테스트해보세요. 모달창이 닫히지 않고 수정한 값들이 화면의 울렁거림 없이 처리가 되는 것을 확인하실 수 있습니다.

편집하는 부분을 테스트 하시려면 먼저 수정하려는 해당 로우(row)를 선택하신 후 편집 버튼을 클릭하시거나, 해당 로우를 더블클릭하시면 됩니다. 해보시죠?^^;


마지막으로 정말 삭제하실거에요? 를 본후 노는 시간을 마치도록 하겠습니다.




마무리요


정말 jquery 관련 플러그인들은 참 편리하네요. 이렇게 손쉽게 처리가 가능하니 말이죠.
암튼, 이번시간으로 jqGrid는 마치겠습니다. 뭐 한것도 없이 마친다고 하니 웃기네~ 라고 말씀을 해주셔도 마칠겁니다.^^;

아직은 무덥고, 다양한 날씨속에서 지내는 지금, 건강 꼭 챙기세요. 감사합니다^^

참고자료 : http://elijahmanor.com/webdevdotnet/post/jQuery-jqGrid-Plugin-Add-Edit-Delete-with-ASPNET-MVC.aspx
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
아직 ASP.NET MVC 2 의 관련 글도 모두 정리하지 못하고 있는 저에게 ( 게을러서 죄송합니다 :-) )
ASP.NET MVC 3 프리뷰 1 이 릴리즈 되었다는 소식이 들어왔네요^^;
아흑 너무 빠르게 변화되는 참 좋은 세상~ ㅡ,.ㅡ;



ASP.NET MVC 3 소식 전파

ASP.NET MVC 3 프리뷰 1이 릴리즈 되었습니다. 여기서 다운 받으시면 됩니다.

일단 다운받아서 보니 MVC 3 관련된 것이 떡하니 템플릿으로 끄집어내져 있습니다.


정말이지.. 뭔가 많은 것들을 해봐야 할듯한 포스가 느껴집니다. 암튼.


뭐가 어떻게 된 것이냐?( 릴리즈에 추가된 사항들.. )



- 레이저 뷰엔진 :

ASP.NET MVC의 새로운 뷰엔진입니다. 코드를 최소하하도록 도와주죠^^ 자세한 것은 저희 팀블로그의 Razor in WebMatrix를 참고해주세요^^


- 다이나믹 뷰와 뷰모델 속성 :

딕셔너리를 다이나믹을 사용(기존 ViewData 객체를 더 간단한 문법으로 접근하게 해주죠^^)하여 컨트롤러와 뷰사이에 데이터를 전달합니다. 예를 들어, 기존의 경우,

ViewData["Title"] = "ASP.NET MVC 3가 웬말이냐?!";
ViewData["Message"] = "ASP.NET MVC 3 Preview 1이 릴리즈가 되었습니다.";

이렇게 ViewData 딕셔너리를 통해 뷰페이지에 전달하였습니다. 하지만 다이나믹 뷰모델 속성을 이용하여 다음과 같이 위의 두 값들을 ViewData 딕셔너리에 추가할 수 있습니다.

ViewData.Title = "ASP.NET MVC 3가 웬말이냐?!";
ViewData.Message = "ASP.NET MVC 3 Preview 1이 릴리즈가 되었습니다.";

뷰페이지에서도 다음과 같이 받습니다.

<h2>View.Title</h2>
<h2>View.Message</h2>


- 뷰 추가 다이얼로그 박스에서 뷰엔진을 선택할 수 있게 해줍니다. :


커스텀 뷰엔진을 포함한 이번에 추가된 Razor(CSHTML) 을 선택할 수도 있고~
ASPX(C#) 을 선택할 수도 있고~


- 글로벌 필터 :

모든 컨트롤들의 액션 메쏘드에 전역적으로 적용할 필터를 등록할 수 있다네요.
Global.asax의 Application_Start 메쏘드에서

GlobalFilters.Filters.Add(new MyActionFilter());

와 같이 등록할 수 있습니다.

이미, 웹 어플리케이션 프로젝트를 생성하시면,

public static void RegisterGlobalFilters(GlobalFilterCollection filters){}

이 메쏘드가 생성되어있습니다.

filters.Add(new MyActionFilter()); 로 추가하시면 되겠네요^^


- JsonValueProviderFactory 클래스 :

모델을 바로 JSON 데이터로 바인드해준다네요. 액션 메쏘드에서 파라미터로 JSON 데이터를 주고 받을 수 있는 거죠^^;
자세한 것은 Sending JSON to an ASP.NET MVC Action Method Argument 을 참고해서 보시면 됩니다.


- .NET Framework 4의 메타데이터 속성 지원 :

.NET 4의 DisplayAttribute와 같은 속성들을 지원해준다네요.

등등등 이 있지만, 해봐야 알겠죠^^

- 서비스 로케이션과 DI(Dependency Injection) 지원
- .NET Framework 4 유효성검사 속성과 IValidatableObject를 지원
- New IClientValidatable Interface
- 새로운 액션 타입이 추가되었죠 : HttpNotFoundResult(404 에러), HttpStatusCodeResult


계속 살펴보겠습니다.^^ 관련 글 팍팍 진행하도록 하겠습니다. 물론 mvc 2 얘기가 끝난 것이 아니라 병행하면서요 ㅡ,.ㅡ;;
 
참고자료 : http://www.hanselman.com/blog/ASPNETMVC3Preview1ReleasedChannel9VideoAndHanselminutesPodcast224OhMy.aspx
http://haacked.com/archive/2010/07/27/aspnetmvc3-preview1-released.aspx

신고
크리에이티브 커먼즈 라이선스
Creative Commons License


 

티스토리 툴바