Resources : Programming ASP.NET(mspress), MSDN
이번 강좌에서는 다중 웹폼을 사용하는 여러가지 방법 중 가장 ASP.NET 스러운 방식을 이야기해볼까 합니다. 사실, 이미 이 방법을 아시는 분들이 많을텐데요. 그래도, 많은 분들이 문의를 해오고 계셔서리 강좌로 올려두기로 했습니다. ^^
혹시나 이미 아시는 분들은 이 강좌를 Skip하실 수 있도록 이번 강좌가 다루는 내용을 간략하게 설명드리자면... 이번 시간에 다룰 내용은 바로 이것입니다!! 두둥~~~
1. 논리적인 폼 구역들을 작성한다.
2. Server.Transfer() 메소드를 사용하여, 실제적인 처리를 다른 aspx 페이지로 전가시킨다.
3. @ Reference 지시문을 사용하여, 이전 다중웹폼 페이지 클래스를 참조하여 프로그래밍을 완성한다.
대략 이와 같습니다.
그렇습니다. 실제로 다중 웹폼을 구성하는 것이 아니라, 논리적으로 폼과 같은 구역들을 가지도록 웹 페이지를 제작하고, 실제 처리는 다른 실행 페이지에서 이루어지도록 그 제어를 전가하는 방법이 되겠다 이겁니다. ^^. 물론, 반드시 다중 웹폼을 처리하고자 하는 경우, 이 방법이 짱!!이다. 라는 의미는 아닙니다. 이러한 방법도 있다는 것이고, 개인적으로는 사용할만한 방법이 아닌가 한다는 것이지요.
모든 상황에 다 적용될 수 있는 가장 좋은 방법을 원한다면... 그러한 것은 없다고 말씀드리고 싶습니다. 상황에 따라 최선의 방법이라는 것은 자못 달라질 수 있는 것이 현실세계이니까요. 그렇지 않나요???
물론, 페이지가 그러한 논리적인 다중 폼의 처리를 꼭 다른 페이지로 전가시켜야만 하는 것은 아닙니다. 그 처리량이 그리 복잡하지 않다면, 그냥 해당 페이지에서 모두 처리해도 문제가 없을 것입니다. 하지만, 처리해야 할 분량이 상당하다면 그 경우에는 어쩌면 코드를 분리하는 것이 나을 수도 있다는 것이지요.
분명, 이 방법이 최선은 아닐런지 모르겠지만, 추천드릴만한 방법일 수 있고, 또는 알아두면 상당히 유용한 방법일 수 있기에 이번 시간에는 이러한 이야기를 나누어보려 합니다.
그럼 시작해 보겠습니다. 일단, 가정을 한번 해봅시다.
즉, 하나의 웹 페이지가 있고, 이 페이지는 논리적으로 3개의 폼을 가져야만 한다고 가정해 봅시다. 이 경우, 각각의 논리적인 폼 안에 들어있는 버튼이 클릭될 경우, 실제적인 처리가 수행되어야 하겠는데요. 물론, 기본적인 방식은... 각각의 버튼 Click 이벤트에서 하고자 하는 처리를 수행하시면 될 것입니다. 하지만, 그 처리해야 할 분량이 상당하다거나 다소 복잡하다면, 그러한 처리를 각기 다른 페이지에서 처리하도록 할 수도 있다는 것입니다. 원본 페이지를 참조하여 처리하는 식으로 말입지요.
일단, 다음 그림을 한번 살펴보도록 할까요?

