Posted
Filed under .NET/ASP.NET

이번 강좌에서는 ASP.NET 1.X 시절의 개발과 ASP.NET 2.0 기반의 개발에서 실제 개발자들이 느끼게 되는 차이점과 어떤 식으로 ASP.NET 2.0에서는 개발을 하면 되는 지에 대한 제 개인적인 생각을 사설 식으로 풀어볼까 합니다.

우선 ASP.NET 2.0에 대한 전반적인 새로운 모습들이 궁금하신 분들은 제가 작년에 월간 마소에 기고했던 다음 컬럼을 한번 읽어 보시기 바랍니다.

http://taeyo.net/lecture/NET/AspNet2.asp

그 글을 보시고 나면, 대단히 많은 새로운 기능들이 추가된 모습에 약간은 당황스러우시거나, 혹은 개발이 훨씬 쉬어질 수 있다는 기대에 기쁨이 느껴질지도 모르겠습니다. 컨트롤들을 뚝딱뚝딱 올려놓으면 모든 것이 알아서 다 되니 말입니다.

하지만, 한 가지 기억해야 할 것은 새로운 버전과 함께 제공되는 새로운 기능들이 반드시 필수적으로 사용해야만 하는 것은 아니라는 점입니다. 새로운 제품은 항상 새로운 기능을 제공하는 것이 당연합니다만, 그것들을 선택적으로 상황에 맞게 사용하는 것은 개발자의 몫입니다. 무턱대고 새로운 기능을 남발하는 것이 언제나 최선의 방법은 아니라는 말씀을 드리고 싶습니다. 제가 ASP.NET 2.0 세미나와 강의를 진행하면서 느끼는 것 중 하나는 교육을 받으시는 분들 중에는 ASP.NET 2.0의 수많은 새로운 기능들을 반드시 사용해야만 한다는 압박감에 사로 잡히셔서, 부담을 느끼는 분들이 의외로 많았다는 것입니다.

사실 중압감을 느끼실 필요는 전혀 없습니다. 일단은 시야를 넓게 가지시고, 새롭게 제공되는 기능이 각각 어떤 역할을 하는 지, 그 기능을 이용하면 기존의 개발과 비교했을 경우 어떤 점이 나아지는 지 정도만을 살펴보는 것으로 충분하다고 생각합니다. 즉, 지금 당장 면밀하게 모든 새로운 기능을 다 알 필요는 없다는 의미입니다. 물론, 다 공부할 수 있다면 더할 나위 없이 좋겠지만 그것은 선택일 뿐 필수는 아니라는 것이죠. 새로운 기능들이 대략적으로 어떤 것이고, 어떤 경우에 적용하면 좋은 지를 큰 그림으로 바라보는 것이 현재로서는 더 중요하다고 생각합니다. 보다 상세한 기능과 구현 방법은 그것을 적용할 경우에 배우셔도 크게 늦지 않는다고 생각하기 때문입니다.

제가 느끼기에는 ASP.NET 2.0 기반의 개발도 ASP.NET 1.x 기반의 개발과 크게 다를 것이 없습니다. 많은 기능이 추가되었지만 그것은 사용하기 나름이기 때문입니다.

요즘 원서로 나오는 책들을 보면 ASP.NET 2.0의 새로운 기능만을 나열하고 있을 뿐, 그들을 이용해서 어떻게 효과적으로 웹 어플리케이션을 제작하는 것이 좋은지에 대해서는 그다지 언급하지 않고 있습니다. 그럴 수 밖에 없는 상황(ASP.NET 2.0이 너무 방대해져 버렸기에)을 이해 못하는 것은 아니지만 그래도 뭔가 ASP.NET 2.0을 효과적으로 적용할 수 있는 방법을 제시하는 책이 나와주었으면 했는데 말이죠(그런 책이 곧 나와줄 것이라 계속 기대하고 있는 중이긴 합니다).

자. 듣고 보니 기분이 훨씬 가벼워졌죠? 그렇다면, 다행입니다. 원래 뭔가 새로운 것을 시작할 때는 그런 첫 마음이 매우 중요합니다. 그렇다면, 이제 시작해 보겠습니다. ^^

ASP.NET 2.0을 개발하려면 물론 예전처럼 텍스트 편집기로 작업이 가능하지만 그래도 Visual Studio 2005가 최적의 도구임을 부인할 사람은(남편할 사람도) 아무도 없을 것입니다. 해서, 강좌도 그 툴을 이용해서 진행합니다.

가장 먼저 Visual Studio 2005로 새롭게 웹 프로젝트를 하나 만들어 보겠습니다. 웹 프로젝트를 새롭게 만드는 시점부터 뭔가 재미난 것을 볼 수 있는데요. 그것은 VS 2005 부터는 웹 프로젝트를 만들기 위해 더 이상 IIS가 필수적으로 요구되지 않는다는 것입니다. 즉, 일반 폴더를 마치 가상 디렉터리처럼 사용할 수 있다는 것이죠. VS 2005 자체가 가상 웹 서버를 내장하고 있어서 일반 폴더에 있는 파일을 실행해도 그 순간 해당 폴더를 가상 디렉터리처럼 만들어서 페이지를 실행해 줍니다. 이는 개발 시에 상당한 이점이 되어줄 것입니다.

저는 C:\WebSites(별도로 이러한 폴더를 만들어 주세요)라는 폴더의 하위로 ASPNET2라는 폴더를 웹 프로젝트의 경로로 지정해 보았습니다. 여러분도 그렇게 만들어 보시겠어요? 그림과 같이 말입니다.

그러면, 해당 폴더가 실제로 가상 디렉토리가 아닌 로컬 파일 시스템에 만들어지는 것을 볼 수가 있습니다. 하지만, 실행을 하게 되면 마치 가상 디렉터리에 존재하는 웹 페이지들이 실행되는 것처럼 동작하게 됩니다. 물론, 이는 VS 2005의 기능일 뿐 ASP.NET 2.0의 기능과는 아무런 상관이 없다는 것은 기억해 주세요 ^^

