'2016/12'에 해당되는 글 4건

Programming/.NET

1. 출력캐시(Output Cache)

 

출력캐시는 페이지의 컨텐츠 내용을 서버의 메모리나 디스크에 저장하고 사용자가 해당 페이지를 다시 요청하는 저장한 내용을 반환해주는 방법입니다. 동적으로 생성된 페이지의 경우에도 최종 렌더링이후의 내용을 저장하고 사용자에게 반환합니다.

 

특정 페이지에 출력캐시를 지정하려면 다음과 같이 OutputCache선언문을 사용합니다.

 

<%@ OutputCache Duration="60" VaryByParam="None" %>

 

Duration은 캐시가 저장될 시간을 설정합니다. 해당 시간이 지나면 저장된 컨텐츠는 만료됩니다. 시간단위는 '초'입니다.

 

 1. VaryByParam

 

페이지가 호출될때 다음과 같은 형식으로 페이지가 호출된다고 가정해 보겠습니다.

 

http://www.testsite.com/default.aspx?userid=cliel

 

default.aspx페이지는 GET로 받아들인 userid값에 따라 다른 내용을 출력하는 페이지입니다. 이러한 형태의 페이지를 캐시하고자 하는 경우에는 userid값이 따라 각각 개별적으로 페이지를 캐시해야할 필요가 있을 것입니다. 이럴 때 VaryByParam을 다음과 같이 설정해야 합니다.

 

<%@ OutputCache Duration="60" VaryByParam="userid" %>

 

만약 GET으로 받아들이는 매개변수가 2개 이상인 경우에는 ; 문자로 구분해 지정해 주면 됩니다.

 

<%@ OutputCache Duration="60" VaryByParam="userid;username" %>

 

만일 매개변수가 너무 많거나 매개변수의 구분없이 모든 값에 대응하여 캐시해야 하는 경우에는 * 문자를 사용합니다.

 

<%@ OutputCache Duration="60" VaryByParam="*" %>

 

 2. VaryByHeader

 

특정 헤더값에 따라 페이지를 캐시해야 하는 경우 VaryByHeader 특성을 사용합니다. 예를 들어 헤더의 User-Agent값을 구분하여 캐시하고자 한다면 다음과 같이 지정합니다.

 

<%@ OutputCache Duration="60" VaryByParam="None" VaryByHeader="User-agent" %>

 

 3. VaryByControl

 

이 특성을 사용하면 특정 컨트롤의 데이터만을 캐시할 수도 있습니다.

 

예를 들어 수강신청시스템에서 수강하고자 하는 과목을 선택하는 ComboBox컨트롤이 존재할때 이 컨트롤은 페이지가 호출될때마다 현재의 모든 과목을 DB에서 불러와 표시할 수 있을 것입니다. 만약 과목이 자주 변하지 않는다는 전제가 있는 경우 ComboBox에서 표시되는 최종 결과를 캐시하도록 하면 사용자에게 좀 더 빠른 출력을 제공할 수 있을 것입니다.

 

<%@ OutputCache Duration="60" VaryByParam="None" VaryByControl="cmb_Subject" %>

 

VaryByControl 특성에는 Control의 ID를 지정합니다.

 

 4. VaryByCustom

 

임의의 값에 따라 캐시처리를 해야 하는 경우 VaryByCustom 특성을 사용합니다.

 

<%@ OutputCache Duration="60" VaryByParam="None" VaryByCustom="cache" %>

 

이 값은 페이지의 GetVaryByCustomString 메소드를 오버로드하여 custom으로 넘어오는 매개변수를 읽는 방법으로 확인해야 합니다.

 

public override string GetVaryByCustomString(HttpContext context, string custom)
{
    if (custom == "cache") {

    }

    return base.GetVaryByCustomString(context, custom);
}

 

이 메소드는 Global.asax 페이지에 정의되어야 합니다.

 

2. 부분페이지캐시(Page Partial Cache)

 

