[ASP.NET] 세션 상태

세션이랑 네트워크 환경에서 종보 교환을 하기 위한 논리적인 연결로, 웹 브라우저 마다 하나의 세션이 생성된다. 연결이 이루어지면 클라이언트와 서버는 연결에 대한 정보를 갖게 되는데 이를 세션 ID(식별자)라고 한다.

 

사용자가 세션 ID를 서버에 전달하면, ASP.NET은 대상 세션을 찾는다. 대상 세션을 통해 이전에 저장한 객체를 검색하고 이를 프로그램에 사용한다. 이러한 과정은 사용자가 적절한 세션 ID를 서버에 전달할 때 이루어진다.

 

서버에 세션 ID를 전달하는데는 다음 두 가지 방법이 있다.

· 쿠키 사용 : default로 세션을 사용하면 자동으로 만들어지는 ASP.NET_SessionID라는 이름의 쿠키로 세션 ID가 전달된다.

· URL에 포함 : 세션 ID를 URL에 포함하여 전달한다. 쿠키를 지원하지 않는 클라이언트에 사용할 수 있다.

 

ASP.NET의 세션 상태는 다음과 같은 경우에 유용하다.

· 웹 응용 프로그램이 쿠키나 쿼리 스틀이을 통해 쉽게 저장할 수 없는 복잡한 정보를 저장하고 접근하는 경우

· 철저한 보안이 요구되는 경우

세션 상태를 이용하면 서버의 메모리에 데이터를 저장할 수 있으며, 저장된 데이터는 사용자에게 전달되지 않기 때문에 좀 더 안전하다. 그러나 많은 사용자가 서버의 메모리를 사용하면, 응용 프로그램의 성능이 저하될 수 있으므로 세션 상태에서 사용 시는 신중을 기해야 한다.

 

세션 상태의 사용

세션 상태는 System.Web.SessionState.HttpSessionState 클래스를 이용한다. ASP.NET 페이지에서 HttpSessionState 클래스는 Session 객체로 제공된다. 세션 상태 컬렉션에 정보를 추가하거나 검색하는 방법은 뷰 상태 컬렉션에서의 방법과 같다.

Session["Note"] = 1;

Session 컬렉션의 Note 키에 값이 1이 저장된다. Session 컬렉션에 Note라는 키 항목이 없는 경우에는 새로운 항목으로 추가되고, 이미 Note라는 항목이 있는 경우에는 기존의 값이 1로 대치된다. Session 컬렉션에서 값을 가져올 때는 키 이름을 이용하여 값을 얻어오는데, 이때 변수형에 맞는 형 변환이 필요하다.

int note;
note = (int)Session["Note"];

세션 상태는 각 사용자가 사용하고 있는 웹 응용 프로그램에서 전역적으로 이용할 수 있다. 그러나 다음과 같은 상황에서는 세션 상태를 잃을 수 있으므로 주의해야 한다.

① 사용자가 웹 브라우저를 닫거나 다시 시작할 경우

② 사용자가 같은 페이지를 웹 브라우저의 다른 창을 통해 접근할 경우

③ 일정 시간동안 사용자의 요구가 없는 경우

④ 웹 페이지 코드에서 Session.Abandon() 메서드를 호출하여 세션을 종료할 경우

 

ASP.NET은 웹 브라우저를 닫았는지, 창을 바꾸었는지 알 수 없기 때문에 ①과 ②의 경우 서버의 메모리에 세션이 남아있게 되고, 만료 시간이 경과되어야 만료(expire)되어 세션 상태를 잃는다.

멤버 설명
Count 세션 상태 항목 컬렉션의 항목 수 반환
IsCookieless 세션 ID를 전달하는 방법을 선택(쿠키 또는 URL)
IsNewSession 세션을 현재 요청으로 만들었는지의 여부를 나타내는 값 반환
Keys 세션 상태 항목 컬렉션에 저장된 모든 값의 키 컬렉션 반환
Mode 현재 세션 상태 모드 반환
SessionID 세션의 고유한 세션 식별자(ID) 반환
Timeout 세션 지속 시간을 분 단위로 반환하거나 설정
Abandon() 현재 세션 종료
Clear() 세션 상태 항목 컬렉션에서 모든 값 삭제

 