자. 이제 새롭게 ASPNET2 웹 프로젝트에 웹 폼을 하나 추가해 보도록 하겠습니다. 메뉴 중 [파일][새 파일]을 선택(단축키는 Ctl+N)하셔서 파일을 추가하시는 데요. 당연한 이야기지만 웹 폼을 추가하셔야 합니다. 폼의 이름은 Main.aspx로 주시고, 다음과 같이 [다른 파일에 코드 입력]에 체크 표시를 하도록 하세요. 그래야 코드 비하인드(code behind)를 사용하는 것이 된 답니다. 그리고, 사용 언어는 C#으로 하도록 하겠습니다. (VS 2005부터는 각 폼 별로 언어를 각기 사용할 수 있습니다)

추가된 Main.aspx 페이지는 겉으로 보기에는 ASP.NET 1.x 시절의 웹 폼과 큰 차이가 없습니다. 그렇습니다. 내부적으로는 다소간의 변화가 있었지만, 겉으로 보기에는 큰 차이가 없습니다. 굳이 차이점을 이야기 하라면 다음과 같은 것들이 있긴 하지만요.

1. 클래스 선언 부에 partial 이라는 키워드가 추가되었다.
2. 클래스 안에 컨트롤 선언 코드들과 이벤트 매핑 코드들이 사라졌다.
   (기존 1.x에서는 [Web Form 디자이너에서 생성한 코드] 라는 구역이 있었는데 그 부분이 아예 없어졌습니다)

이는 의미하는 바가 크기에 설명을 하지 않을 수가 없습니다.

partial이란 것은 어떤 의미일까요? 그 단어가 의미하듯이 이는 일부분이라는 의미입니다. 즉, 현재 선언하고 있는 클래스는 전체 클래스의 일부분이라는 의미인 것입니다. C# 2.0에서 새롭게 추가된 partial이라는 키워드는 하나의 클래스를 물리적으로 다른 두 개의 파일에 담을 수 있게 하는 기능입니다. 그리고, 물리적으로 분리되어 있으나 하나의 클래스인 이 들은 컴파일 시에 하나로 합쳐져서 컴파일되는 것이죠. 이는 많은 개발자들이 요구해왔던 기능 중에 하나였고 그래서 .NET 2.0에서 추가되었습니다. 이 기능이 왜 필요한 지는 다음 글을 참고해 보세요. 드원 소프트웨어의 유경상 수석님이 2005년 5월에 월간 마이크로소프트웨어에 기고한 글인데 맘에 들어서 인용을 해 봤습니다.

partial type이 정말로 유용해 지는 것은 웹 서비스 참조나 형식화된 데이터셋과 같이 비주얼 스튜디오가 관련된 코드를 생성해 주는 경우이다. 이전 버전의 비주얼 스튜디오에서 웹 서비스를 참조하면 웹 서비스에 대한 클라이언트 프록시 코드가 생성되곤 했다. 이 프록시 코드는 별도의 .cs 소스 파일로(대개 Reference.cs라는 이름으로) 존재했다. 문제는 이 프록시 코드에 개발자가 별도의 코드를 추가하고자 할 때이다. 자동으로 생성된 소스 파일을 수정하는 것까지는 문제가 없지만 웹 서비스 참조를 갱신(update)하는 경우, 개발자가 추가해 놓은 코드는 모두 유실되어 버린다. 이 때문에 웹 서비스 프록시 클래스를 상속하는 별도의 클래스를 만들고 이 클래스에 코드를 추가하는 우회 방법을 쓰곤 했다. 이러한 우회 방법도 완전하지 않은 것이, 클래스가 특성(attribute)을 추가해야 한다거나 클래스의 private 필드를 액세스해야 하는 경우, 난감한 상황이 발생하곤 했다.

출처 : 마이크로소프트웨어 [2005년 5월]

유경상 수석 컨설턴트의 블로그 : www.simpleisbest.net

그렇다면, ASP.NET 클래스에서는 왜 partial이 사용되는 것일까요? 그것은 위에서 언급한 차이점 2에 그 해답이 있습니다. ASP.NET 2.0부터는 aspx 파일에 서버 컨트롤을 추가하더라도 코드 비하인드에 개체 변수가 생성되지 않습니다. 마찬가지로 이벤트 매핑 코드(this.Load += new EventHandler(..)와 같은)도 추가되지 않습니다. 그러한 코드는 컴파일 시에 동적으로 별도의 partial 클래스로 생성되기 때문입니다. 그리고, 현재의 코드 비하인드 클래스와 하나로 묶여서 컴파일 되어 완전한 하나로 거듭나게 되는 것이죠.

왜 ASP.NET 2.0에서는 그 부분을 partial 클래스로 동적 생성하는 것일까요? 사실, 그 부분은 개발자가 일일이 작성할 필요도 없는 부분인데다가(즉, 자동화 적용이 가능한 부분), 그 부분이 수동으로 편집 가능함으로써 예기치 않은 문제들이 있어왔기 때문입니다. 해서, partial을 적용함으로써 예전 ASP.NET 1.x의 경우에 종종 있어왔던 문제(예를 들면, 배포 후에 실수로 aspx 페이지의 서버 컨트롤 id를 변경한다던가 해서 발생하곤 했던 런타임 오류)를 확실하게 예방하고, 개발자의 노고도 줄여주게 한 것입니다.

해서, ASP.NET 2.0부터는 partial 클래스를 기본적으로 사용하도록 되었습니다. 어떻습니까? Partial이 적용되니 코드 비하인드 클래스도 뭔가 확 다이어트가 되어서 정갈하고 깔끔한 느낌이 들지 않나요? ^^

일단 ASP.NET 페이지만을 놓고 바라봤을 경우에, 개발자들에게 직접적으로 느껴지는 ASP.NET 1.x와 2.0의 차이점은 이 정도입니다. 그 외에 개발하는 방식 자체는 사실 기존과 크게 다르지 않습니다. ^^ 기타 차이점이나 새로운 기능들은 이후 강좌를 통해서 더 설명을 드리겠지만, 그 부분은 ASP.NET 페이지 자체와는 크게 차이가 없는 부분이기에 지금은 설명을 참고(?) 있는 것입니다. (아까부터 배가 아픈데 참느라 힘듭니다)