부분 페이지 캐시는 정확히 말해 여러 페이지에서 공통적으로 사용하는 '사용자 정의 컨트롤(ascx)'을 캐시합니다. 만약 특정 ascx에서 OutputCache 선언이 존재한다면 이 컨트롤을 사용하는 각 페이지에서 개별적으로 컨트롤이 캐시되는데 Shared속성을 true로 추가하면 단 한번만 캐시되어 ascx를 사용하는 모든 페이지에서 공통적으로 캐시된 ascx를 사용하게 됩니다.

 

<%@ OutputCache Duration="120" VaryByParam="None" Shared="true" %>

 

ascx에 OutputCache가 걸려 있고 이를 사용하는 페이지가 출력된다면 실제 ascx컨트롤이 해당 페이지에 들어가지 않고 대신 PartialCachingControl이 생성되어 기존 ascx컨트롤을 대체하여 최종 HTML이 렌더링됩니다. 결론적으로 aspx에는 캐시된 PartialCachingControl이 존재할뿐 실제 ascx컨트롤은 존재하지 않는 것입니다.

 

이 상태에서 ascx에 접근하여 무엇인가를 처리하려고 한다면 경우에 따라 오류가 발생할 가능성이 많습니다. 이를 예외적으로 처리하기 위해 aspx의 cs코드에서는 다음과 같이 PossiblyCachedUserControl이 존재하는지를 확인하고 처리해야 합니다.

 

if (custom_control == null) {
    //없음
}
else {
    //있음
}

 

3. 캐시 치환

 

페이지 전체를 캐시하더라도 특정 부분은 항상 동적인 데이터를 출력해야 하는 경우가 있습니다. 이런 경우에는 우선 캐시된 페이지를 출력하고 나서 특정 메소드를 호출하여 원하는 데이터를 끌어오는 방법을 사용할 수 있습니다. 이걸 '캐시 치환'이라고 합니다.

 

<form id="form1" runat="server">
<div>
    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
    <asp:Substitution ID="Substitution1" runat="server" MethodName="GetTime" />
</div>
</form>

 

캐시 치환에는 Substitution 컨트롤이 사용됩니다. 이 컨트롤에는 MethodName속성으로 GetTime라는 정적메소드의 이름이 지정되었습니다.

 

protected void Page_Load(object sender, EventArgs e)
{
    Label1.Text = "cliel";
}

public static string GetTime(HttpContext context)
{
    return DateTime.Now.ToString();
}

 

호출할 메소드는 정적메소드여야 하며 HttpContext개체를 매개변수로 전달해야 합니다. 이와 같은 방법으로 메소드에 원하는 데이터를 가져오도록 하면 Substitution컨트롤부분에 동적데이터를 표시할 수 있습니다.

0 0
Programming/.NET

서버 컨트롤에서 페이지에 포스트백 이벤트를 발생시키려면 우선 GetPosBackEventReference 메소드를 사용해 클라이언트에 포스트백을 일으키는 스크립트를 생성해야 합니다.

 

protected override void RenderContents(HtmlTextWriter output)
{
    PostBackOptions pbo = new PostBackOptions(this);
    output.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.ClientScript.GetPostBackEventReference(pbo));

    output.AddAttribute(HtmlTextWriterAttribute.Id, "btn_" + this.ClientID);
    output.RenderBeginTag(HtmlTextWriterTag.Button);
    output.Write("Button");
    output.RenderEndTag();
}

 

PostBackOptions는 포스트백을 발생시킬때 사용가능한 옵션을 설정합니다. 지금은 아무것도 필요하지 않으므로 객체만 생성하고 GetPostBackEventReference 메소드에 해당 객체를 전달하도록 합니다.

 

예제에서는 버튼에 포스트백을 걸어놓았는데 버튼을 눌렀을때 실제 이벤트를 처리하려면 우선 IPostBackEventHandler 인터페이스를 상속받아

 

public class WebCustomControl1 : WebControl, IPostBackEventHandler

 

RaisePostBackEvent 메소드를 작성합니다.

 

public void RaisePostBackEvent(string sender)
{

}

 