그림에서 볼 수 있다시피, 가장 좌측에 놓여져있는 페이지는 3개의 논리적인 폼들을 가지고 있습니다. 그리고, 폼 안에 있는 각각의 버튼이 클릭될 경우, 실제적인 처리는 해당 페이지의 코드 비하인드가 아닌, 별도의 실행 페이지에서 처리하도록 하겠다는 것이지요. 이렇게 하기 위해서 필요한 설정은 의외로 간단합니다. 일단, 각 버튼의 Click 이벤트 처리기에서는 단지 Server.Transfer() 메서드를 사용하여, 실제적인 처리를 수행할 페이지로 서버측 분기(Server-side Redirection)을 시켜주기만 하면 됩니다. 이 메서드는 서버측에서 페이지를 이동시킬 뿐만 아니라, 원본 페이지의 제어기를 실제처리 페이지에서 사용할 수 있게도 해줍니다.
조금 어렵게 이야기하면 말입니다. Transfer 메서드를 사용할 경우, 원래 요청의 Context는 유지되고, 새로운 실행 페이지에서 사용할 수 있다는 것입니다. 즉, Context의 Handler 속성이 바뀌지 않기에 원래의 HTTP 요청을 받은 처리기를 계속해서 가리키게 된다는 것이지요. 그런 이유로, 실제적인 처리 페이지는 Handler 속성을 사용해서, 이전 페이지를 참조할 수 있습니다. 이 Handler는 유효한 Page 개체의 인스턴스를 반환하기에, 여러분은 이를 사용하여 이전 다중 웹폼 페이지의 모든 속성들과 메서드들에 접근할 수가 있게 됩니다.
뭐 이러한 복잡한 이야기를 반드시 이해해야만 하는 것은 아닙니다. 일단은 방법만 외우고 있어도 실제로 개발하는 데에는 큰 문제가 없습니다. 지금까지 많은 이야기를 한 것 같은데요... 사실은 한가지 뿐입니다. 그것은 단지...
버튼이 클릭된 경우 Server.Transfer 메서드를 사용해서 실제로 처리할 페이지로 분기시켜라!
인 것이지요.
그렇게 하셨다면, 그 다음 단계는 실제처리할 페이지를 제작하는 것입니다. 이 페이지는 기존처럼 aspx 페이지로 만드시면 되는데요. 이 페이지에서 이전 페이지(다중 웹폼 페이지)를 참조하고자 한다면(참조한다는 것은 그 페이지 안에 있는 모든 속성, 메서드에 접근하겠다는 겁니다. 단, 접근자가 허용하는 한 말입지요) 단지, 페이지에 추가적으로 <%@Reference Page= "이전 페이지 명" %> 이라는 지시문을 추가해주기만 하면 된다는 겁니다. 이전 페이지를 참조할 생각이 없었다면 Server.Transfer를 사용하지도 않았을테니, 사실 이 설정은 필수적입니다. ^^. 그러면, 그 후에는 Context.Handler를 통해서 이전 페이지 클래스를 참조할 수 있게 됩니다.
대충이나마 정리가 된 것 같네요. 그렇죠??? 그렇다면, 이제 완전한 이해를 위해서 실제적인 코드 작성에 들어가 보도록 하겠습니다. 먼저, 논리적으로 다중 폼을 갖는 예제 페이지를 하나 만들어야 하겠지요? 저는 논리적으로 2개의 폼을 가지는 Page를 만들어 보았습니다(다음 그림 참고). 각각의 폼은 <table> 태그로 구분해 보았습니다요. 즉, 클라이언트가 보기에나 폼처럼 보이는 것이지 사실 논리적인 다중 폼은 실제 폼이 아니라 그냥 구역에 불과하다는 것입니다~