ASP.NET 2.0의 내부가 기존과 어떻게 달라졌는지가 매우 궁금하신 분들은 다음의 MSDN 링크(한글판)에서 그 자세한 정보를 얻어보시기 바랍니다.

http://www.microsoft.com/korea/msdn/library/ko-kr/dev/aspdotnet/internals.aspx

그렇다면, 이제 화면을 간단하게나마 마저 구성해 볼까요?

다음 그림과 같이 버튼과 레이블을 각각 하나씩 폼 위에 올려서 우리만의 멋진 사이트를 완성해 보도록 하겠습니다.

그리고, 버튼을 더블 클릭하여, 코드 비하인드 페이지의 코드를 다음과 같이 완성하도록 하겠습니다.

public partial class Main : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToString();
    }
}

다 되었다면, 다음과 같이 [솔루션 탐색기]에서 Main.aspx 페이지를 실행해 보세요 ^^

그러면, 다음 그림과 같이 VS 2005의 가상 웹 서버가 동작을 하기 시작하면서 트레이 아이콘에 웹 서버가 올라오는 것을 볼 수 있습니다. 하하하. 재미있죠?

그리고, 웹 페이지는 제대로 동작하여 다음과 같이 화려하고 멋진 결과가 나오는 것을 볼 수 있을 것입니다.

호오~ 멋지죠?

페이지의 결과는 나왔습니다만, 현재 상태로는(VS 2005의 도움이 없이는) 브라우저만으로 페이지를 실행할 수가 없습니다. 웹 페이지가 실제로 IIS 상에서 서비스되는 것이 아니기 때문이죠.

현재의 방식은 VS 2005를 이용해서 IIS 없이 개발자 PC에서 개발할 경우의 시나리오이고요. 실제로 개발이 끝난 다음에는 이를 IIS에 배포를 해야 할 것입니다. 물론 배포를 하는 것은 예전과 같은 방식으로 수동으로 파일을 복사해서 배포할 수도 있을 것입니다만, VS 2005을 이용하면 이러한 배포로 매우 쉽게 가능합니다. ^^ 더불어, 소스(HTML 포함)를 전혀 노출하지 않는 상태로의 배포도 가능하죠.

출처: Taeyo.pe.kr

2007/08/08 11:54 2007/08/08 11:54
Posted
Filed under .NET/ASP.NET

Hello. ASP.NET!!

그렇다. 오랫동안 기다렸다. 손가락이 날뛰고 싶어하는 것을 오랫동안 참고 견디게 한 여러분의 노고를 치하한다. 그러면 이제 개념적인 이야기들을 잠시 접고, 우리의 첫번째 ASP.NET을 바라보도록 하자. 이 간단한 하나의 예제에서 여러분은 웹 폼(Web Form)과 웹 서버 컨트롤, PostBack 그리고 이벤트 중심적인 프로그래밍 방법을 모두 만나볼 수 있을 것이다.

메모장을 열고 다음과 같은 코드를 작성하자.(아직은 Visual Studio.NET을 사용하기에 이르다)

<%@ Page language="c#"%>
<HTML>
    <Script runat="server">
    void btnSubmit_OnClick(Object sender, EventArgs e)
    {
        lblMsg.Text = "클릭!!!";
    }
    </Script>
    <body>
        <form runat="server">
            <asp:Label id="lblMsg" runat="server" /><br>
            <asp:Button id="btnSubmit" runat="server"
                    Text="Click!!!" OnClick="btnSubmit_OnClick" />
        </form>
    </body>
</HTML>

그리고, 이 페이지를 여러분의 가상 디렉터리에 Start.aspx 라는 이름으로 저장해보자. 때오는 TaeyoBook 라는 가상 디렉터리를 만들어 두었다. 만일, 가상 디렉터리가 무엇이고, 어떻게 만드는지를 모른다면 다음 강좌를 참고하도록 하라.

http://www.taeyo.pe.kr/lecture/1_beginner/aspbook6.htm

자. TaeyoBook 이라는 가상 디렉토리를 만들고, 그 안에 위의 파일을 Start.aspx 라는 이름으로 저장했다면, 이제 이 파일은 인터넷을 통해 공개가 되어진 것이다.(여러분의 IP주소가 고정 IP라면) 만일, 여러분이 사설 네트워크 망내에 들어있다면(대부분의 학원, 학교, 교육센터가 그러하다) 여러분의 ASP.NET 사이트는 외부인들은 구경해볼 수 없을 것이다. 하지만, 사설망안의 사람들은 여전히 가능하다.

대부분 아는 이야기겠지만, 개발자 자신이 자신의 서버에 존재하는 aspx 파일을 실행시키기 위해서라면 브라우저로 다음과 같이 URL을 요청하면 된다. 세 가지 중 어떤 방법이든지 사용해도 무관하지만, 일반적으로는 첫번째 방법을 많이 사용한다.

- http://localhost/TaeyoBook/Start.aspx
- http://서버이름/TaeyoBook/Start.aspx
- http://IP Address(아이피 주소)/TaeyoBook/Start.aspx

다음 화면은 이렇게 실행하였을 경우에 나타나는 결과화면이다. 왼쪽은 페이지가 로드되었을 경우의 화면이고, 버튼을 클릭하였을 경우의 화면은 우측과 같다.

좋다. 일단 동작했다는 점은 맘에 든다. 이번에는 브라우저의 결과화면에서 [보기] [소스 (C)]를 선택해서 결과 HTML은 어떻게 만들어졌는지 확인해 보자. 아마도 다음과 비슷할 것이다. (소스 중에는 <input  type="hidden" 컨트롤이 하나 있을텐데 그 안에 들어있는 값들은 때오의 것과 다를 수 있다)

