AJAX를 사용하여 동적 업데이트 제공

작성자: Microsoft

PDF 다운로드

이는 ASP.NET MVC 1을 사용하여 작지만 완전한 웹 애플리케이션을 빌드하는 방법을 안내하는 무료 "NerdDinner" 애플리케이션 자습서 의 10단계입니다.

10단계에서는 저녁 식사 세부 정보 페이지에 통합된 Ajax 기반 접근 방식을 사용하여 로그인한 사용자가 저녁 식사에 참석하는 데 관심이 있는 RSVP에 대한 지원을 구현합니다.

ASP.NET MVC 3을 사용하는 경우 MVC 3 또는 MVC Music Store에서 시작 자습서를 따르는 것이 좋습니다.

NerdDinner 10단계: AJAX 사용 RSVP 허용

이제 로그인한 사용자가 저녁 식사 참석에 관심을 가지는 RSVP에 대한 지원을 구현해 보겠습니다. 저녁 식사 세부 정보 페이지 내에 통합된 AJAX 기반 접근 방식을 사용하여 이를 사용하도록 설정합니다.

사용자가 RSVP인지 여부를 나타냅니다.

사용자는 /Dinners/Details/[id] URL을 방문하여 특정 저녁 식사에 대한 세부 정보를 볼 수 있습니다.

저녁 식사에 대한 세부 정보가 있는 Nerd Dinner 웹 페이지의 스크린샷.

Details() 작업 메서드는 다음과 같이 구현됩니다.

//
// GET: /Dinners/Details/2

public ActionResult Details(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (dinner == null)
        return View("NotFound");
    else
        return View(dinner);
}

RSVP 지원을 구현하는 첫 번째 단계는 Dinner 개체(앞에서 빌드한 Dinner.cs 부분 클래스 내)에 "IsUserRegistered(username)" 도우미 메서드를 추가하는 것입니다. 이 도우미 메서드는 사용자가 현재 Dinner에 대한 RSVP인지 여부에 따라 true 또는 false를 반환합니다.

public partial class Dinner {

    public bool IsUserRegistered(string userName) {
        return RSVPs.Any(r => r.AttendeeName.Equals(userName, StringComparison.InvariantCultureIgnoreCase));
    }
}

그런 다음 Details.aspx 뷰 템플릿에 다음 코드를 추가하여 사용자가 이벤트에 등록되었는지 여부를 나타내는 적절한 메시지를 표시할 수 있습니다.

<% if (Request.IsAuthenticated) { %>
 
    <% if (Model.IsUserRegistered(Context.User.Identity.Name)) { %>       

        <p>You are registred for this event!</p>
    
    <% } else {  %>  
    
        <p>You are not registered for this event</p>
        
    <% }  %>
    
<% } else { %>
 
    <a href="/Account/Logon">Logon</a> to RSVP for this event.

<% } %>

이제 사용자가 Dinner를 방문하면 등록됩니다. 이 메시지가 표시됩니다.

이 이벤트에 등록됨 메시지가 맨 아래에 표시되는 Nerd Dinners 세부 정보 페이지의 스크린샷

그리고 저녁 식사를 방문할 때 등록되지 않은 경우 아래 메시지가 표시됩니다.

Nerd Dinners 세부 정보 페이지의 스크린샷. 이 이벤트에 등록되지 않은 메시지가 표시됩니다.

Register 작업 메서드 구현

이제 세부 정보 페이지에서 저녁 식사를 위해 사용자가 RSVP에 사용할 수 있도록 하는 데 필요한 기능을 추가해 보겠습니다.

이를 구현하기 위해 \Controllers 디렉터리를 마우스 오른쪽 단추로 클릭하고 추가> 컨트롤러 메뉴 명령을 선택하여 새 "RSVPController" 클래스를 만듭니다.

Dinner에 대한 ID를 인수로 사용하고, 적절한 Dinner 개체를 검색하고, 로그인한 사용자가 현재 등록한 사용자 목록에 있는지 확인하고, RSVP 개체를 추가하지 않는 경우를 확인하는 새 RSVPController 클래스 내에서 "Register" 작업 메서드를 구현합니다.

public class RSVPController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // AJAX: /Dinners/RSVPForEvent/1

    [Authorize, AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Register(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (!dinner.IsUserRegistered(User.Identity.Name)) {
        
            RSVP rsvp = new RSVP();
            rsvp.AttendeeName = User.Identity.Name;

            dinner.RSVPs.Add(rsvp);
            dinnerRepository.Save();
        }

        return Content("Thanks - we'll see you there!");
    }
}

작업 메서드의 출력으로 간단한 문자열을 반환하는 방법을 위에서 확인합니다. 보기 템플릿 내에 이 메시지를 포함할 수 있었지만 너무 작기 때문에 컨트롤러 기본 클래스에서 Content() 도우미 메서드를 사용하고 위와 같은 문자열 메시지를 반환합니다.

AJAX를 사용하여 RSVPForEvent 작업 메서드 호출