RaisePostBackEvent 메소드는 버튼을 눌렀을때 실제 호출되는 메소드인데 해당 메소드를 통해서 원하는 이벤트를 호출하는 것입니다.

 

private EventHandler _click; 
public event EventHandler Click 
{ 
    add { _click += value; } 
    remove { _click -= value; }
}

 

호출될 이벤트를 서버 컨트롤과 연결시키기 위해 서버컨트롤에서 Click 속성을 생성하고 _click 이벤트 핸들러에 속성으로 전달되는 이벤트를 연결시키도록 합니다.

 

protected virtual void OnClickEvent()
{ 
    if (_click != null) 
        _click(this, new EventArgs()); 
}

 

_click에 연결된 이벤트는 OnClickEvent 가상메소드에 의해 호출되도록 하며

 

public void RaisePostBackEvent(string sender)
{
    OnClickEvent();
}

 

이 가상 메소드는 이전에 IPostBackEventHandler 인터페이스로 구현된 RaisePostBackEvent 메소드에서 호출될것입니다.

 

이제 서버 컨트롤에서의 준비는 끝났으므로 서버 컨트롤이 사용되는 페이지에서 서버컨트롤의 Click이벤트를 연결하고

 

protected void Page_Load(object sender, EventArgs e)
{
    myControl.Click += MyControl_Click;
}

 

해당 이벤트의 메소드를 작성합니다.

 

private void MyControl_Click(object sender, EventArgs e)
{
    Response.Write("aaa");
}

 

페이지를 실행하고 서버 컨트롤에서 생성된 Button을 클릭하면 자연스럽게 페이지에 작성된 MyControl_Click 메소드가 호출될 것입니다.

 

뿐만 아니라 서버 컨트롤에서는 페이지에서 포스트백이 발생할때 서버로 전송되는 데이터를 받아오는 것도 가능합니다.

 

public class WebCustomControl1 : WebControl, IPostBackDataHandler

 

포스트백 데이터를 받아오기 위해서는 IPostBackDataHandler 인터페이스를 구현해야 합니다.

 

public bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
    Text = postCollection["TextBox1"];
    return false;
}

public void RaisePostDataChangedEvent()
{
}

 

IPostBackDataHandler 인터페이스는 LoadPostData와 RaisePostDataChangedEvent메소드를 구현해야 합니다. 페이지에서는 포스트백이 발생하면 서버 컨트롤의 LoadPostData메소드를 호출하여 서버로 전송되는 데이터를 NameValueCollection 에 담아 전송해주게 됩니다.

 

LoadPostData 메소드에서는 TextBox1의 입력값을 받아오기 위해 키를 TextBox1로 지정했는데 자기 자신의 포스트백데이터를 받아오려면 postDataKey를 키값으로 지정해 주면 됩니다. 또한 LoadPostData메소드에서는 false를 return값으로 정했는데 만약 이 값을 true로 바꾸면 RaisePostDataChangedEvent메소드를 호출하게 됩니다. 특정 이벤트를 서버 컨트롤에서 발생시켜야 하는 경우 return을 true로 바꾸고 RaisePostDataChangedEvent메소드에 필요한 이벤트를 지정하면 됩니다.

 

protected override void OnInit(EventArgs e)
{
    Page.RegisterRequiresPostBack(this);
}

 

LoadPostData메소드가 정상적으로 호출될 수 있도록 하려면 OnInit 초기화 메소드를 재정의 하여 페이지의 RegisterRequiresPostBack메소드를 등록해야 합니다.

 

<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<cc1:WebCustomControl1 runat="server" ID="myControl" />
<asp:Button Text="Submit" Runat="server" />

 

페이지에는 TextBox와 Button컨트롤을 추가했습니다. Button의 용도는 다른것 없이 오로지 포스트백만을 발생시키기 위한 것입니다.

 

protected void Page_Load(object sender, EventArgs e)
{
    Response.Write(myControl.Text);
}

 

