Posted
Filed under .NET/ASP.NET

Code Behind

사실 이번 강좌는 이전 강좌에서 약속한대로 Start.aspx 를 VS.NET으로 만들어 보는 강좌이고자 했다. 하지만, 몇몇가지 문제가 있었는데 그중에 하나는 VS.NET은 웹 폼 페이지에 기본적으로 코드 비하인드라는 기법을 사용한다는 것이다. 즉, 여러분이 Start.aspx 를 VS.NET으로 만들기 위해서는 반드시 코드 비하인드라는 것이 어떤 것인지 알고 있어야 하며, 그것을 모를경우 전반적인 이해가 어려울 수 있다는 것이다

해서, 이번 강좌부터는 갑작스럽긴 하지만, 그리고 그리 쉬운 내용은 아니지만 코드 비하인드 기술에 대해서 먼저 심도있게 알아보고자 한다

혹시나 여러분이 ASP를 해본 적이 있다면 그 경험에 빗대어 ASP.NET 을 매우 만만하게 보고 있을 수도 있겠다. 하지만, 사실 ASP.NET 은 그리 만만하지 않다. 이제 여러분은 ASP.NET이 ASP의 업그레이드 버전이 아닌 완전히 새로운 기술이라는 것을 실감하게 될 것이다.

그 시작은 바로 코드 비하인드이다.

ASP.NET 페이지의 구성은 기본적으로 크게 UI(User Interface)와 Logic 부분으로 나뉘어진다. 이중에 UI를 담당하는 것이 HTML 과 여러 서버 컨트롤들(이도 사실상 결과로써는 HTML이다)이며, Logic을 담당하는 것은 여러 서버 사이드 측의 함수들이 될 것이다. ASP 에서는 이 두 부분이 하나의 페이지에 모두 들어있어야만 하는 구조였고, ASP.NET 도 그러한 구조를 지원하지만, ASP.NET은 추가적인 코드 비하인드라는 구조를 제공해 준다.

코드 비하인드라는 것은 말 그대로 코드를 뒷면에 숨겨두겠다는 이야기이다. 즉, 컨텐트 페이지와 프로그래밍 코드 페이지를 따로 두겠다는 의미이며, 런타임 시에 같이 어우러져 동작하게 하겠다는 의미이다. 이것은 ASP 의 Include 파일과는 자못 틀린 개념이다. 코드 비하인드를 생각하며 절대로 Include를 떠올리지 말기 바란다. 그것은 개념의 혼란만을 가중시킬 뿐이다.

그렇다면, 이전 예제였던 Start.aspx 페이지의 소스를 다시금 한번 살펴보자. 그 소스는 다음 그림과 같이 서버 사이드 프로그래밍 코드와 UI 컨텐트 코드가 뒤섞여 있는 구조였다.

코드 비하인드라는 구조는 위와 같은 혼합적인 코드의 구조를 다음 그림과 같이 분리시켜서, UI 렌더용 HTML 페이지와 ASP.NET 코드 페이지로 구성하는 것을 의미한다.

그림의 경우에서는 분리된 코드 비하인드 파일의 이름을 Start.aspx.cs 라고 주었는데, 이것은 VS.NET 이 명명하는 기준을 따른 것이고, 사실상은 여러분이 주고 싶은 어떠한 이름이라도 사용할 수 있다. 단지, 이 코드 비하인드 파일은 반드시 .NET 언어의 클래스로 구성되어야 하기에, 그 확장자는 C#의 .cs 이거나 VB.NET의 .vb 등이어야만 하며, Page 라는 .NET 클래스로부터 상속을 받은 클래스로써 구성이 되어야만 한다. 구체적인 이야기는 곧 나올 것이다.

페이지를 이렇게 코드 비하인드로 구성하게 되면, 여러분은 UI와 코드를 완벽하게 분리할 수 있게 되기 때문에 소스를 디버그 하거나, 유지, 보수, 관리할 경우 상당한 이점을 얻을 수 있게 된다.