AJAX를 사용하여 세부 정보 보기에서 Register 작업 메서드를 호출합니다. 이를 구현하는 것은 매우 쉽습니다. 먼저 두 개의 스크립트 라이브러리 참조를 추가합니다.

<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>

첫 번째 라이브러리는 핵심 ASP.NET AJAX 클라이언트 쪽 스크립트 라이브러리를 참조합니다. 이 파일의 크기는 약 24k(압축됨)이며 핵심 클라이언트 쪽 AJAX 기능을 포함합니다. 두 번째 라이브러리에는 ASP.NET MVC의 기본 제공 AJAX 도우미 메서드(곧 사용)와 통합되는 유틸리티 함수가 포함되어 있습니다.

그런 다음 이전에 추가한 뷰 템플릿 코드를 업데이트하여 "이 이벤트에 등록되지 않았습니다." 메시지를 출력하는 대신 푸시할 때 RSVP 컨트롤러 및 RSVP에서 RSVPForEvent 작업 메서드를 호출하는 AJAX 호출을 수행하는 링크를 렌더링합니다.

<div id="rsvpmsg">

<% if(Request.IsAuthenticated) { %>
 
    <% if(Model.IsUserRegistered(Context.User.Identity.Name)) { %>       

        <p>You are registred for this event!</p>

    <% } else { %>  
    
        <%= Ajax.ActionLink( "RSVP for this event",
                             "Register", "RSVP",
                             new { id=Model.DinnerID }, 
                             new AjaxOptions { UpdateTargetId="rsvpmsg"}) %>         
    <% } %>
    
<% } else { %>
 
    <a href="/Account/Logon">Logon</a> to RSVP for this event.

<% } %>
    
</div>

위에서 사용된 Ajax.ActionLink() 도우미 메서드는 MVC를 ASP.NET 기본 제공되며, 표준 탐색을 수행하는 대신 링크를 클릭할 때 작업 메서드에 대한 AJAX 호출을 수행한다는 점을 제외하고 Html.ActionLink() 도우미 메서드와 유사합니다. 위에서는 "RSVP" 컨트롤러에서 "Register" 작업 메서드를 호출하고 DinnerID를 "id" 매개 변수로 전달합니다. 전달되는 최종 AjaxOptions 매개 변수는 작업 메서드에서 반환된 콘텐츠를 가져와서 ID가 "rsvpmsg"인 페이지의 HTML <div> 요소를 업데이트하려고 했음을 나타냅니다.

그리고 이제 사용자가 저녁 식사로 이동하면 아직 등록되지 않은 경우 RSVP에 대한 링크가 표시됩니다.

아래쪽에 R S VP 단추가 있는 Nerd Dinners 페이지의 스크린샷.

"이 이벤트에 대한 RSVP" 링크를 클릭하면 RSVP 컨트롤러의 Register 작업 메서드에 대한 AJAX 호출이 수행되고 완료되면 다음과 같은 업데이트된 메시지가 표시됩니다.

하단에 감사드립니다. 메시지가 표시된 Nerd Dinner 세부 정보 페이지의 스크린샷

이 AJAX 호출을 수행할 때 관련된 네트워크 대역폭 및 트래픽은 매우 간단합니다. 사용자가 "이 이벤트에 대한 RSVP" 링크를 클릭하면 회선에서 아래와 같은 /Dinners/Register/1 URL에 대한 작은 HTTP POST 네트워크 요청이 수행됩니다.

POST /Dinners/Register/49 HTTP/1.1
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Referer: http://localhost:8080/Dinners/Details/49

또한 Register 작업 메서드의 응답은 다음과 같습니다.

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 29
Thanks - we'll see you there!

이 경량 호출은 빠르며 느린 네트워크를 통해서도 작동합니다.

jQuery 애니메이션 추가

구현한 AJAX 기능은 잘 작동하고 빠르게 작동합니다. 하지만 사용자가 RSVP 링크가 새 텍스트로 대체되었음을 알 수 없을 정도로 빠르게 발생할 수 있습니다. 결과를 좀 더 명확하게 하기 위해 간단한 애니메이션을 추가하여 업데이트 메시지에 주의를 끌 수 있습니다.

기본 ASP.NET MVC 프로젝트 템플릿에는 Microsoft에서 지원하는 우수한(그리고 매우 인기 있는) 오픈 소스 JavaScript 라이브러리인 jQuery가 포함되어 있습니다. jQuery는 멋진 HTML DOM 선택 및 효과 라이브러리를 포함하여 다양한 기능을 제공합니다.

jQuery를 사용하려면 먼저 스크립트 참조를 추가합니다. 사이트 내의 다양한 위치 내에서 jQuery를 사용할 예정이므로 사이트 내에 스크립트 참조를 추가하겠습니다. 모든 페이지에서 사용할 수 있도록 페이지 파일을 master master.

<script src="/Scripts/jQuery-1.3.2.js" type="text/javascript"></script>