페이지를 실행해 버튼을 클릭하면 서버 컨트롤에서는 LoadPostData메소드를 통해 TextBox1의 값을 가져와 Text속성값으로 지정하게 됩니다. 그리고 페이지의 Load이벤트에 의해 해당 내용이 표시됩니다.

0 0
Programming/.NET

ViewState와 비슷한 개념의 ControlState는 컨트롤에만 사용할 수 있는 것으로 ViewState가 비활성상태라 하더라도 아무런 영향을 받지 않고 컨트롤에서 데이터를 저장할 수 있는 기능을 유지할 수 있습니다.

 

protected override void OnInit(EventArgs e)
{
    Page.RegisterRequiresControlState(this);
    base.OnInit(e);
}

 

ControlState사용을 위해서는 우선 RegisterRequiresControlState메소드를 호출해야 합니다. 예제에서 이 메소드는 컨트롤의 OnInit메소드를 재정의하여 구현하였습니다.

 

protected override void LoadControlState(object dataState)
{
    Text = (string)dataState;
}

protected override object SaveControlState()
{
    return (object)Text;
}

 

뒤이어 LoadControlState와 SaveControlState메소드를 위와같이 재정의 합니다. 이것으로 ControlState사용준비가 끝났습니다.

 

public string Text
{
    get
    {
        String s = (String)ViewState["Text"];
        return ((s == null) ? String.Empty : s);
    }

    set
    {
        ViewState["Text"] = value;
    }
}

 

서버 컨트롤에서 Text 속성은 ViewState를 사용하도록 되어 있는데 RegisterRequiresControlState메소드 사용과 LoadControlState, SaveControlState메소드 재정의를 통해서 이제는 ControlState를 데이터저장용도로 사용할 것입니다.

 

따라서 페이지에서 EnableViewState속성이 false로 되어 있다 하더라도 Text속성으로 입력된 내용을 여전히 기억할 것입니다.

 

<form id="form1" runat="server">
<div>
    <cc1:WebCustomControl1 runat="server" ID="myControl" />
    <asp:Button ID="Button1" runat="server" Text="Button" />
</div>
</form>

 

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
        myControl.Text = "aaabbb";
}

0 0
Programming/.NET

서버 컨트롤을 통해 페이지 하단에 스크립트를 출력하려면 RegisterStartupScript 메소드를 사용합니다.

 

protected override void OnPreRender(EventArgs e)
{
    Page.ClientScript.RegisterStartupScript(typeof(Page), "alert", "alert('aaa');", true);
}

 

RegisterStartupScript 메소드를 사용할때는 두번째 인자에 스크립트 식별키를, 세번째 인자에 스크립트 본체를 전달합니다. 식별키는 등록하려는 스크립트를 구분하기 위한 키로서 IsStartupScriptRegistered 메소드등으로 특정 스크립트가 등록되어 있는지 여부를 확인할 수 있는 방법을 제공합니다.

 

네번째 인자에는 true값을 주었는데 이러한 값을 전달해야만 스크립트등록시 <script>구문을 추가하여 스크립트가 정상적으로 작동될 수 있도록 합니다.

 

protected override void OnPreRender(EventArgs e)
{
    Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "alert", "alert('aaa');", true);
}

 

이 예제는 스크립트 등록을 위한 메소드를 RegisterClientScriptBlock 메소드로 바꾼것인데 이 메소드는 스크립트를 Form요소 다음의 페이지 상단에 배치합니다.

 

만약 HTML페이지 내에서 서버 컨트롤에서 추가시키는 스크립트를 호출하는 부분이 존재한다면

RegisterClientScriptBlock 메소드를 사용해야 합니다. 페이지 상단에 미리 스크립트가 등록되어 있어야 뒤이어 오는 스크립트 호출부분이 정상적으로 처리될 수 있을 것입니다.

 

protected override void RenderContents(HtmlTextWriter output)
{
    output.AddAttribute("OnClick", "javascript:cal(10, 20);");

    output.RenderBeginTag(HtmlTextWriterTag.Div);
    output.Write(Text);
    output.RenderEndTag();
}