<HTML>
    <body>
        <form name="_ctl0" method="post" action="Start.aspx" id="_ctl0">
            <input type="hidden" name="__VIEWSTATE"
                value="dDwtOTk1MjE0NDA4O3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDE+
                Oz47bDx0PHA8cDxsPFRleHQ7PjtsPO2BtOumrSEhITs+Pjs+Ozs+Oz4+Oz4+
                Oz6H3gaYy7qY2B/L0EAGvSqLn3ak8w==" />

            <span id="lblMsg">클릭!!!</span><br>
            <input type="submit" name="btnSubmit" value="Click!!!" id="btnSubmit" />
        </form>
    </body>
</HTML>

다 되었다. 이제 뭐가 어떻게 된 것인지 설명을 듣는 것만이 남아있다. 그러나, 주의하라. 새로운 기술의 첫번째 예제를 이해하는 것은 매우 중요하다. 첫번째 예제를 어떻게 이해했느냐에 따라 이후의 모든 예제들을 같은 방식으로 이해하려 들 것이기 때문이다. 그런 놀라운 적응력을 여러분들은 보유하고 있다. 그렇기에 이번 예제를 제대로 이해하려는 노력이 필요하다.  

먼저, 원래의 aspx 의 소스를 라인별로 알아보자. 첫번째 라인의 소스는 다음과 같았다.

<%@ Page language="c#"%>

이 부분은 ASP.NET 페이지에서만 사용 가능한 @Page Directive 라는 지시자 구역이다. 반드시 <%@ Page 라는 것으로 시작해야 하며, 이 안에 여러가지 설정을 지정할 수 있다. 이 구역에 지정하는 설정은 ASP.NET 파서와 컴파일러에 의해 사용되어지며, Page 의 여러가지 특성을 정의하기 위해 사용된다. @Page 지시자내에 사용할 수 있는 여러가지 어트리뷰트들은 차후 하나씩 알아보게 될 것이다. 우리의 코드에서는 그 어트리뷰트중에서 language 라는 어트리뷰트를 사용하고 있는데, 이는 현재의 페이지에서 사용할 .NET 언어를 지정하는 특성이다. 우리는 현재의 ASP.NET 페이지에서 사용할 언어로 C#을 지정하고 있음을 알 수 있다.

소스의 다음부분은 <html>의 시작부분이며, 그 밑으로 다음과 같은 서버 사이드 스크립트 블럭이 나오고 있다.

    <Script runat="server">
    void btnSubmit_OnClick(Object sender, EventArgs e)
    {
        lblMsg.Text = "클릭!!!";
    }
    </Script>

서버에서 처리될 스크립트 블럭은 반드시 위처럼 runat="server" 라는 특성을 보유한 <Script> 코드로 작성되어야 한다. ASP.NET 코드의 절반은 runat= "server" 라고 말해도 과언이 아닐 정도로 runat= "server"라는 어트리뷰트는 중요하다.

스크립트 블럭내에서는 void btnSubmit_OnClick(Object sender, EventArgs e)라는 함수가 자리를 차지하고 있지만, 이 함수에 대한 설명은 잠시 미루자. 이 함수는 서버측에서 누군가가 호출을 할 경우에만 작동하는 함수이다. 아직은 그 누구도 이 함수를 부르지 않았으니, 실제로 누군가가 부르는 경우 그 때 이 함수를 확인해 보자.

이제 <body> 안으로 들어간다. 그 안에는 다음과 같은 폼의 코드가 있다.

<form runat="server">

폼 태그 안쪽으로 runat="Server" 라는 어트리뷰트가 설정되어져 있다. 이 설정은 매우 중요하다. 바로 이 runat= "Server"로 인해서 이 폼은 ASP.NET의 웹 폼(Web Form)이 되는 것이다. 두둥~~

잠시 시간이 정지한 듯 보였을 것이다. 이해한다. 웹 폼의 정체가 이토록 썰렁한 것이라는 사실을 알았을 때, ASP.NET의 새로운 프로그래밍 모델인 웹 폼의 정체가 단지 이것이라는 것을 알았을 때의 그 실망감.. 때오도 같은 기분을 느꼈었다. 그러나, 한편으로는 대단한 것이다. 단지 runat= "server"라는 어트리뷰트의 지정만으로 이 폼은 실제로 웹 폼으로써 동작하게 된다. 실제 운영에 필요한 하부구조는 ASP.NET이 준비해 놓은 것이다. 어쨋든 이렇게 웹 폼이 구성되어지면 우리 개발자들은 웹 폼 내부에 놓여질 서버 컨트롤들과 프로그래밍적으로 용이하게 작업할 수 있게 된다.

하나의 ASP.NET 페이지에는 오직 하나의 웹 폼만이 존재할 수 있다는 사실도 기억하자. 그리고, 모든 서버 컨트롤들은 반드시 웹 폼 구역안(<form runat="server"> </form>) 안에 존재해야만 한다. 그래야만 프로그래밍적으로 제어할 수 있다.

이제 폼 내부의 코드로 들어가 보자. 그 안에는 2 개의 ASP.NET Web Control 들이 존재하고 있다. 처음보는 이름의 <asp:Label>과 <asp:Button> 은 그 명쾌한 이름으로 인해 컨트롤들이 ASP.NET 에서 새로이 제공하는 컨트롤이라는 것을 느낄 수 있게 하며, 동시에 각각의 컨트롤이 Label, Button 컨트롤이라는 것을 알 수 있게 하고 있다.

<asp:Label id="lblMsg" runat="server" />

Label 컨트롤은 단지 문자열의 값을 디스플레이하는 역할을 하는 단순한 기능의 컨트롤이다. 이 컨트롤은 서버 컨트롤로 사용할 것이기에 태그 안의 어트리뷰트로 반드시 runat= "server"를 설정해주어야 한다. 그리고, 서버에서 프로그래밍적으로 이 컨트롤의 여러 속성들을 접근하기 위해서 id 를 부여해야 한다. 아이디는 웹 폼내에서는 고유한 값을 가져야 하며, 여기서는 Label의 약어인 lbl을 접두어로 사용하여 lblMsg 라고 그 값을 주었다.