단, 코드 비하인드로 Logic 부분을 분리시킬 경우, 코드 비하인드 페이지는 여러분이 위의 그림에서 본 모습과는 다르다. 위의 그림은 일종의 예시였을 뿐이다. 코드 비하인드 페이지는 여러 가지 따라주어야 하는 까다로운 조건들을 가지고 있다. 이제부터 그러한 조건들과 규칙들에 대해서 이야기를 해볼까 한다.

이 이야기는 사실상 OOP(개체 지향 프로그래밍)에 대한 지식이 있어야 이해할 수 있는 내용이기는 하다. 전에 말했듯이 ASP.NET은 여러 가지 .NET 의 기술들을 복합적으로 사용하는 기술이며, 그 근간은 여러 .NET 클래스들에 의해 구성되어 있다. ASP.NET 페이지라는 것은 사실상 Page 라고 하는 하나의 .NET 클래스를 기본으로 한다. 그렇기에 이제부터 필자가 서술할 이야기는 OOP가 낯 설은 초보 프로그래머들에게 있어서는 매우 복잡하고, 이해하기 어렵게 느껴질 수 있는 이야기이다. 물론, 여러분이 글을 읽는 즉시 필자의 이야기를 이해할 것이라고는 생각하지는 않는다. 하지만, 어렵다고 하더라도 일단은 그렇다고 받아들이고 읽어나가자. 지금은 이해하기 어려울 수 있지만, 이 책을 마무리할 즈음에는 어느 정도 이해할 수 있을 것이며, 개별적인 .NET 언어에 대한 학습을 통해 이 지식을 다져나갈 수 있을 것이라 믿는다.