protected override void OnPreRender(EventArgs e)
{
    Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "alert", "var cal = function(i, j) { i = i + j; alert(i);};", true);
}

 

참고로 서버 컨트롤에서 간단하게 위와 같이 직접 스크립트를 등록할 수 있지만 내용이 많은 경우 하나의 파일로 저장하고 이 파일(js파일)을 포함시킬 수 있습니다.

 

protected override void OnPreRender(EventArgs e)
{
    Page.ClientScript.RegisterClientScriptInclude("myScript", "sample.js");
}

 

ASP.NET에서는 서버와의 처리를 AJAX로 구현할 수 있는 클라이언트 콜백을 사용할 수 있습니다.

 

2014/02/12 - [Programming/.NET] - [ASP.NET] 클라이언트 콜백(Client Callback)


서버 컨트롤도 마찬가지 인데 컨트롤도 위와 같은 클라이언트 콜백을 구현할 수 있습니다.

 

public class WebCustomControl1 : WebControl, ICallbackEventHandler

 

우선 서버컨트롤에 ICallbackEventHandler 인터페이스를 구현합니다. 이 인터페이스는 RaiseCallbackEvent 와 GetCallbackResult 메소드를 구현해야 합니다.

 

string name;
public void RaiseCallbackEvent(string param)
{
    if (param == "error") {
        throw new Exception("잘못된 이름입니다.");
    }

    name = param + "님 반갑습니다.";
}

public string GetCallbackResult()
{
    return name;
}

 

RaiseCallbackEvent 메소드에는 실제 서버에서 작업이 처리되는 부분이며 GetCallbackResult 메소드는 어떤 결과를 클라이언트에 반환하는 역활을 수행합니다. 예제로는 RaiseCallbackEvent 에서 특정 값을 전달받아 '님 반갑습니다.'라는 메세지를 붙이며 만약 전달값이 'error'면 임의로 예외가 발생하도록 하였습니다. GetCallbackResult 에서는 RaiseCallbackEvent 에서 작업한 결과를 반환합니다.

 

protected override void RenderContents(HtmlTextWriter output)
{
    output.AddAttribute("OnClick", "javascript:hello('anchor37 ');");
    output.RenderBeginTag(HtmlTextWriterTag.Div);
    output.Write(Text);
    output.RenderEndTag();
}

protected override void OnPreRender(EventArgs e)
{
    Page.ClientScript.RegisterStartupScript(typeof(Page), "hello", "var hello = function (param) { " + Page.ClientScript.GetCallbackEventReference(this, "param", "CallbackHandler", null, "ErrorHandler", true) + " };", true);
}

 

RenderContents 에서 Hello라는 스크립트 함수를 호출합니다. 이 스크립트는 OnPreRender 메소드의 RegisterStartupScript 로 등록되며 GetCallbackEventReference 메소드에서 함수 실행 본체를 서버에서 처리할 수 있도록 클라이언트와 서버처리를 결합시킵니다. 이 때 두번째 함수의 인자에 전달될 클라이언트측 변수값(param)을 지정하고 세번째인자에 정상처리될 경우의 스크립트를, 다섯번째인자에 오류가 발생했을 경우의 스크립트를 등록해야 합니다.

 

<script type="text/javascript">
    var CallbackHandler = function (args, ctx) {
        alert(args);
    };

    var ErrorHandler = function (args, ctx) {
        alert(args);
    };
</script>

 

위 GetCallbackEventReference 메소드로 등록했던 스크립트입니다. 일단 클라이언트에서 hello 메소드가 호출되면 서버의 RaiseCallbackEvent 메소드가 실행되며 정상처리되었을 경우 클라이언트의 CallbackHandler 메소드를 호출해 '~님 반갑습니다.'라는 내용을 args에 넘겨주게 됩니다.

 

만약 이 과정에서 오류가 발생하면 '잘못된 이름입니다.'라는 메세지를 ErrorHandler 메소드를 표시할 것입니다.

0 0
1
블로그 이미지

클리엘