현재 우리의 ASP.NET 코드상에서는 <asp:Label > 컨트롤이지만, 이 코드가 컴파일되고 실행되서 결과물이 만들어질 때에 이 코드는 <span> 태그로 바뀌게 된다. 다음은 이 Label 컨트롤의 코드가 클라이언트에게 전달될 경우에 생성되는 결과 HTML 이다.

<span id="lblMsg"></span>

     서버 컨트롤은 서버에서만 인식되는 컨트롤이다.

서버 컨트롤은 서버에서만 인식되는 컨트롤이다. 클라이언트는 서버에 그러한 컨트롤이 있는지에 대해서는 전혀 알지 못한다. 또한, 클라이언트에서는 서버측의 컨트롤에 접근할 수도 없다. 우리가 작성한 모든 코드는 서버에서 실행시에 사용되는 컨트롤들이다. 클라이언트는 단지 자신이 받아 볼 결과에만 관심이 있다. 다시 말해서, 클라이언트에게는 원래의 aspx 소스를 훔쳐볼 방법이 없다.

그 다음 컨트롤은 Button 컨트롤이다. 마찬가지로 반드시 runat= "server" 라는 부분을 지정해 주어야 하며, id 값도 부여해야 한다. 소스에서는 id를 btnSubmit 라고 지정하였다. 그리고, Text 속성의 값을 지정하고 있다. Text 속성은 버튼이 화면에 출력될 경우에 버튼에 쓰여질 텍스트 문자를 나타낸다. 소스에서는 "Click!!!" 이라고 지정하고 있으며, 결과화면에서 그러한 텍스트를 가진 버튼을 우리는 볼 수 있게 될 것이다. 그리고, OnClick 라는 것에 btnSubmit_OnClick 이라는 값을 지정하고 있는 것을 볼 수 있다.

<asp:Button id="btnSubmit" runat="server" 
        Text="Click!!!" OnClick="btnSubmit_OnClick" />

이것이 바로 웹 폼, 서버 컨트롤들의 이벤트 지정이다. 컨트롤들이 지원하는 이벤트들이 컨트롤들마다 조금씩 다르기는 하지만 대부분의 컨트롤이 OnClick 이라는 이벤트를 지원한다. Button 컨트롤도 이 이벤트를 지원하는데, 이는 버튼이 클라이언트에 의해 클릭되었을 경우 발생한다. (정확히 말하자면, 버튼이 클릭되었을 경우, 서버로 폼을 서브밋하고, 다른 여러가지 기본 처리 후에, 버튼의 클릭 이벤트도 수행을 한다)그리고, OnClick 에 지정된 문자열과 같은 서버측의 함수를 찾아서 그 함수를 수행한다. 만일, 지정된 이름의 함수가 없다면 에러가 발생할 것이다. 그리고, 함수 이름의 대,소문자의 지정이 틀려도 에러가 발생할 것이다. C# 이라는 언어는 문자의 대. 소문자를 구별하는 언어이다. 즉, "a" 와 "A"를 다르게 생각한다는 것이다. 그러므로, "함수를 찾을 수 없습니다."와 같은 에러는 마주하게 되면 스펠링의 대,소문자가 틀리지는 않은지를 검사하도록 하라.

그리고, 이 컨트롤의 소스(태그)를 잘 보면 태그가 닫히기 직전에 / 라는 문자를 사용하고 있는 것을 볼 수 있다. 이는 태그가 닫는 태그(</asp:Button> 과 같은)를 사용하지 않을 경우 반드시 넣어주어야 하는 문자이다. /를 사용하면 닫는 태그를 쓰는 것과 같다고 볼 수 있다. 서버 컨트롤들은 반드시 이렇게 태그의 닫힘을 명확히 지정해 주어야 한다. 그렇게 하지 않으면 제대로 동작하지 않는다.(에러가 발생할 것이다)

또한, Button 컨트롤도 현재 우리의 ASP.NET 코드상에서는 <asp:Button> 컨트롤이지만, 이 코드가 컴파일되고 실행되서 결과물이 만들어질 때에 이 코드는 <input type="submit"> 태그로 바뀌게 된다. 다음은 이 Button 컨트롤의 코드가 클라이언트에게 전달될 경우에 생성되는 결과 HTML 이다.

<input type="submit" name="btnSubmit" value="Click!!!" id="btnSubmit" />

자. 이제 ASP.NET 페이지가 어떻게 구성되어져 있는지 간략히 알아보았다. 자. 그럼 이제 좀 더 구체적으로 알아보자. 페이지가 실행될 경우, 그리고 페이지에서 버튼이 클릭되는 이벤트가 발생할 경우 어떤 일들이 추가적으로 일어나는지를 말이다.

     클라이언트측의 버튼 클릭!! 서버측의 함수가 반응???

버튼이 클릭되었을 경우에 위의 설명대로라면 btnSubmit_OnClick 이벤트 함수가 처리되겠지만, 잘 보면 버튼을 클릭하는 것은 클라이언트 측의 행동이고, btnSubmit_OnClick 함수는 서버측에 있다. 클라이언트측에서 서버측의 함수를 호출할 방법은 사실상 없다. HTTP 라는 프로토콜은 연결이 유지되는 환경이 아니기 때문이다. 사용자가 결과물을 브라우저로 확인하고 있을 당시에 서버와의 연결은 이미 끊긴 상태이고, 인터넷은 잠시 끊겨져 있는 상태라는 것을 기억하라. 그것이 웹이라는 환경의 특성이다. 그럼에도, 이와 같은 방법이 가능한 것은 클라이언트가 버튼을 클릭할 경우에 무조건 폼이 서버로 서브밋되기 때문이다. 폼의 모든 데이터들이 서브밋이 되어지며, 동시에 현재 서버측의 btnSubmit_OnClick 라는 이벤트 함수를 호출하였다라는 정보도 같이 서버로 전송되어진다. 서버에서는 현재의 aspx 페이지를 다시금 생성하면서 추가적으로 btnSubmit_OnClick 라는 함수도 실행한다. 대략 이러한 식으로 페이지가 동작한다는 사실을 잠시 알아두기 바란다. 곧 구체적인 실행의 흐름과정을 알아보겠지만, 먼저 살며시 알아두는 것도 이해에 도움이 되리라 생각한다.

