Skip to main content
Foto Gisela Torres

por Gisela Torres

Senior Developer en Alten España

http://geeks.ms/blogs/gtorres/

AJAX y ASP.NET MVC

Cuando creamos un proyecto de MVC, de forma automática se genera una carpeta llamada Scripts con los siguientes archivos js:

En el momento que queramos hacer uso de ellos, únicamente debemos importarlos, generalmente en la Master Page de nuestra aplicación:

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>
        <asp:ContentPlaceHolder ID="TitleContent" runat="server"/>
    </title>
    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />

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

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

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

</head>

Para mostrar un ejemplo de la forma de trabajar con Ajax en una aplicación MVC, voy a llevar a cabo una serie de pasos para ajustar el contenido de la aplicación Movie Manager usada en otros ejemplos.

PARTIAL VIEW DEL LISTADO DE PELÍCULAS

Seleccionamos la carpeta Movie, dentro de Views, y con lo el botón derecho seleccionamos Add => View. Especificamos la siguiente configuración:

Pulsando en Add, se genera una nueva vista con extensión ascx. He modificado ligeramente el contenido para configurar las acciones de detalle, edición y una última para la eliminación de películas de manera asíncrona con Ajax. Además, he añadido tres funciones utilizando JQuery.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<MovieManager.Models.Objects.Movie>>" %>
<%@ Import Namespace="MovieManager.Helpers" %>

<script type="text/javascript">

function beginMovieList(args) {
    $('#divMovieList').slideUp('normal');
 }
 function successMovieList() {
    $('#divMovieList').slideDown('normal');
 }
 function failureMovieList() {
    alert("Could not retrieve movies.");
 }

</script>

<table>
    <tr>
        <th>
        </th>
        <th>
            Id
        </th>
        <th>
            Name
        </th>
        <th>
            Genre
        </th>
        <th>
            Synopsis
        </th>
        <th>
            Date
        </th>
    </tr>
    <% foreach (var item in Model)
       { %>
    <tr>
        <td>
            <%=Html.ImageLink("Movie", "Details", "Content\\detail.gif", new {item.Id })%>
            |
            <%=Html.ImageLink("Movie","Edit","Content\\edit.gif",new {item.Id }) %>
            |
            <%= Ajax.ActionLink("Delete", "Delete", new { id = item.Id }, new AjaxOptions { Confirm = "Delete movie?", HttpMethod = "Delete", UpdateTargetId = "divMovieList", OnBegin = "beginMovieList", OnComplete = "successMovieList", OnFailure = "failureMovieList" })%>
        </td>
        <td>
            <%= Html.Encode(item.Id) %>
        </td>
        <td>
            <%= Html.Encode(item.Name) %>
        </td>
        <td>
            <%= Html.Encode(item.Genre) %>
        </td>
        <td>
            <%= Html.Encode(item.Synopsis) %>
        </td>
        <td>
            <%= Html.Encode(String.Format("{0:g}", item.Date)) %>
        </td>
    </tr>
    <% } %>
</table>

En la acción Delete se ha utilizado el helper específico para los controles Ajax. Dentro del mismo, he usado ActionLink donde se usan los mismos parámetros que en un control normal del Html helper a excepción del último parámetro: AjaxOptions. Este objeto, contiene una serie de propiedades para su configuración. Las utilizadas en el ejemplo son:

  1. Confirm: Antes de realizar la acción, se tendrá que confirmar la misma a través de un cuadro de diálogo con el texto introducido en esta propiedad. 
  2. HttpMethod: Se indica el tipo de verbo http que se utilizará en la llamada. En esta ocasión se hace uso de Delete ya que estamos intentando eliminar un recurso.
  3. UpdateTargetId: Id del elemento de nuestra vista que se va a actualizar, como si se tratara de un Update Panel.
  4. OnBegin: Se le pasa el nombre de la función que se ejecutará cuando se inicie la llamada asíncrona. Por ejemplo, podemos llamar a la función beginMovieList para ocultar el listado de películas cuando comience la eliminación de una de ellas.
  5. OnComplete: Si la llamada asíncrona se completa con éxito, se lanzará la función asociada a esta propiedad. En este caso successMovieList volverá a mostrar el listado de películas actualizado.
  6. OnFailure: Si durante la llamada se produce algún tipo de error, se lanzará la función enlazada a esta propiedad en vez de la función añadida en OnComplete, pudiendo avisar al usuario de la incidencia.

MODIFICAR LA VISTA INDEX

Para poder hacer uso de la partial view, y  no perder la funcionalidad hasta ahora conseguida, debemos modificar la vista Movies/Index.aspx de la siguiente manera:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<MovieManager.Models.Objects.Movie>>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h2>
        Index</h2>
    <div id="divMovieList">
        <% Html.RenderPartial("MovieList"); %>
    </div>
    <p>
        <%= Html.ActionLink("Create New", "Create") %>
    </p>
</asp:Content>

Se ha añadido un elemento de tipo div, el cual contiene una llamada a Html.RenderPartial que renderizará la vista parcial que acabamos de crear.
En MovieController creamos una nueva acción para eliminar la película seleccionada.

[AcceptVerbs(HttpVerbs.Delete)]
public ActionResult Delete(int id)
{
    var movieToDelete = _movieRepository.GetMovie(id);
    _movieRepository.Delete(movieToDelete);
    returnPartialView("MovieList", _movieRepository.ListMovies());
}

Cuando recupera la película a través de NHibernate y elimina la misma, retorna el nuevo listado de películas a MovieList.

Los métodos Delete y GetMovie han sido añadidos tanto en la interfaz IMovieRepository como en su implementación, siempre en la parte del Modelo.

using System.Collections.Generic;
using MovieManager.Models.Objects;

namespace MovieManager.Models
{
    public interface IMovieRepository
    {
        IList<Movie> ListMovies();
        voidSaveMovie(Movie movieToSave);
        Movie GetMovie(intid);
        voidDelete(Movie movieToDelete);
    }
}using System.Collections.Generic;
using MovieManager.Models.Objects;
using NHibernate;
using NHibernate.Criterion;

namespace MovieManager.Models
{
    public class MovieRepository : IMovieRepository
    {
        private readonly ISessionFactory _session;

        publicMovieRepository(ISessionFactory sessionFactory)
        {
            _session = sessionFactory;
        }

        publicIList<Movie> ListMovies()
        {
            return_session.GetCurrentSession().CreateCriteria(typeof(Movie)).List<Movie>();
        }

        public void SaveMovie(Movie movieToSave)
        {
            _session.GetCurrentSession().SaveOrUpdate(movieToSave);
        }

        public Movie GetMovie(int id)
        {
            return(Movie)_session.GetCurrentSession().CreateCriteria(typeof(Movie))
                .Add(Restrictions.Like("Id", id)).UniqueResult();
        }

        publicvoidDelete(Movie movieToDelete)
        {
            _session.GetCurrentSession().Delete(movieToDelete);
        }

    }
}

Como hemos visto, podemos trabajar de una forma más simplificada con Ajax, gracias a MVC y JQuery, adaptando la aplicación de una forma poco agresiva :)

Adjunto el proyecto por si fuera de utilidad.

Microsoft está realizando una encuesta en línea para comprender su opinión del sitio web de. Si decide participar, se le presentará la encuesta en línea cuando abandone el sitio web de.

¿Desea participar?