세션을 이용한 장바구니 만들기

① 상품 데이터 클래스 만들기

상품 데이터를 별도의 클래스로 설계하고 상품과 관련된 정보를 저장한다. 코드의 길이를 짧게 하기 위해 상품 데이터의 멤버들을 public으로 선언한다. 또 상품 관련 정보를 담은 객체를 쉽게 생성할 수 있도록 상품 이름, 제조사, 가격을 매개변수로 받는 생성자를 사용한다.

 

새로운 클래스를 생성하는 과정은 다음과 같다.

1. 솔루션 탁색기에서 [새 항목] 창을 연다.

2. 클래스를 선택하고 이름에 'Goods.cs'라고 입력한 후, [추가] 버튼을 클릭한다.

3. 'App_Code' 폴더 저장 여부를 묻는 메시지 창이 나타나면 [예] 버튼을 클릭한다.(나는 안나옴)

4. 솔루션 탐색기에 'App_Code' 폴더가 새롭게 생선되고 C# 클래스 파일이 추가되면서 'Goods.cs' 파일 편집창이 열린다.

 

Goods.cs 파일에 상품을 모델링한 상품 클래스 Goods는 다음과 같이 정의한다.

// Goods.cs
public class Goods
{
  public string Name;
  public string Manufacturer;
  public int Cost;

  public Goods(string name, string manufacturer, int cost) { 
    Name = name;
    Manufacturer = manufacturer;
    Cost = cost;
  }
}

② 장바구니 페이지 디자인

솔루션 탐색기에서 새 웹 폼인 'ShoppingBasket.aspx'를 생성한다. 세션 상태에 대한 정보를 함께 나타내고 있는 장바구니 페이지는 다음과 같다.

번호 컨트롤 속성 속성 값
Label ID lblSessionInfo
Text  
ListBox ID lsㅅGoods
Button ID btnMoreInfo
Text 상세 정보 보기
Label ID lblGoodsInfo
Text  

③ 코드 숨김 파일 작성하기

사용자가 이미 쇼핑을 끝내고 장바구니 페이지를 요청하는 것으로 시작하는 예제 페이지의 시나리오를 나타낸 것이다.

장바구니 페이지 시나리오

장바구니 페이지 시나리오에 따라 Page_Load 이벤트 처리기에서는 사용자가 쇼핑한 것으로 가정한 상품을 직접 생성한다. 또 생성한 상품을 세션 상태에 저장하고 ListBox 항목에도 추가한다.

protected void Page_Load(object sender, EventArgs e)
{
  if (!IsPostBack) {
    // 쇼핑 상품 직접 생성
    Goods book1 = new Goods("Head First C#", "한빛미디어", 32000);
    Goods book2 = new Goods("Effective C#", "한빛미디어", 20000);
    Goods book3 = new Goods("데이터베이스 관리와 실습", "한빛미디어", 25000);

    // 세션에 저장
    Session["Book1"] = book1;
    Session["Book2"] = book2;
    Session["Book3"] = book3;

    // 장바구니 ListBox 항목 추가
    lstGoods.Items.Add(book1.Name);
    lstGoods.Items.Add(book2.Name);
    lstGoods.Items.Add(book3.Name);
  }

  // 세션 정보 보이기
  lblSessionInfo.Text = "세션 ID : " + Session.SessionID;
  lblSessionInfo.Text += "<br/>세션 내 객체 개수 : " + Session.Count.ToString();
  lblSessionInfo.Text += "br/>세션 모드 : " + Session.Mode.ToString();
  lblSessionInfo.Text += "<br/>쿠키 사용 안함 : " + Session.IsCookieless.ToString();
  lblSessionInfo.Text += "<br/>새 세션 : " + Session.IsCookieless.ToString();
  lblSessionInfo.Text += "<br/>세션 만료 시간 : " + Session.Timeout.ToString() + "분";
}