이제 Start.aspx 페이지의 첫 페이지가 로드되고, 사용자가 버튼을 클릭할 경우를 알아보자. 위의 참고에서 이야기했듯이 버튼이 클릭될 경우에는 무조건 웹 폼은 서버로 서브밋을 시작한다. 즉, 포스트백이 발생한다는 것이다. 별다른 제약을 두지 않는 한 기본적으로 웹 폼내에 존재하는 모든 버튼 서버 컨트롤들은 클릭시 웹 폼을 포스트백하게 된다. 단, 자신의 페이지로 폼을 서브밋하면서(즉, 포스트백) 현재 btnSubmit_OnClick 이라는 이벤트도 발생하였다라는 정보를 같이 넘긴다.

aspx 페이지는 사용자가 페이지를 요청하던, 버튼을 클릭하여 포스트백이 일어나던 매번 페이지의 요청에 따라 동적으로 결과물을 처음부터 다시 생성하기 시작한다. 버튼이 클릭되지 않은 첫 페이지의 로드시에는 btnSubmit_OnClick 이라는 함수는 실행되지 않은 채 결과 페이지가 생성되게 되지만, 버튼이 클릭되어 btnSubmit_OnClick 이라는 함수를 요청하게 되면, 결과 페이지가 생성되어지는 와중에 btnSubmit_OnClick 이라는 함수도 실행되어지게 되고, 그 결과를 포함한 결과물이 생성되어진다.

     잠시만!!

지금은 btnSubmit_OnClick라는 함수의 인자로 왜 (Object sender, EventArgs e)라는 것을 사용하고 있는지에 대해서는 잠시 무시하도록 하자. 곧 그 부분에 대한 자세한 설명이 뒤따를 것이다.

   void btnSubmit_OnClick(Object sender, EventArgs e)
    {
        lblMsg.Text = "클릭!!!";
    }

위처럼 btnSubmit_OnClick 이라는 함수안의 코드는 서버측에서 실행되어지면 서버측에서 프로그래밍적으로 Label 서버 컨트롤로 접근하여 lblMsg 라는 컨트롤의 Text 값을 "클릭!!!" 으로 설정하게 된다. 그리고, 그 결과에 의한 HTML을 다시금 동적으로 구성하게 된다. 해서, 버튼을 클릭했을 경우에는 결과화면으로써 다음과 같이 Label 컨트롤에 "클릭!!!" 이라는 출력문자가 포함된 것을 보게 되는 것이다.

 

다시 한번 강조하는 데, <Script runat="server"> 라는 서버측 스크립트 블럭은 클라이언트는 전혀 볼 수 없는 구역이며, 오로지 서버측 개발자만이 볼 수 있는 구역이다. 또한, ASP.NET 에 의해 해석되고, 실행되는 구역이다. 지금 브라우저에 의해 결과화면을 보고 있다면, 그 결과화면에서 HTML 소스를 보도록 하자. 클라이언트에게 전송된 결과 HTML 에서는 서버측의 코드가 어떻게 구성되어져 있는지 알 수 있을만한 코드는 단 한줄도 없을 것이다.

그렇다. 머리가 아프다. 만일, 여러분이 이전에 웹 프로그래밍을 접해본 적이 없다면, 이것은 더더욱 여러분의 머리를 죄어올 것이다. 게다가 만일 여러분이 이전에 C/S 프로그래밍에 익숙해져 있는 개발자라면 어쩌면 처음 ASP.NET을 접하는 이들보다 더욱 머리가 아플 수도 있다. 그래서 습관이라는 것이 무서운 것이다.

더이상 여러분의 머리를 아프게 하지 말자. 그런 의미에서 이 전체적인 흐름을 다시 한번 친절한 그림과 함께 일단 정리해 보도록 하자. 이것을 이해하는 것은 매우 중요하다. 물론, 이미 ASP 를 중급정도 다룰 수 있는 독자가 있다면 그리 어렵지 않게 받아들여질 수 있는 이야기일 것이지만, 그들은 더 잘 알고 있을 것이다. 이러한 기본적인 개념을 이해하는 것이 얼마나 중요한 것인지 말이다.

다음 그림을 보자. 이것은 우리가 작성한 Start.aspx 의 원본 소스이다.

- 이 소스는 서버에 존재하고 있는 코드이며, 사용자는 이 코드를 볼 수가 없다.
- <asp:Label> 이라는 컨트롤을 서버의 처리에 의해 <span> 태그로 둔갑하게 된다.
- <asp:Button> 이라는 컨트롤은 서버의 처리에 의해 <input type="submit"> 로 바뀌게 된다.

그렇게 바뀌어서 다음과 같은 HTML이 만들어지고, 이 HTML이 클라이언트의 브라우저에게 넘겨진다.

이 코드는 생성된 클라이언트 코드이다. 폼 태그쪽을 보면 action (즉, 폼이 서브밋될 서버 페이지명)이 자기 자신 페이지로 지정되어져 있고, 폼의 아이디도 서버에 의해 동적으로 부여되어져 있다.

그리고, hidden 컨트롤이 하나 있는데, 그 이름은 _VIEWSTATE 이고, 값으로는 알아보기 힘든 값들이 들어있다. 이것은 서버측에서 여러 필요한 정보들을 base64 방식으로 인코딩하여 숨겨두는 방법이라고만 알아두자. 나중에 자세히 배우게 될 것이다.

물론, 여러분이 브라우저로 보게 되는 결과는 위의 코드가 아닌 다음과 같은 화면일 것이다. 하지만, 이 화면이 바로 HTML로는 위와 같다는 사실은 알고 있을 것이라 생각한다.