ASP.NET 페이지를 위해 .NET 은 특별한 클래스를 하나 준비해 두었는데, 그 클래스의 이름은 Page 이며, 모든 ASP.NET 코드 비하인드 페이지는 Page 라는 .NET 의 클래스로부터 상속된 하나의 클래스로 제작해야 한다. 그러므로, 하나의 aspx 페이지당 하나의 코드 비하인드 클래스가 필요하게 된다. 예를 들자면, 다음 그림은 각각의 aspx 페이지마다 각각의 코드 비하인드 페이지가 연결되어 있는 VS.NET의 모습을 나타내고 있다. (C# 언어를 사용하였기에 비하인드 파일의 확장자가 .cs 인 것을 알 수 있다.)

하지만, 코드 비하인드 파일이 언제나 하나의 aspx 당 하나가 필요한 것은 아니다. 하나의 코드 비하인드 파일은 여러 개의 aspx 페이지에서 공유하여 사용할 수도 있다. 잠시 후 관련 예제를 보게 될 것이다.

우선, 코드 비하인드 페이지는 다음과 같은 페이지의 골격을 가져야만 한다. 이것은 C# 을 사용했기 때문에 이렇게 작성된 것이며, 만일 VB.NET 을 사용한 경우는 조금 다르게 구성한다.(완전한 소스는 VB.NET으로 작성한 코드도 보여주도록 하겠다)

단, C#으로 작성했던 VB.NET으로 작성했던, 그 어떤 .NET 언어로 작성을 했던지 간에 현재의 클래스의 부모 클래스로는 반드시 System.Web.UI.Page 가 지정되어야 한다

using System;

public class Start : System.Web.UI.Page
{
}

클래스의 이름은 일반적으로 aspx 페이지의 파일명을 기준으로 한다. 클래스 이름은 현재의 웹 어플리케이션 내에서 절대적으로 고유한 이름을 사용해야만 하는데, 파일명 또한 그러하기 때문에, 주로 파일명을 클래스 명으로 사용하는 것이다.

소스를 보면 소스의 제일 첫 줄에는 using System; 이라는 문장이 있는 것을 볼 수가 있다. 이는 System 이라는 네임스페이스에 존재하는 클래스들을 사용하도록 하겠다는 의미라고 볼 수 있다.

System 이라는 네임스페이스 안에는 여러 가지 기본적인 .NET 클래스들이 존재하고 있는데, array, Boolean, byte, char, DateTime, int, string 등등의 기본적인 데이터 타입들이 모두 제공 된다. 대부분의 코드에서는 이러한 데이터 형들을 매우 자주 사용하게 되기에, 이 네임스페이스를 소스 코드에 추가하는 것은 거의 필수적이다.

만일, 여러분이 System이라는 네임스페이스를 using 키워드를 통해서 코드에 추가하지 않으면, 코드내에서 string 을 사용해야 할 경우, System.String 과 같이 완전한 이름으로 사용해야만 한다. 이러한 불편함을 덜어주기 위해서 System 이라는 네임스페이스를 using를 통해서 첨부한 것이다.

코드의 두 번째 줄에는 다음과 같은 코드가 있다.

public class Start : System.Web.UI.Page

이것은 System.Web.UI.Page 라는 클래스로부터 상속을 받는 Start 라는 클래스를 우리가 작성하겠다는 의미를 가지는 부분인데, 여기서 .NET 이 ASP.NET을 위해 특별히 준비해 둔 Page 클래스라는 것이 바로 System.Web.UI.Page임을 알 수 있다.

System.Web.UI.Page 라는 부분을 유심히 보면, Page 라는 클래스는 System.Web.UI 라는 네임스페이스 안에 들어있는 하나의 클래스라고도 볼 수 있다. 그렇다. System.Web.UI는 하나의 네임스페이스이며, page 는 그 네임스페이스 안에 들어있는 하나의 클래스인 것이다.

필독 : 네임스페이스(namespace) 란 ?

여기서 네임스페이스(namespace)라는 단어가 여러 차례 등장했다. 네임스페이스라는 것은 무엇일까? 네임스페이스라는 것은 .NET 에서 관련된 여러 클래스들을 그룹을 지어 묶어 놓은 일종의 논리적인 그룹핑이다. 관련이 있는 클래스들을 하나의 이름으로 묶어서 관리하는 구조인 것이다. 예를 들어서, .NET 에서 제공하는 모든 클래스들은 System 이라는 가장 큰 단위로 모두 묶여있다. 그리고, 그 클래스들 중에서 Web과 연관이 있는 클래스는 System의 하위로 Web 이라는 네임스페이스를 두어 그 곳에 모두 모아 두었다. Web 내에서도 UI 와 관계가 있는 클래스들은 다시 세분화하여 UI 라는 네임스페이스에 두도록 했다. 대표적인 UI 관련 클래스로는 이미 위에서 보았듯이 Page 라는 것이 있다. 해서, 이 Page 라는 클래스를 완전하게 나타낸다면 System.Web.UI.Page 라고 말할 수가 있는 것이다. .(점)은 "..의 밑의” 라는 의미로 생각하면 되겠다. 중요한 것은 이러한 네임스페이스 구조에서는 자신의 네임스페이스 내에 직접적으로 존재하지 않는 클래스는 인식하지 못한다는 것이다. 무슨 말인고 하니, Page 라는 클래스는 System.Web.UI 라는 네임스페이스에 존재하고 있지, System.Web 이라는 네임스페이스에 존재하고 있는 것은 아니라는 이야기이다. 마치 System.Web 이 System.Web.UI를 포함하고 있기에 Page 클래스라는 것이 System.Web 안에도 속할 것 같지만, 그렇지 않다는 것이다. 자신의 네임스페이스에 직접적으로 존재하는 클래스만이 해당 네임스페이스를 통해 접근할 수 있다.

이러한 네임스페이스라는 논리적인 구분은 두 가지의 장점을 제공하는데, 하나는 관련된 타입들을 논리적으로 그룹핑 한다는 것이고, 또 다른 하나는 같은 이름을 가진 클래스들이 충돌할 가능성을 줄여준다는 것이다. .NET 에서 제공되는 클래스들 외에 누구라도 위와 같은 식으로 네임스페이스를 구성하고, 클래스들을 만들어서 위치시킬 수 있다.(사실 ASP.NET 페이지를 코드 비하인드로 구성할 경우 페이지 하나, 하나가 모두 클래스라고 볼 수 있다) 그럴 경우, 잘 정의된 네임스페이스는 다른 클래스들과 이름이 충돌될 가능성이 매우 줄여줄 것이다. 일반적으로 각 회사에서 만들어내는 솔루션의 최상위 네임스페이스로는 전세계적으로 유일한 자사의 도메인 명을 사용하고는 한다.(예 : inbrein.com)

네임스페이스는 어떻게 보면 탐색기의 폴더와 아주 흡사한 구조이다. 단지, 탐색기는 논리적인 구조가 아니라 물리적인 구조라는 점이 차이이다. 논리적으로 구조적인 면만을 보았을 경우에 탐색기와 유사하다고 생각하자. 사실상 Page 라는 클래스는 논리적으로는 System.Web.UI 안에 들어있지만, 실제 물리적으로는 System.Web.dll 라는 어셈블리 파일 안에 들어있다.

그렇다면(= 여러분이 위의 "필독 : 네임스페이스란?" 이라는 부분도 모두 정독하였다면) 우리의 기본 비하인드 코드를 다음과 같이 바꿀 수도 있다는 이야기인가?

using System;
using System.Web.UI;

public class Start : Page
{
}

물론이다. Page 라는 클래스는 System.Web.UI 란 네임스페이스에 포함되어 있으니, System.Web.UI 네임스페이스를 using 키워드를 통해서 추가한다면 이후 코드 내에서는 Page 라는 클래스 명을 짧게 직접 사용할 수가 있다.

되었다. 여러분은 이제 코드 비하인드 페이지가 갖추어야 할 기본적인 사항을 이해하였다. 그렇다면, 기존의 Start.aspx 페이지의 Logic 부분을 코드 비하인드로 작성해 보자. 여러분의 예상대로 코드 비하인드 페이지는 다음처럼 구성되어야 한다.

using System;
using System.Web.UI;

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

기존 Start.aspx 페이지의 서버 사이드 스크립트 블록내의 함수가 그대로 class 내부로 들어와 있다. 단지, 함수의 앞에 public 이라는 키워드가 붙어있는데, 코드 비하인드로 구성할 경우 이것은 반드시 붙여주어야 한다. 기존에 코드 비하인드 형태가 아니었던 경우에는 같은 페이지 내에서 컨트롤이 함수를 호출하는 것이기에 public 이라는 키워드가 필요치 않았지만, 이제는 페이지가 분리되었기에 별도의 파일에서 이 파일의 어떠한 함수를 실행하기 위해서는 반드시 public 이라는 키워드를 통해서 누구나 함수에 접근할 수 있도록 해주어야 한다.

좋다. 여기까지의 생각은 아주 좋았다. 그러나, 한가지가 더 필요하다. 그것은 btnSubmit_OnClick 이라는 이벤트 함수 내에서 하고 있는 작업 때문이다. 우리의 함수에서는 lblMsg 라는 Label 서버 컨트롤에 접근하여 그 Text 값을 변경하는 작업을 하고 있는데, 그 이야기는 이 함수 내에서 aspx 페이지의 ASP.NET Label 컨트롤에 접근할 수 있어야 한다는 이야기이다.

같은 페이지로 구성되었던 이전 Start.aspx 의 경우라면 이 또한 문제가 안 되는 부분이었다. 다시 말하지만, 파일이 분리되지 않고, 하나의 페이지 내에 함수, 개체가 모두 존재하였기에 바로, 바로 접근할 수가 있었던 것이다. 하지만, 지금 처럼 코드 비하인드로 구성되는 경우에는, 비하인드 코드 내에서 접근이 필요한 컨트롤을 선언해 주어야 한다. 그것도 웹 폼에 존재하는 Label 컨트롤의 id 와 같은 이름의 변수로써 말이다.

해서, 우리는 다음과 같은 코드를 추가할 필요가 있다.(반드시 그래야만 한다)

System.Web.UI.WebControls.Label lblMsg;

뭔가 조금은 길다고 느껴진다. 그도 그럴 것이 C# 에서는 변수를 선언할 경우 반드시 그 변수의 Type를 먼저 알려주고 선언해야 하는 규칙을 가지고 있기 때문이다. 이라는 ASP.NET 웹 폼 컨트롤은 사실상 .NET 에서 System.Web.UI.WebControls 라는 네임스페이스의 Label 이라는 이름의 클래스로써 정의가 되어져 있다. 고로, 이 Label 컨트롤 변수를 선언하기 위해서는 위처럼 길게 그 모든 정보를 나열해 주어야 하는 것이다.

레벨 업이 된 여러분은 지금 어쩌면 이렇게 말하고 싶을 것이다.

"그렇다면, using을 사용해서 System.Web.UI.WebControls을 페이지에 추가하면 위의 코드도 Label lblMsg;" 라고 줄일 수 있지 않은가? 필자?”

그렇다. 질문과 답변 사이에 정답이 있었다. 그 말이 옳다. 그렇다면, 우리의 코드 비하인드 클래스의 전체 소스를 한번 확인해 보도록 하자. 다음처럼 구성하였다면 일단은 좋은 구성이다.

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

public class Start : Page
{
    public Label lblMsg;

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

사실 약간의 아쉬움은 남지만, 부족한 부분은 곧 채워나갈 것이다.

그리고, 다음의 코드는 VB.NET 으로 이 클래스를 작성한 소스이다.

Imports System
Imports System.Web.UI
Imports System.Web.UI.WebControls

Public Class Start
        Inherits Page

    public lblMsg as Label

    Sub btnSubmit_OnClick(ByVal sender As Object, ByVal e As EventArgs)
        lblMsg.Text = "클릭!!!"
    End Sub

End Class

C# 의 소스와 VB.NET 의 소스가 형식상의 차이만 조금 보일 뿐 많이 흡사하다는 것을 알 수 있을 것이다. 그렇다. .NET 언어는 매우 재미있다. 모든 .NET 언어들이 VB.NET 과 C++ 그리고 Java의 장점을 섞어놓은 구성을 띄고 있기에 더욱 그러한 것 같다.

코드를 다 작성하였으면, 이 파일을 Start.cs 라는 이름으로 TaeyoBook 이라는 가상 디렉터리 안에 놓도록 하자. 물리적인 전체 경로는 C:\Inetpub\wwwroot\TaeyoBook\start.cs 가 될 것이다.

참고 : C# 클래스는 대, 소 문자를 구분한다.

그렇기에 위의 Start.cs 내의 코드는 반드시 대, 소문자를 잘 따져서 코딩을 해 주어야 한다. 대 소문자중에 틀린 것이 있을 경우에는 이후 결과 화면이 제대로 나오지 않고 에러가 날 수 있다.

자. 이제 코드 비하인드 페이지는 만들어 두었다. 이제는 이 비하인드 페이지를 사용하는 UI 페이지를 꾸밀 시간이다. Start2.aspx 라는 이름의 페이지를 역시나 메모장으로 작성해 보자.

<%@ Page language="c#" Inherits="Start" Src="Start.cs" %>
<HTML>
    <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>

코드를 다 작성하였으면, 이 파일을 Start2.aspx 라는 이름으로 TaeyoBook 이라는 가상 디렉터리 안에 놓도록 하자. 물리적인 전체 경로는 C:\Inetpub\wwwroot\TaeyoBook\Start2.aspx 이 될 것이다.

이 코드는 기존의 Start.aspx 페이지의 코드와 매우 흡사하다. 단지, Logic 부분인 서버 사이드 스크립트가 사라졌으며, @Page 지시자 구역 내에 다음과 같은 2 개의 속성이 추가되어 있는 것을 볼 수 있다.

Inherits="Start" Src="Start.cs"

이 두 개의 속성의 역할이 바로 현재의 UI 페이지에게 자신 페이지와 연결된 코드 비하인드 페이지는 어떤 것인지, 그리고, 어떠한 클래스로부터 상속을 받아 페이지를 꾸밀 것인지를 지정하는 것이다.

Src 라는 속성은 말 그대로, 현재의 UI의 페이지와 연결될 코드 비하인드 페이지의 명이 무엇인지를 지정하는 속성이다. 우리의 경우는 Start.cs 라고 주었다. 만일, 여러분이 VB.NET을 선호하여 Start.vb 를 만들어 두었다면 그것을 지정해도 무관하다.

Inherits 라는 속성은 현재의 ASP.NET 페이지가 Src 로 지정된 클래스 파일 내에서 어떠한 클래스로부터 상속을 받을 것인지를 지정하는 것으로, 우리의 경우는 Start.cs 내에 Start 라는 클래스로 지정하고 있다. 다시금 Start.cs의 소스를 보도록 하자. 다음과 같은 코드를 확인할 수 있다.

public class Start : Page

이러한 클래스의 지정이 왜 반드시 필요할까? 라는 의구심이 들지도 모르겠다. 그도 그럴 것이 어차피 Start.cs 라는 파일 안에는 Start 라는 클래스 하나만이 존재하는데, 굳이 지정하지 않아도 인식하지 않을까라는 생각이 스쳐 지나갈 것이기 때문이다. 그렇다. 그런 생각은 그냥 스쳐 지나가게 내버려 두라.

하나의 cs 클래스 파일 안에 반드시 하나의 클래스 코드만이 존재할 수 있다는 규칙은 없다. 이 말은 Start.cs 안에는 Start 외에도 여러 개의 클래스 들이 놓일 수 있다는 이야기이다. 잠시 후 이와 관계된 이야기를 좀 더 나누어 보자.

조금 늦은 감이 있지만, 이제 브라우저를 열고 Http://localhost/TaeyoBook/Start2.aspx 를 실행하도록 하자. 그리고, 결과화면을 테스트 해보도록 하자. 위쪽이 페이지가 로드 되었을 경우의 화면이고, 아래 쪽이 버튼을 클릭했을 경우의 결과화면이다.

이전의 Start.aspx 의 경우와 결과는 같게 나오는 것을 확인 할 수 있다. 또한, 브라우저에서 마우스 우측 클릭을 하여 HTML 소스를 확인해 보도록 하자. 그 HTML 소스도 이전 Start.aspx 의 경우와 거의 일치한다. 이 말은 클라이언트는 여전히 서버 측에서 어떠한 일이 일어났는지에 대해서는 전혀 알 수 없다는 것이다. 서버의 페이지가 코드 비하인드로 구성이 되어 있는지, 어떤지는 전혀 알 수가 없으며, 오로지 브라우저에 로딩되는 결과화면에 관심이 있다는 것이다. 클라이언트는 단순하다고 기억해두자. 클라이언트는 서버 일에 전혀 참견하지 않으며, 결과만 제대로 로딩되면 그것으로 만족한다고 말이다. 이 사실을 많은 개발자들이 자주 잊는 듯 해서 강조해 보았다.

일단, 한번 정리를 하고 계속 해 보자. 코드 비하인드를 구성하려면, 여러분은 다음 단계를 거쳐서 페이지를 구성해야 한다.순서가 반드시 아래와 같을 필요는 없다.

- 사용할 .NET 언어를 선택한 다음, 코드 비하인드 페이지의 틀을 만든다.
- 코드 비하인드 페이지는 Page 클래스로부터 상속을 받은 형태로 만든다.
- UI 페이지를 만들고, 사용할 개체와 이벤트들을 코드 비하인드 페이지에 코딩한다.
- UI 페이지의 @Page 지시자 구역에 Src 와 Inherits 속성을 추가한다.

출처 : Taeyo.pe.kr

2007/08/23 15:51 2007/08/23 15:51