사용자가 상품을 선택하고 [상세 정보 보기] 버튼을 누르면 해당 상품에 대한 정보를 세션에서 읽어 보여주는 버튼 클릭 이벤트 처리기는 다음과 같다.

protected void btnMoreInfo_Click(object sender, EventArgs e)
{
  if (lstGoods.SelectedIndex == -1)
  {
    lblGoodsInfo.Text = "장바구니에 있는 상품을 먼저 선택하세요.";
  }
  else { 
    // 선택 상품에 대한 세션 키 만들기
    string key = "Book" + (lstGoods.SelectedIndex + 1).ToString();

    // 세션 키로 상품 객체 얻어오기
    Goods book = (Goods)Session[key];

    // 상세 정보 출력
    lblGoodsInfo.Text = "도서명 : " + book.Name;
    lblGoodsInfo.Text += "<br/>출판사 : " + book.Manufacturer;
    lblGoodsInfo.Text += "<br/>정가 : " + book.Cost;                
  }
}

④ 실행하기

상품을 선택하고 [상세 정보 보기] 버튼을 클릭하면 위와 같은 내용이 표시된다.

 

세션 상태 구성

현재 웹 사이트에 대한 세션 상태의 구성은 aspx 파일이 있는 가상 디렉터리의 구성 파일인 web.config를 통해 이루어지는데, 세션 만료 시간이나 세션 모드 등을 설정할 수 있다. 이때 ASP.NET MMC를 이용하면 비주얼 환경에서 세션 상태를 구성할 수 있다.

1. [시작] 버튼을 클릭한 후 입력 창에 'INetMgr'을 입력하고 엔터를 누르다.

2. ASP.NET MMC를 이용하여 <관리> 섹션 그룹의 <구성 편집기> 섹션의 속성을 다음과 같이 누른다.

· cookieless = "UserCookies", timeout = "10", mode = "InProc"

디렉터리 04를 선택해서 해야 한다.

3. 솔루션 탐색기의 web.config 파일이 다음과 같이 변경된 것을 확인할 수 있다.

(나는 04에서 sessionState가 없어서 수기로 입력해주었다.)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  ...
  <system.web>
    <sessionState cookieless="UseCookies" timeout="10" mode="InProc"/>
    ...
  </system.web>
</configuration>
설정 값 설명
UseCookies default 값으로 웹 브라우저나 장비가 쿠키를 지원하지 못하는 경우라도 쿠키를 이용
UseUri URL에 세션 ID를 저장
UseDeviceProfile ASP.NET가 HttpBrowserCapabilities 객체를 시험함으로써 쿠키 사용 여부를 결정-사용자가 쿠키 사용을 허용하지 않았을 경우 세션 정보에 대한 손실이 발생
AutoDetect ASP.NET가 쿠키를 설정하고 쿠키를 검색함으로써 쿠키 사용 여부를 결정-UseDeviceProfile의 단점을 극복

쿠키를 사용하지 않도록 하려면 web.config 파일의 <sessionState> 엘리먼트의 cookieless 속성을 다음과 같이 바꾼다. 물론 ASP.NET MMC를 이용하여 설정을 변경해도 된다.

<sessionState cookieless="UseUri" timeout="10" mode="InProc"/>

쿠키를 사용하지 않도록 설정하면, 세션 ID가 자동으로 URL에 삽입된다.

 

timeout

사용자의 요청이 없을 경우, 세션을 파기하기 전에 기다리는 시간을 분 단위로 설정한다. 세션이 비통상적으로 큰 데이터를 포함하고 있다면, 서버의 성능 저하를 막기 위해 세션 저장 시간을 제한해야 한다. 이와 같은 경우에는 사용자에게 통보하고, 다음과 같은 코드로 Session 객체의 Timeout 속성을 다시 설정할 수 있다.