서버측의 코드와 클라이언트측의 결과를 비교해 보니 조금은 이해가 쉽다. 그렇지 않은가? 만일, 이해가 안가는 부분이 있다면 가장 좋은 방법은 일단은 그냥 외우는 방법이다. 프로그래밍은 많은 예제와 실습을 통해서 여러분의 것이 되어지기에, 지금의 설명이 피부에 와닿지 않을 수 있다. 그럴지라도 조급하지 말자. 곧 여러분의 것이 될 것이다.

자. 이 상태에서 클라이언트는 버튼을 클릭한다. 버튼을 클릭하는 순간, 폼은 서브밋되고, Start.aspx 는 서버로 페이지를 다시 구성해달라는 재요청을 하게 된다. 그 요청에 의해 클라이언트가 받아보게 되는 결과는 다음과 같은 HTML 이다.

_VIEWSTATE 라는 컨트롤의 값들이 많이 늘어난 것을 볼 수 있으며, <span> 태그 안에는 "클릭!!!" 이라는 문자열이 추가되어져 있다. 버튼이 클릭되어, 서버에서 추가적으로 실행된 함수(btnSubmit_OnClick)의 결과만이 추가되어진 것이다. _VIEWSTATE의 값이 늘어난 이유에 대해서는 곧 알아보게 될 것이다. 그리고,다음 그림은 이 HTML가 사용자 브라우저에 보여질 경우의 화면이다.

또한, 다음 그림을 통해서 클라이언트와 서버간의 흐름을 다시 한번 정리해 보자.



그림이 조금 작아서 보기에는 그렇겠지만, 이것은 간단하게나마 전체적인 흐름을 보여주고 있는 그림이다. 사실, 보여지는 그림이 ASP.NET이 동작하는 방식이라고 이야기하기에는 많은 부분을 생략하고 있긴 하지만, 처음 예제를 이해하는 것이기에 일단은 이정도로 이해해도 그리 나쁘지 않아보인다. 구체적인 ASP.NET의 처리방식, 이벤트 로딩순서등에 대해서는 계속해서 보강해 가며 알아볼 것이다.

이제 어느 정도 정리가 되어진 듯 하다. 부디 이것이 필자만의 생각은 아니기를 바라는 마음으로 btnSubmit_OnClick 이라는 이벤트 함수에 대해서 조금 더 알아보도록 하자.

서버 사이드 스크립트 블럭내에서는 void btnSubmit_OnClick(Object sender, EventArgs e)라는 함수가 자리를 차지하고 있다. 왜 이런 이름으로 함수를 만들어야 하는지, 함수에서 사용하는 두개의 인자는 무엇인지 알지 못한 채 그렇게 사용하고 있다. 미리 언급하자면 반드시 함수의 인자로는 첫번째 Object 라는 타입의 인자를 사용해야 하며, 두번째 인자로는 EventArgs 타입의 인자를 사용해야 한다.

함수의 시작은 void 로 시작하고 있는데, 이 의미는 이 함수에 의해 리턴되는 값은 아무 것도 없다는 의미이다. 리턴할 값이 없는, 자신에게 주어진 처리만 하고 작업을 마무리하는 함수는 이처럼 앞에 반드시 void 라는 키워드를 사용해 주어야 한다. 만일, 작업 후 어떤 Integer 값을 리턴할 함수가 있다면 void 대신 int 를 사용해 주어야 하고, 어떤 문자열 값을 리턴할 함수가 있다면 void 대신 string을 사용해 주어야 한다.

btnSubmit_OnClick 이라는 함수의 이름은 임의적이다. 즉, 우리 마음대로 지정할 수 있다는 것이다. 이 함수는 코드 중에 버튼 컨트롤이 클릭할 경우에 호출되게 할 함수이기에 이름을 btnSubmit_OnClick 라고 주었다. btnSubmit은 버튼 컨트롤의 아이디로 지정된 값이고, OnClick 이벤트가 발생시 처리될 함수라는 의미로 말이다.

사실, 이러한 함수의 이름은 관례적으로 '컨트롤명_이벤트명'으로 주고는 한다. 반드시 그렇게 할 이유는 없지만 많은 개발자들이 그런 방식으로 명명하고는 하기에, 가급적 따르는 것이 좋을 것이다. 경험에 기반한 이러한 작은 규칙들은 따르는 것은 눈에 보이지 않는 잇점이 있는 편이고, 적어도 손해는 주지 않는다.

그 다음 함수에서 사용하는 인자들을 보도록 하자. (Object sender, EventArgs e) 라고 되어져 있다. 이것은 지켜야 할 룰이다. 첫번째 인자로는 반드시 Object 형의 인자를 지정해 주어야 하고, 두번째 인자로는 반드시 EventArgs 라는 형의 인자를 지정해 주어야 한다.  이 인자들은 일괄적으로 모든 이벤트들에서 사용되어진다. 누가 그러한 인자값을 알려주는가? ASP.NET이 그러한 것을 우리에게 넘겨준다. 개체 변수의 이름은 여러분이 지정하기 나름이다. (Object sender, EventArgs e) 라는 부분을 다음처럼 바꾸어도 아무런 문제는 없다

(Object myobject, EventArgs myEvent)

변수의 타입만 제대로 지정해 주면 된다. 첫번째 인자인 Object로는 현재 이벤트를 발생시킨 그 객체 자체에 대한 참조가 넘어온다. 두번째 인자로는 이벤트 데이터를 가지고 있는 개체 클래스가 넘어온다. 중요한 것은 첫번째 인자로 우리가 이벤트에 사용한 컨트롤은 Button 인데, 인자의 데이터형은 Button이 아니라 Object 형이라는 사실이다. 나중에 이야기하겠지만 이것은 모든 컨트롤들에게 범용적으로 사용하기 위해서 Object 로 넘겨져 오는 것이다. 만일, Object 라는 통일된 데이터 타입을 사용하지 않는다면, 버튼의 이벤트의 경우에는 (Object sender, EventArgs e) 라는 것이

(Button sender, EventArgs e)

이 되어야 할 것이고, 텍스트박스의 경우는