JQuery를 사용하여 작성된 코드는 CSS 선택기를 사용하여 하나 이상의 HTML 요소를 검색하는 전역 "$()" JavaScript 메서드를 사용하는 경우가 많습니다. 예를 들어 $("#rsvpmsg") 는 rsvpmsg ID가 있는 HTML 요소를 선택하고 $(".something") 는 "something" CSS 클래스 이름을 가진 모든 요소를 선택합니다. $("input[@type=radio][@checked]")와 같은 선택기 쿼리를 사용하여 "선택된 라디오 단추 모두 반환"과 같은 고급 쿼리를 작성할 수도 있습니다.

요소를 선택한 후에는 메서드를 호출하여 숨기는 것과 같은 작업을 수행할 수 있습니다. $("#rsvpmsg").hide();

RSVP 시나리오의 경우 "rsvpmsg" div>를 선택하고 텍스트 콘텐츠의 크기에 애니메이션 효과를 주는 "AnimateRSVPMessage"<라는 간단한 JavaScript 함수를 정의합니다. 아래 코드는 텍스트를 작게 시작한 다음 400밀리초 이상 증가합니다.

<script type="text/javascript">

    function AnimateRSVPMessage() {
        $("#rsvpmsg").animate({fontSize: "1.5em"},400);
    }

</script>

그런 다음 AjaxOptions "OnSuccess" 이벤트 속성을 통해 Ajax.ActionLink() 도우미 메서드에 이름을 전달하여 AJAX 호출이 성공적으로 완료된 후 이 JavaScript 함수를 연결할 수 있습니다.

<%= Ajax.ActionLink( "RSVP for this event",
                     "Register", "RSVP",
                     new { id=Model.DinnerID }, 
                     new AjaxOptions { UpdateTargetId="rsvpmsg",
                                       OnSuccess="AnimateRSVPMessage"}) %>

이제 "이 이벤트에 대한 RSVP" 링크를 클릭하고 AJAX 호출이 성공적으로 완료되면 다시 전송된 콘텐츠 메시지가 애니메이션 효과를 주고 커집니다.

아래쪽에 큰 글자를 인쇄하여 감사드립니다. 메시지가 표시된 괴상한 저녁 식사 페이지의 스크린샷

AjaxOptions 개체는 "OnSuccess" 이벤트를 제공하는 것 외에도 처리할 수 있는 OnBegin, OnFailure 및 OnComplete 이벤트를 노출합니다(다른 다양한 속성 및 유용한 옵션과 함께).

정리 - RSVP 부분 보기 리팩터링

세부 정보 보기 템플릿이 조금 길어지기 시작했으며, 이로 인해 초과 작업으로 인해 이해하기가 조금 더 어려워집니다. 코드 가독성을 개선하기 위해 세부 정보 페이지에 대한 모든 RSVP 보기 코드를 캡슐화하는 부분 보기인 RSVPStatus.ascx를 만들어 보겠습니다.

\Views\Dinners 폴더를 마우스 오른쪽 단추로 클릭한 다음 추가> 보기 메뉴 명령을 선택하여 이 작업을 수행할 수 있습니다. Dinner 개체를 강력한 형식의 ViewModel로 사용합니다. 그런 다음 Details.aspx 보기에서 RSVP 콘텐츠를 복사/붙여넣을 수 있습니다.

이렇게 하면 편집 및 삭제 링크 보기 코드를 캡슐화하는 또 다른 부분 보기인 EditAndDeleteLinks.ascx도 만들어 보겠습니다. Dinner 개체를 강력한 형식의 ViewModel로 사용하고 Details.aspx 보기에서 편집 및 삭제 논리를 복사/붙여넣습니다.

세부 정보 보기 템플릿은 아래쪽에 두 개의 Html.RenderPartial() 메서드 호출만 포함할 수 있습니다.

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent"runat="server">
    <%= Html.Encode(Model.Title) %>
</asp:Content>

<asp:Content ID="details" ContentPlaceHolderID="MainContent" runat="server">

    <div id="dinnerDiv">

        <h2><%=Html.Encode(Model.Title) %></h2>
        <p>
            <strong>When:</strong> 
            <%=Model.EventDate.ToShortDateString() %> 

            <strong>@</strong>
            <%=Model.EventDate.ToShortTimeString() %>
        </p>
        <p>
            <strong>Where:</strong> 
            <%=Html.Encode(Model.Address) %>,
            <%=Html.Encode(Model.Country) %>
        </p>
         <p>
            <strong>Description:</strong> 
            <%=Html.Encode(Model.Description) %>
        </p>       
        <p>
            <strong>Organizer:</strong> 
            <%=Html.Encode(Model.HostedBy) %>
            (<%=Html.Encode(Model.ContactPhone) %>)
        </p>
    
        <% Html.RenderPartial("RSVPStatus"); %>
        <% Html.RenderPartial("EditAndDeleteLinks"); %>
 
    </div>
         
</asp:Content>

이렇게 하면 코드를 더 클리너로 읽고 유지 관리할 수 있습니다.

다음 단계

이제 AJAX를 더욱 사용하고 애플리케이션에 대화형 매핑 지원을 추가하는 방법을 살펴보겠습니다.