Session.Timeout = 5; // Session Timeout 속성을 5분으로 설정

mode

모드 설정을 통해 다른 형태의 세션 상태 서비스를 사용할 수 있도록 구성할 수 있다. 설정 가능한 주요 모드로는 InProc, Off, StateServer, SQLSever 등이 있다.

 

· InProc 모드

default 모드인 InProc은 ASP.NET과 같은 프로세스에 세션 정보를 저장하며, 소규모 웹 사이트에 적합하다. 최고의 성능을 갖고 있지만 서버가 다시 시작할 경우 세션 상태를 모두 잃는 최악의 내구성을 보인다. 대형 웹 사이트의 경우 서버의 부하조절을 위해 여러 대의 서버를 운영한다. 이러한 경우에는 사용자의 요청을 어떤 서버가 처리할 것인지를 알 수 없으므로 페이지를 처리하는 프로세스에 세션 정보를 저장하는 InProc 모드는 사용할 수 없다.

 

· Off 모드

응용 프로그램에 있는 어떤 페이지도 세션 상태를 이용할 수 없다. 이 설정으로 웹 사이트의 성능을 다소 향상시킬 수 있다.

 

· StateServer 모드

상태 관리를 위한 서비스가 ASP.NET과 분리되어 운영된다. 따라서 ASP.NET 프로세스의 재시작으로 발생하는 세션 정보의 손실을 막을 수는 있지만, 프로세스에서 프로세스로 상태 정보를 전달하는 과정에서 시간 지연이 발생한다.

 

응용 프로그램이 StateServer 서비스를 이용하기 전에 ASP.NET State Service가 운영되고 있어야 한다.

1. [시작]-[제어판]-[시스템 및 보안]-[관리 도구]에서 [서비스]를 선택한다.

2. 오른쪽 창에서 ASP.NET State Service를 찾아 상태를 확인한다.

3. StateServer를 사용할 경우에는 윈도우가 시작할 때 서비스도 함께 시작하도록 한다. 이를 설정하기 위해 [서비스] 창의 ASP.NET State Service에 마우스 우클릭을 하면 나타나는 팝업 메뉴에서 [속성] 메뉴를 선택한다. 시작 유형을 <자동>으로 변경하고 [확인] 버튼을 누른다.

ASP.NET State Service가 시작되었다면, 구성 파일에서 세션 상태 구성을 다음과 같이 변경한다.

<sessionState cookieless="UseCookies" timeout="10" mode="StateServer" stateConnectionString="tcpip=localhost:44319" stateNetworkTimeout="10"/>

포트 번호는 자신의 포트번호를 입력하면 된다.

오류 메시지 내용과는 달리 세션 상태로 저장하는 객체가 직렬화되지 않았기 때문에 발생하는 오류이다. StateServer 모드나 다음에 살펴볼 SqLServer 모드의 경우 ASP.NET은 세션 상태 객체를 저장하기 위해 직렬화 한다.

 

장바구니 실습의 세션 상태를 StateServer 모드나 SQLServer 모드로 세션을 관리하려면 Goods 클래스 정의 앞에 [Serializable] 속성을 추가해야 한다.

[Serializable]
public class Goods
{ ... }

이렇게 해도 오류가 발생하는건 왜 때문인지 모르겠다.

 

SQLServer 모드는 생략해야겠다.

'ASP.NET 4.0' 카테고리의 다른 글

[ASP.NET] 데이터베이스 관리 시스템  (0) 2022.01.04
[ASP.NET] 애플리케이션 상태  (0) 2022.01.03
[ASP.NET] 쿠키  (0) 2022.01.03
[ASP.NET] 페이지들 사이의 정보 전달  (0) 2022.01.03
[ASP.NET] 뷰 상태  (0) 2022.01.03

댓글