(TextBox sender, EventArgs e)

가 되어야 할 것이다. 이것은 그다지 좋은 선택이 아니다. 그렇기에 ASP.NET 은 모든 컨트롤들을 Object 라는 형으로 개체 참조를 형변환(Casting)하여 첫번째 인자로 넘겨주는 것이다. (Object sender, EventArgs e) 라고 말이다.

개발자인 여러분들은 첫번째 인자로 Object 가 넘어온다고 해도 실은 이 이벤트를 일으킨 컨트롤이 누구인지 알고 있다. 그러므로, 함수 내의 소스에서 이 Object를 Button으로 다시금 변환해서 사용할 수 있다.

그리고, 사실 이렇게 Object 형으로 형변환 가능한 것은 Object 형이 모든 컨트롤들의 원조 클래스이기 때문이다.  구체적인 내용들에 대해서는 나중에 더욱 자세히 알아볼 것이다. 지금은 가벼운 이야기를 해야하는 시간인데, 조금은 깊게 들어왔다. 죄송하게 생각한다. 좋다. 일단은 여기까지만 기억하자. 이해가 전혀 가지 않는다고 해도 괜찮다. 나중에 여러가지 예제들을 통해서 여러분은 충분히 이해하게 될 것이다. 알려는 마음만 가진다면 어려울 것은 전혀 없다. 다시 한번 이야기하지만, 여러분은 아직 여러분의 두뇌를 과소평가하고 있다.

    두번째 인자가 언제나 EventArgs 타입이라굽쇼? 안 그런 것도 있던데??

물론, 이벤트를 발생시킨 컨트롤에 따라 두번째 인자의 형은 바뀔 수도 있다. 그렇다면 때오가 이야기한 일괄적으로 (Object sender, EventArgs e) 가 사용된다는 말은 틀린 말일 것이다. 하지만, 컨트롤에 따라 틀려지는 두번째 이벤트 형의 부모 클래스는 사실 EventArgs 이다. 그렇기에 위에서는 넓은 의미에서 일괄적으로 (Object sender, EventArgs e) 와 같은 인자가 사용된다고 이야기한 것이다.

인자부분을 정리하자면, 무조건 일반적인 경우는 (Object sender, EventArgs e) 를 사용한다고 기억해 두자. 이것은 ASP.NET에 의해 어느정도는 고정되어져 있다고 생각하자. (하지만, 기쁘게도 여러분은 이러한 인자를 외울 필요가 없다. 이후에 VS.NET 을 사용해보면 알겠지만, 모든 이러한 코드들은 VS.NET이 자동으로 우리를 대신하여 만들어 준다.)

자. 이제 함수 내부를 이야기할 시간이다. 함수의 안에는 다음과 같은 한줄짜리 코드가 존재한다.

lblMsg.Text = "클릭!!!";

이것은 lblMsg 라는 id를 가진 서버 컨트롤(코드상의 Label 컨트롤)의 Text 속성의 값을 "클릭!!!" 이라는 값으로 설정하라는 코드이다. 그리고, 함수는 닫힌다. 그래서, 여러분은 결과화면에서 "클릭!!!" 이라는 값이 출력되는 것을 볼 수 있었던 것이다.

자. 이 시점. 여러분은 한가지 의문이 들 수 있다. 버튼이 클릭될 경우, 폼은 자기 자신 페이지로 전송이 되고, 버튼이 클릭하여 발생한 이벤트인 btnSubmit_OnClick 이라는 함수가 실행되어진다는 것은 알았는데 그런데, 만일 폼을 자기 자신 페이지가 아닌 다른 페이지로 전송한다면? 즉, 폼 태그 부분을 다음처럼 수정하여 action 을 다른 페이지로 지정한다면?

<form runat="server" action="otherPage.aspx">

이렇다면, 버튼이 클릭될 경우, 폼은 otherPage.aspx 로 전송되어질 것이고, otherPage.aspx 페이지의 btnSubmit_OnClick 함수가 실행되어지는 것인가? 만일, otherPage.aspx 페이지에 btnSubmit_OnClick 이라는 함수가 없다면? 이렇게 되면 상당히 많은 문제가 발생한다. 이것은 난감하지 않을 수 없다.

ASP.NET은 이러한 부분도 해결하고 있는데, 그것은 개발자가 폼의 action을 바꾸어도 그 내용은 무시해버리고, 자기 자신 페이지로 포스트백 하도록 한다는 사실이다. 그래서, 이전에 필자는 ASP.NET의 흐름은 다음 그림과 같다고 강조했던 것이다.

기억하자. 웹 폼의 action을 개발자가 바꾸어도 ASP.NET은 그 경로를 자기자신 페이지로 강제한다는 것을 말이다.

호오.. 매우 긴 첫번째 예제였다. 그 어떠한 책도 시작하는 예제, 일명 "Hello" 예제를 가지고 이렇게 길게 끈 적은 없었을 것이다. 필자가 이렇게 많은 지면을 할애하여 이 부분을 설명한 데에는 그만한 이유가 있다. 이 작은 예제에 대한 이해가 앞으로의 만날 수 많은 예제들을 이해하는 데에 큰 기반이 되어줄 것이기 때문이다. 기능적인 이해 뿐 아니라, 코드에 의한 기능을 넘어선 뒷단의 논리 흐름의 이해까지도 고려하며 프로그래밍을 할 수 있게 할 것이기 때문이다.

좋다. 모든 것을 이해했던, 일부만을 이해했던, 아예 이해를 하지 못했던 어쨋든 여러분의 머리속에는 어느 정도의 기반이 준비가 되어져 있다. 이제, 쉬운 길을 보여주도록 하겠다.

같은 예제를 VS.NET(Visual Studio.NET)으로 작성하는 예를 말이다. 여러분이 관심을 가져야 할 것은 코드가 아니라 흐름임을 기억하고, Start.aspx 를 VS.NET으로 만들어 보자.


출처 : Taeyo.pe.kr
2007/08/06 11:28 2007/08/06 11:28