코드를 보여드릴 필요까지는 없어보이는데요... 뭐 원하시는 분들이 있으니깐~~ 일단은 올려봅니다. 바로 이 부분이 강좌의 장점이지요.. 책이 아니니깐 코드를 보여드린다고 해서 지면이 증가하지도 않고, 책 값이 비싸지지도 않을테니깐요~~ 히~~~ (참고로, 전 페이지의 명칭을 MultiWebForm.aspx 로 주었습니다)
<%@ Page language="c#" Codebehind="MultiWebForm.aspx.cs" AutoEventWireup="false" Inherits="MSDN.MultiForm.MultiWebForm" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD> <title>MultiWebForm</title> <LINK href="../css/main.css" type="text/css" rel="stylesheet"> </HEAD> <body> <form id="MultiWebForm" method="post" runat="server">
<table cellpadding="5" cellspacing="0" width="300" style="border:1px solid gray"> <tr> <td bgcolor=#6666cc colspan="2" style="color:white"> <STRONG>LOGIN</STRONG> </td> </tr> <tr> <td width="80">사용자 ID</td> <td><asp:textbox runat="server" id="LogUserID" BorderStyle="Solid" BorderWidth="1px" Width="200px" /></td> </tr> <tr> <td>비밀번호</td> <td><asp:textbox runat="server" id="LogPwd" textmode="password" BorderStyle="Solid" BorderWidth="1px" Width="200px" /></td> </tr> <tr> <td colspan="2"> <asp:button runat="server" text="Log in" ID="btnLogin" CssClass="input" /> </td> </tr> </table> | <br>
<table cellpadding="5" cellspacing="0" width="300" style="border:1px solid gray"> <tr> <td bgcolor=#6666cc colspan="2" style="color:white" > <STRONG>Mailing List</STRONG> </td> </tr> <tr> <td width="80">사용자 이름</td> <td><asp:textbox runat="server" id="MailingName" BorderStyle="Solid" BorderWidth="1px" Width="200px" /></td> </tr> <tr> <td>메일주소</td> <td><asp:textbox runat="server" id="MailingAddr" BorderStyle="Solid" BorderWidth="1px" Width="200px" /></td> </tr> <tr> <td colspan="2"> <asp:button runat="server" text="Register" ID="btnRegist" CssClass="input" /> </td> </tr> </table> | </form> </body> </HTML>
|
일단, 소스에서 보이다시피 이는 논리적으로 두개의 폼(?)을 가지고 있습니다. 사실, 개발자의 입장에서 보면 그들이 폼은 아닙니다만... 최종 사용자의 입장에서 보면 마치 폼 처럼 보이겠지요? 사실, <table>이 아니라 <panel>을 써도 무방하긴 할 것입니다만, 굳이 서버 컨트롤을 남발할 필요는 없기에, 저는 그냥 <table>을 사용해 보았습니다.
자. 이제 실제적인 처리 부분으로 들어가 보도록 하겠습니다.
각각의 논리적인 폼에는 버튼이 하나씩 있구요. 그 버튼이 클릭될 경우, 각 폼에 대한 실제적인 처리가 이루어져야 하겠죠? 그렇다면, 그렇게 일단 각 버튼의 Click 이벤트 처리기를 작성해 보아요. 다음처럼 말입지요
private void btnLogin_Click(object sender, System.EventArgs e) { 실제 로긴 처리... }
private void btnRegist_Click(object sender, System.EventArgs e) { 실제 등록 처리... } |
사실, 로긴 처리나 등록 처리의 경우, 그 처리가 간단하다면 그냥 현재의 위치에서 그것을 처리하는 코드를 작성해도 무방할 것입니다. 하지만, 우리는 그 처리가 복잡할 경우(굳이 복잡하지 않다고 하더라도 이 방법을 사용하는 것이 나쁘지는 않죠)를 예상하고 있기에... 이 부분의 처리를 다른 페이지로 분기시켜보려 합니다. 이를 위해서는 다음처럼 Server.Transfer를 사용하면 되는 것이죠.
private void btnLogin_Click(object sender, System.EventArgs e) { Server.Transfer("loginProcess.aspx"); }
private void btnRegist_Click(object sender, System.EventArgs e) { Server.Transfer("registerProcess.aspx"); } |
보이다시피, 간단하게 로긴과 관계된 처리는 loginProcess.aspx 페이지로 그 제어권을 넘기고 있구요. 등록관련 처리는 registerProcess.aspx 페이지로 넘기고 있습니다. ^^; 간단하죠?
이제, 드디어 각각의 실제 처리 페이지를 만들 시간이 되었습니다. 그렇다면, 먼저, loginProcess.aspx 페이지부터 만들어 보도록 합시당~ 사실, loginProcess.aspx 페이지의 처리는 로긴과 관계된 처리를 해야 하겠지만, 여기서는 그렇게까지는 하지 않을거구요... loginProcess.aspx 페이지에서 처리해야 할 가장 기본적인 작업만을 해결해 보도록 하겠습니다. 기본적인 처리라 함은 이전 페이지의 값들을 참조해 오는 것이지요. 가장 간단하게는 이전 다중 폼 페이지에 있는 컨트롤 중 로긴과 관계된 컨트롤의 값을 얻어오는 것이 되겠습니다. 이러한 방법만 알면, 이전 페이지에서 원하는 것은 무엇이든 참조가 가능할테니까 말입니다... 해서, loginProcess.aspx 페이지에서는 단지 이전 페이지에서 로긴과 관계된 컨트롤들의 값을 얻어와서, 그것을 Label 컨트롤에 출력하는 것 정도로만 간단하게 처리하려 합니다. 실무에서라면 그러한 처리를 제대로 해주어야 하겠지만, 지금은 예제일뿐이니까요 ^^
우선적으로, 실제 처리 페이지에서 이전 페이지를 참조하려면 @Reference 지시문을 사용해 주어야 합니다. 해서, 다음과 같이 여러분은 loginProcess.aspx 페이지의 지시문 구역에 코드를 작성해 주어야만 합니다.
<%@ Page language="c#" Codebehind="loginProcess.aspx.cs" AutoEventWireup="false" Inherits="MSDN.MultiForm.loginProcess" %> <%@ Reference Page="MultiWebForm.aspx" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD> <title>loginProcess</title> ... 이하 생략 ...
|
@ Reference 지시문에는 Page 어트리뷰트를 지정해 주어야 하는데요. 그 값은 이전 페이지, 즉 참조할 페이지(Server.Transfer를 수행한)의 파일 명이 되어야 합니다. 해서, 소스에서는 다음처럼 작성한 것이지요.
<%@ Reference Page="MultiWebForm.aspx" %>
이 설정은 대단히 중요합니다. 이 부분이 없으면 이전 페이지를 참조할 수가 없으니까요 ^^
자. 이제 80%의 작업은 되었습니다. 이제, 이러한 레퍼런스를 이용해서 loginProcess.aspx 페이지의 코드 비하인드에서는 이전 페이지로의 접근이 가능해지게 되었구요. 이전 페이지의 여러 값들도 읽어올 수가 있게 되었답니다.
코드에서 이를 접근하기 위해서는 먼저 다음과 같이, 이전 페이지 클래스를 선언해 주어야 하구요. 현재 Context의 Handler를 그 클래스 형식으로 형변환 해주셔야 합니다. 그래야, 이전 페이지 클래스에 프로그래밍적으로 접근이 가능하게 된답니다.
MultiWebForm multiWF = (MultiWebForm) Context.Handler;
이전 페이지 클래스의 이름이 MultiWebForm이기에, 코드에서는 그러한 형식을 사용하고 있음을 알 수 있습니다. 쉽죠????
이제는 multiWF 라는 이름으로 이전 페이지의 모든 컨트롤들, 속성들, 기능들을 이용할 수가 있게 됩니다. ^^;; 근데, 여기에는 문제가 하나 있습니다요... 그렇다면, 그 문제란 무엇이냐???
그것은 이전 페이지의 모든 컨트롤들이 기본적으로 그 접근자가 protected 라는 점입니다. 이러한 이유로 현재 상태로는 클래스로는 접근이 가능하지만, 개별적인 속성이나 컨트롤들에 대해서는 public 으로 선언된 것들에 한해서만 접근이 가능하고 그 외의 protected, private으로 선언된 것들로는 접근이 불가능하다는 것이지요. 해서, 지금 상태로는 이전 페이지의 컨트롤로 접근을 할 경우, 접근 권한이 없다는 에러만이 퓽퓽 뜰 겁니다. ㅠㅠ
이를 해결하기 위해서는, 물론, 이전 페이지의 코드비하인드 페이지에서 컨트롤들의 선언부를 약간 수정하여 protected로 선언되어져 있는 것을 public으로 바꾸면 문제 해결이 간단합니다만... 그것은 그다지 바람직한 접근법은 아니라고 사료됩니다. 물론, 그렇게 해도 뭐 크게 문제가 되지는 않습니다만.. 그보다 추천되는 방법은 별도의 public 속성을 작성하고, 그 속성을 통해서 각각의 컨트롤들의 값을 제공하는 것이지요. 이것이 보다 객체지향적인 프로그래밍 접근이 아니겠습니까???
해서, 저는 MultiWebForm.aspx 페이지의 코드 비하인드에 다음과 같이 각각의 컨트롤 값을 public 으로 노출하는 몇개의 속성을 추가로 작성해 보았습니다. 다음과 같이 말입니다.
public string MailingUserName { get { return MailingName.Text; } }
public string MailingEmailAddr { get { return MailingAddr.Text; } }
public string LoginUserID { get { return LogUserID.Text; } }
public string LoginPwd { get { return LogPwd.Text; } } |
자. 이제 필요한 값들을 모두 속성을 사용해서 public으로 공개시켰다면, 다시금 loginProcess.aspx 페이지로 돌아와서 다음과 같이 Page_Load 이벤트 처리기를 작성해 봅시다.
private void Page_Load(object sender, System.EventArgs e) { // 여기에 사용자 코드를 배치하여 페이지를 초기화합니다. MultiWebForm multiWF = (MultiWebForm) Context.Handler; Label1.Text = multiWF.LoginUserID; Label2.Text = multiWF.LoginPwd; } |
간단하지요? 이전 페이지에서 필요한 컨트롤 값들을 모두 public 속성으로 노출시켜 두었기에, 실제 처리 페이지에서는 이렇듯 간단하게 이전 페이지를 참조하여 원하는 값들을 가져다 사용할 수 있게 된 것입니다. ^^
결과는 대략 다음과 같이 나올 것 입니다. ^^

registerProcess.aspx 페이지의 처리도 loginProcess.aspx 페이지의 경우와 동일합니다. 똑같이 처리해 주시면 되지요~~ ^^.. 일단, registerProcess.aspx 페이지의 처리는 여러분이 한번 직접 시도해 보시구요. 만일, 그 처리가 잘 안된다 하시면, 다음에 첨부한 첨부파일을 살펴보도록 하세요. 지금 예제에서 설명드린 소스를 그대로 담아두었습니다. ^^
그럼 오늘도 좋은 하루 되시구요. 다음 강좌 기대해 주세요 ^^ 감사합니다.