Compartir a través de


Ordenación, filtrado y paginación con Entity Framework en una aplicación de ASP.NET MVC (3 de 10)

de Tom Dykstra

En la aplicación web de ejemplo Contoso University, se muestra cómo crear aplicaciones ASP.NET MVC 4 con Code First de Entity Framework 5 y Visual Studio 2012. Para obtener información sobre la serie de tutoriales, consulte el primer tutorial de la serie.

Nota:

Si se encuentra con un problema que no puede resolver, descargue el capítulo completado e intente reproducir el problema. Por lo general, puede encontrar la solución al problema comparando su código con el código completado. Para conocer algunos errores comunes y cómo resolverlos, consulte Errores y soluciones alternativas.

En el tutorial anterior, se implementó un conjunto de páginas web para operaciones básicas de CRUD para entidades Student. En este tutorial agregaremos la funcionalidad de ordenación, filtrado y paginación a la página de índice Students. También crearemos una página que realice agrupaciones sencillas.

En la siguiente ilustración se muestra el aspecto que tendrá la página cuando haya terminado. Los encabezados de columna son vínculos en los que el usuario puede hacer clic para ordenar las columnas correspondientes. Si se hace clic de forma consecutiva en el encabezado de una columna, el criterio de ordenación alterna entre ascendente y descendente.

Students_Index_page_with_paging

Para agregar ordenación a la página Student Index, se debe cambiar el método Index del controlador Student y agregar código a la vista Student Index.

Adición de la funcionalidad de ordenación al método Index

En Controllers\StudentController.cs, reemplace el método Index por el código siguiente:

public ActionResult Index(string sortOrder)
{
   ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name_desc" : "";
   ViewBag.DateSortParm = sortOrder == "Date" ? "Date_desc" : "Date";
   var students = from s in db.Students
                  select s;
   switch (sortOrder)
   {
      case "Name_desc":
         students = students.OrderByDescending(s => s.LastName);
         break;
      case "Date":
         students = students.OrderBy(s => s.EnrollmentDate);
         break;
      case "Date_desc":
         students = students.OrderByDescending(s => s.EnrollmentDate);
         break;
      default:
         students = students.OrderBy(s => s.LastName);
         break;
   }
   return View(students.ToList());
}

Este código recibe un parámetro sortOrder de la cadena de consulta en la dirección URL. ASP.NET MVC proporciona el valor de la cadena de consulta como un parámetro al método de acción. El parámetro es una cadena que puede ser "Name" o "Date", seguido (opcionalmente) por un guión bajo y la cadena "desc" para especificar el orden descendente. El criterio de ordenación predeterminado es el ascendente.

La primera vez que se solicita la página de índice, no hay ninguna cadena de consulta. Los alumnos se muestran en orden ascendente por LastName, que es el valor predeterminado establecido por el caso desestimado en la instrucción switch. Cuando el usuario hace clic en un hipervínculo de encabezado de columna, se proporciona el valor sortOrder correspondiente en la cadena de consulta.

Las dos variables ViewBag se usan para que la vista pueda configurar los hipervínculos de encabezado de columna con los valores de cadena de consulta adecuados:

ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name_desc" : "";
ViewBag.DateSortParm = sortOrder == "Date" ? "Date_desc" : "Date";

Estas son las instrucciones ternarias. La primera de ellas especifica que, si el parámetro sortOrder es NULL o está vacío, ViewBag.NameSortParm debe establecerse en "name_desc"; en caso contrario, se debe establecer en una cadena vacía. Estas dos instrucciones habilitan la vista para establecer los hipervínculos de encabezado de columna de la forma siguiente:

Criterio de ordenación actual Hipervínculo de apellido Hipervínculo de fecha
Apellido: ascendente descending ascending
Apellido: descendente ascending ascending
Fecha: ascendente ascending descending
Fecha: descendente ascending ascending

El método usa LINQ to Entities para especificar la columna por la que se va a ordenar. El código crea una variable IQueryable antes de la instrucción switch, la modifica en la instrucción switch y llama al método ToList después de la instrucción switch. Al crear y modificar variables IQueryable, no se envía ninguna consulta a la base de datos. La consulta no se ejecuta hasta que se convierte el objeto IQueryable en una colección mediante una llamada a un método como ToList. Por lo tanto, este código produce una única consulta que no se ejecuta hasta la instrucción return View.

En Views\Student\Index.cshtml, reemplace los elementos <tr> y <th> de la fila de encabezado por el código resaltado:

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            @Html.ActionLink("Last Name", "Index", new { sortOrder = ViewBag.NameSortParm })
        </th>
        <th>First Name
        </th>
        <th>
            @Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm })
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {

Este código usa la información de las propiedades ViewBag para configurar hipervínculos con los valores de cadena de consulta adecuados.

Ejecute la página y haga clic en los encabezados de columna Last Name y Enrollment Date para comprobar que la ordenación funciona.

Screenshot that shows the Contoso University Students Index page. The column headings are Last Name, First Name, and Enrollment Date.

Después de hacer clic en el encabezado Last Name, los alumnos se muestran según el orden descendente de los apellidos.

Screenshot that shows the Contoso University Students Index page with a list of students displayed in descending last name order.

Agregar un cuadro de búsqueda a la página de índice de Students

Para agregar filtrado a la página de índice de Students, agregue un cuadro de texto y un botón de envío a la vista y haga los cambios correspondientes en el método Index. El cuadro de texto le permite escribir la cadena que quiera buscar en los campos de nombre y apellido.

Agregar la funcionalidad de filtrado al método Index

En Controllers\StudentController.cs, reemplace el método Index por el código siguiente (los cambios están resaltados):

public ViewResult Index(string sortOrder, string searchString)
{
    ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
    ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";
    var students = from s in db.Students
                   select s;
    if (!String.IsNullOrEmpty(searchString))
    {
        students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
                               || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
    }
    switch (sortOrder)
    {
        case "name_desc":
            students = students.OrderByDescending(s => s.LastName);
            break;
        case "Date":
            students = students.OrderBy(s => s.EnrollmentDate);
            break;
        case "date_desc":
            students = students.OrderByDescending(s => s.EnrollmentDate);
            break;
        default:
            students = students.OrderBy(s => s.LastName);
            break;
    }

    return View(students.ToList());
}

Ha agregado un parámetro searchString al método Index. También ha agregado a la instrucción LINQ una cláusula where que solo selecciona los alumnos cuyo nombre o apellido contienen la cadena de búsqueda. El valor de la cadena de búsqueda se recibe de un cuadro de texto que agregará a la vista Index. La instrucción que agrega la cláusula where solo se ejecuta si hay un valor que se pueda buscar.

Nota:

En muchos casos, puede llamar al mismo método en un conjunto de entidades de Entity Framework o como un método de extensión en una colección en memoria. Los resultados suelen ser los mismos, pero en algunos casos pueden ser diferentes. Por ejemplo, la implementación de .NET Framework del método Contains devuelve todas las filas cuando se pasa una cadena vacía, pero el proveedor de Entity Framework para SQL Server Compact 4.0 devuelve cero filas para cadenas vacías. Por lo tanto, el código del ejemplo (que coloca la instrucción Where dentro de una instrucción if) asegura que obtiene los mismos resultados para todas las versiones de SQL Server. Además, la implementación de .NET Framework del método Contains realiza una comparación que distingue mayúsculas de minúsculas de forma predeterminada, pero los proveedores de SQL Server de Entity Framework realizan comparaciones que no distinguen mayúsculas de minúsculas de forma predeterminada. Por lo tanto, llamar al método ToUpper para hacer que la prueba no distinga mayúsculas de minúsculas explícitamente garantiza que los resultados no cambien cuando cambie el código más adelante para usar un repositorio, lo que devolverá una colección IEnumerable en lugar de un objeto IQueryable. (Al hacer una llamada al método Contains en una colección IEnumerable, obtendrá la implementación de .NET Framework; al hacer una llamada a un objeto IQueryable, obtendrá la implementación del proveedor de base de datos).

Agregar un cuadro de búsqueda a la vista de índice de Student

En Views\Student\Index.cshtml, agregue el código resaltado inmediatamente antes de la etiqueta de apertura table para crear un título, un cuadro de texto y un botón Buscar.

<p>
    @Html.ActionLink("Create New", "Create")
</p>

@using (Html.BeginForm())
{
    <p>
        Find by name: @Html.TextBox("SearchString")  
        <input type="submit" value="Search" /></p>
}

<table>
    <tr>

Ejecute la página, escriba una cadena de búsqueda y haga clic en Buscar para comprobar que el filtrado funciona.

Students_Index_page_with_search_box

Observe que la dirección URL no contiene la cadena de búsqueda "an", lo que significa que, si marca esta página, no obtendrá la lista filtrada cuando use el marcador. Cambiará el botón Buscar para usar cadenas de consulta para los criterios de filtro más adelante en el tutorial.

Adición de paginación a la página Students Index

Para agregar paginación a la página Students Index, comenzará instalando el paquete NuGet PagedList.Mvc. A continuación, realizará cambios adicionales en el método Index y agregará vínculos de paginación a la vista Index. PagedList.Mvc es uno de los muchos paquetes de paginación y ordenación para ASP.NET MVC, y se usa aquí solo como ejemplo, no para recomendarlo para otras opciones. La ilustración siguiente muestra los enlaces de paginación.

Screenshot of the Students Index page showing paging links.

Instalación del paquete NuGet PagedList.MVC

El paquete PagedList.Mvc de NuGet instala automáticamente el paquete PagedList como dependencia. El paquete PagedList instala un tipo de colección PagedList y métodos de extensión para las colecciones IQueryable y IEnumerable. Los métodos de extensión crean una sola página de datos en una colección PagedList de IQueryable o IEnumerable, y la colección PagedList proporciona varias propiedades y métodos que facilitan la paginación. El paquete PagedList.Mvc instala un asistente de paginación que muestra los botones de paginación.

En el menú Herramientas, seleccione Administrador de paquetes NuGet y, después, Administrar paquetes NuGet para la solución.

En el cuadro de diálogo Administrar paquetes NuGet, haga clic en la pestaña En línea de la izquierda y, a continuación, escriba "paged" en el cuadro de búsqueda. Cuando vea el paquete PagedList.Mvc, haga clic en Instalar.

Screenshot that shows the Manage N u GET Packages dialog box. The Online tab and search bar filled with the word paged are highlighted. The Paged List package is selected.

En el cuadro Seleccionar proyectos, haga clic en Aceptar.

Screenshot that shows the Select Project dialog box. The O K button is selected.

Agregar la funcionalidad de paginación al método Index

En Controllers\StudentController.cs, agregue una instrucción using para el espacio de nombres PagedList:

using PagedList;

Reemplace el método Index con el código siguiente:

public ViewResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
   ViewBag.CurrentSort = sortOrder;
   ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
   ViewBag.DateSortParm = sortOrder == "Date" ? "date_desc" : "Date";

   if (searchString != null)
   {
      page = 1;
   }
   else
   {
      searchString = currentFilter;
   }

   ViewBag.CurrentFilter = searchString;

   var students = from s in db.Students
                  select s;
   if (!String.IsNullOrEmpty(searchString))
   {
      students = students.Where(s => s.LastName.ToUpper().Contains(searchString.ToUpper())
                             || s.FirstMidName.ToUpper().Contains(searchString.ToUpper()));
   }
   switch (sortOrder)
   {
      case "name_desc":
         students = students.OrderByDescending(s => s.LastName);
         break;
      case "Date":
         students = students.OrderBy(s => s.EnrollmentDate);
         break;
      case "date_desc":
         students = students.OrderByDescending(s => s.EnrollmentDate);
         break;
      default:  // Name ascending 
         students = students.OrderBy(s => s.LastName);
         break;
   }

   int pageSize = 3;
   int pageNumber = (page ?? 1);
   return View(students.ToPagedList(pageNumber, pageSize));
}

Este código agrega un parámetro page, un parámetro de criterio de ordenación actual y un parámetro de filtro actual a la firma del método, como se muestra a continuación:

public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)

La primera vez que se muestra la página, o si el usuario no ha hecho clic en un vínculo de ordenación o paginación, todos los parámetros son nulos. Si se hace clic en un vínculo de paginación, la variable page contiene el número de página que se tiene que mostrar.

La propiedad A ViewBag proporciona la vista con el criterio de ordenación actual, ya que debe incluirse en los vínculos de paginación para mantener el criterio de ordenación durante la paginación:

ViewBag.CurrentSort = sortOrder;

Otra propiedad, ViewBag.CurrentFilter, proporciona a la vista la cadena de filtro actual. Este valor debe incluirse en los vínculos de paginación para mantener la configuración de filtrado durante la paginación y debe restaurarse en el cuadro de texto cuando se vuelve a mostrar la página. Si se cambia la cadena de búsqueda durante la paginación, la página debe restablecerse a 1, porque el nuevo filtro puede hacer que se muestren diferentes datos. La cadena de búsqueda cambia cuando se escribe un valor en el cuadro de texto y se presiona el botón enviar. En ese caso, el parámetro searchString no es NULL.

if (searchString != null)
        page = 1;
else
    searchString = currentFilter;

Al final del método, el método de extensión ToPagedList del objeto IQueryable de los alumnos convierte la consulta de alumnos en una sola página de alumnos de un tipo de colección que admite paginación. Entonces, esa única página de alumnos pasa a la vista:

int pageSize = 3;
int pageNumber = (page ?? 1);
return View(students.ToPagedList(pageNumber, pageSize));

El método ToPagedList toma un número de página. Los dos signos de interrogación representan el operador de fusión de NULL. El operador de uso combinado de NULL define un valor predeterminado para un tipo que acepta valores NULL; la expresión (page ?? 1) devuelve el valor de page si tiene algún valor o devuelve 1 si page es NULL.

En Views\Students\Index.cshtml, reemplace el código existente por el código siguiente:

@model PagedList.IPagedList<ContosoUniversity.Models.Student>
@using PagedList.Mvc; 
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />

@{
    ViewBag.Title = "Students";
}

<h2>Students</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
@using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
    <p>
        Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)  
        <input type="submit" value="Search" />
    </p>
}
<table>
<tr>
    <th></th>
    <th>
        @Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter })
    </th>
    <th>
        First Name
    </th>
    <th>
        @Html.ActionLink("Enrollment Date", "Index", new { sortOrder = ViewBag.DateSortParm, currentFilter = ViewBag.CurrentFilter })
    </th>
</tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.StudentID }) |
            @Html.ActionLink("Details", "Details", new { id=item.StudentID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.StudentID })
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.LastName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.FirstMidName)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.EnrollmentDate)
        </td>
    </tr>
}

</table>
<br />
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount

@Html.PagedListPager( Model, page => Url.Action("Index", new { page, sortOrder = ViewBag.CurrentSort, currentFilter=ViewBag.CurrentFilter }) )

La instrucción @model de la parte superior de la página especifica que ahora la vista obtiene un objeto PagedList en lugar de un objeto List.

La instrucción using para PagedList.Mvc proporciona acceso al asistente de MVC para los botones de paginación.

El código usa una sobrecarga de BeginForm que le permite especificar FormMethod.Get.

@using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
    <p>
        Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)  
        <input type="submit" value="Search" />
    </p>
}

El BeginForm predeterminado envía datos de formulario con POST, lo que significa que los parámetros se pasan en el cuerpo del mensaje HTTP y no en la dirección URL como cadenas de consulta. Al especificar HTTP GET, los datos de formulario se pasan en la dirección URL como cadenas de consulta, lo que permite que los usuarios marquen la dirección URL. Las directrices de W3C para usar HTTP GET recomiendan usar GET cuando la acción no produzca ninguna actualización.

El cuadro de texto se inicializa con la cadena de búsqueda actual, por lo que al hacer clic en una nueva página puede ver la cadena de búsqueda actual.

Find by name: @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)

Los vínculos del encabezado de la columna usan la cadena de consulta para pasar la cadena de búsqueda actual al controlador, de modo que el usuario pueda ordenar los resultados del filtro:

@Html.ActionLink("Last Name", "Index", new { sortOrder=ViewBag.NameSortParm, currentFilter=ViewBag.CurrentFilter })

Se muestran la página actual y el número total de páginas.

Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount

Si no hay páginas que mostrar, se muestra "Página 0 de 0". (En ese caso, el número de página es mayor que el recuento de páginas porque Model.PageNumber es 1 y Model.PageCount es 0).

Los botones de paginación se muestran mediante el asistente de PagedListPager:

@Html.PagedListPager( Model, page => Url.Action("Index", new { page }) )

El asistente PagedListPager proporciona una serie de opciones que puede personalizar, incluidas las direcciones URL y el estilo. Para obtener más información, consulte TroyGoode / PagedList en el sitio de GitHub.

Ejecute la página.

Screenshot of the Students Index page.

Haga clic en los vínculos de paginación en distintos criterios de ordenación para comprobar que la paginación funciona correctamente. A continuación, escriba una cadena de búsqueda e intente llevar a cabo la paginación de nuevo, para comprobar que la paginación también funciona correctamente con filtrado y ordenación.

Screenshot that shows the Students Index page. The word an is entered in the Find by name search bar.

Creación de una página About que muestra las estadísticas de los alumnos

En la página About del sitio web de Contoso University, se muestran cuántos alumnos se han inscrito en cada fecha de inscripción. Esto requiere realizar agrupaciones y cálculos sencillos en los grupos. Para conseguirlo, haga lo siguiente:

  • Cree una clase de modelo de vista para los datos que necesita pasar a la vista.
  • Modifique el método About en el controlador Home.
  • Modifique la vista About.

Creación del modelo de vista

Cree una carpeta ViewModels. En esa carpeta, agregue un archivo de clase EnrollmentDateGroup.cs y reemplace el código existente por el código siguiente:

using System;
using System.ComponentModel.DataAnnotations;

namespace ContosoUniversity.ViewModels
{
    public class EnrollmentDateGroup
    {
        [DataType(DataType.Date)]
        public DateTime? EnrollmentDate { get; set; }

        public int StudentCount { get; set; }
    }
}

Modificación del controlador Home

En HomeController.cs, agregue las siguientes instrucciones using en la parte superior del archivo:

using ContosoUniversity.DAL;
using ContosoUniversity.ViewModels;

Agregue una variable de clase para el contexto de base de datos inmediatamente después de la llave de apertura de la clase:

public class HomeController : Controller
{
    private SchoolContext db = new SchoolContext();

Reemplace el método About con el código siguiente:

public ActionResult About()
{
    var data = from student in db.Students
               group student by student.EnrollmentDate into dateGroup
               select new EnrollmentDateGroup()
               {
                   EnrollmentDate = dateGroup.Key,
                   StudentCount = dateGroup.Count()
               };
    return View(data);
}

La instrucción LINQ agrupa las entidades de alumnos por fecha de inscripción, calcula la cantidad de entidades que se incluyen en cada grupo y almacena los resultados en una colección de objetos de modelo de la vista EnrollmentDateGroup.

Agregue un método Dispose:

protected override void Dispose(bool disposing)
{
    db.Dispose();
    base.Dispose(disposing);
}

Modificación de la vista About

Reemplace el código del archivo Views/Home/About.cshtml por el código siguiente:

@model IEnumerable<ContosoUniversity.ViewModels.EnrollmentDateGroup>
           
@{
    ViewBag.Title = "Student Body Statistics";
}

<h2>Student Body Statistics</h2>

<table>
    <tr>
        <th>
            Enrollment Date
        </th>
        <th>
            Students
        </th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.EnrollmentDate)
        </td>
        <td>
            @item.StudentCount
        </td>
    </tr>
}
</table>

Ejecute la aplicación y haga clic en el vínculo Acerca de. En una tabla se muestra el número de alumnos para cada fecha de inscripción.

About_page

Opcional: Implementación de la aplicación en Windows Azure

Hasta ahora, la aplicación se ha ejecutado localmente en IIS Express en el proceso de desarrollo. Para que esté disponible para que otras personas la usen a través de Internet, debe implementarla en un proveedor de hospedaje web. En esta sección opcional del tutorial, la implementará en un sitio web de Windows Azure.

Uso de Migraciones de Code First para implementar la base de datos

Para implementar la base de datos, usará Migraciones de Code First. Al crear el perfil de publicación que se usa para configurar las opciones de implementación desde Visual Studio, activará una casilla con la etiqueta Ejecutar Migraciones de Code First (se ejecuta en el inicio de la aplicación). Esta configuración hace que el proceso de implementación configure automáticamente el archivo Web.config de la aplicación en el servidor de destino para que Code First utilice la clase de inicializador MigrateDatabaseToLatestVersion.

Visual Studio no hace nada con la base de datos durante el proceso de implementación. Cuando la aplicación implementada accede a la base de datos por primera vez después de la implementación, Code First crea automáticamente la base de datos o actualiza el esquema de la base de datos a la versión más reciente. Si la aplicación implementa un método Seed de Migraciones, el método se ejecuta tras la creación de la base de datos o la actualización del esquema.

El método Seed de Migraciones inserta datos de prueba. Si estuviera implementando en un entorno de producción, tendría que cambiar el método Seed para que solo inserte los datos que desea insertar en la base de datos de producción. Por ejemplo, en el modelo de datos actual, es posible que quiera tener cursos reales pero estudiantes ficticios en la base de datos de desarrollo. Puede escribir un método Seed para cargar ambos en desarrollo, y después marcar como comentario los alumnos ficticios antes de implementar en producción. O bien, puede escribir un método Seed para cargar solo cursos y escribir manualmente los alumnos ficticios en la base de datos de prueba mediante la interfaz de usuario de la aplicación.

Obtención de una cuenta de Windows Azure

Necesitará una cuenta de Windows Azure. Si aún no tiene una, puede crear una cuenta de evaluación gratuita en un par de minutos. Para obtener información detallada, consulta Evaluación gratuita de Microsoft Azure.

Creación de un sitio web y una base de datos SQL en Windows Azure

El sitio web de Windows Azure se ejecutará en un entorno de hospedaje compartido, lo que significa que se ejecuta en máquinas virtuales (VM) que se comparten con otros clientes de Windows Azure. Los entornos de hospedaje compartidos ofrecen un coste reducido a los nuevos usuarios de servicios en la nube. Más adelante, si el tráfico web aumenta, es posible escalar la aplicación para atender la demanda ejecutándola en máquinas virtuales dedicadas. Si necesita una arquitectura más compleja, puede migrar a un servicio en la nube de Windows Azure. Los servicios en la nube se ejecutan en MV dedicadas que se pueden configurar según sus necesidades.

Windows Azure SQL Database es un servicio de base de datos relacional basado en la nube que se desarrolla a partir de las tecnologías de SQL Server. Las herramientas y aplicaciones que funcionan con SQL Server también lo hacen con SQL Database.

  1. En el Portal de administración de Windows Azure, haga clic en Sitios web en la pestaña izquierda y, a continuación, haga clic en Nuevo.

    New button in Management Portal

  2. Haga clic en CUSTOM CREATE (Creación personalizada).

    Screenshot that shows the New dialog box. The Web Site and Custom Create options are highlighted.

    Se abre el asistente New Web Site - Custom Create (Nuevo sitio web- Crear personalizado).

  3. En el paso New Web Site (Sitio web nuevo) del asistente, escriba una cadena en el cuadro URL que se usará como dirección URL única para la aplicación. La URL completa consistirá en el valor que escriba más el sufijo que aparece junto al cuadro de texto. En la ilustración se muestra "ConU", pero es probable que esa dirección URL esté cogida, de modo que tendrá que elegir una diferente.

    Create with Database link in Management Portal

  4. En la lista desplegable Region (Región), elija una región cercana a la suya. Esta configuración especifica en qué centro de datos se ejecutará el sitio web.

  5. En la lista desplegable Database (Base de datos), elija Create a free 20 MB SQL database (Crear una base de datos SQL gratuita de 20 MB).

    Screenshot that shows the Create Web Site dialog box. In the database dropdown list, Choose a free 20 M B S Q L database is selected. The check mark button is highlighted.

  6. En DB CONNECTION STRING NAME (Nombre de cadena de conexión de base de datos), escriba SchoolContext.

    Screenshot that shows the Create Web Site dialog box. School Context is filled in the D B Connection String Name text field. The check mark button is highlighted.

  7. Haga clic en la flecha que apunta a la derecha en la parte inferior del cuadro. El asistente avanza al paso Database Settings (Configuración de base de datos).

  8. En el cuadro Name (Nombre), escriba ContosoUniversityDB.

  9. En el cuadro Server (Servidor), seleccione New SQL Database server (Nuevo servidor de SQL Database). Alternativamente, si ha creado previamente un servidor, puede seleccionar ese servidor en la lista desplegable.

  10. Escriba el LOGIN NAME (Nombre de usuario) y la PASSWORD (Contraseña). Si seleccionó Nuevo servidor de SQL Database , no debe escribir un nombre y una contraseña existentes en estos campos, sino definir unos nuevos que volverá a utilizar más adelante para obtener acceso a la base de datos. Si seleccionó un servidor que creó anteriormente, escriba las credenciales de ese servidor. En este tutorial, no activará la casilla Avanzado. Las opciones avanzadas le permiten establecer la intercalación de la base de datos.

  11. Elija la misma Región que haya elegido para el sitio web.

  12. Haga clic en la marca de verificación situada en la parte inferior derecha de la casilla para indicar que ha terminado.

    Screenshot that shows the Specify database settings dialog box with all settings selected and a sample password included in text fields. The check mark button is highlighted.

    En la imagen siguiente se muestra el uso de un servidor SQL Server existente y un inicio de sesión.

    Database Settings step of New Web Site - Create with Database wizard

    El Portal de administración vuelve a la página Web Sites y en la columna Status (Estado) se muestra que se está creando el sitio. Después de un tiempo (normalmente menos de un minuto), en la columna Status (Estado) se muestra que el sitio se ha creado correctamente. En la barra de navegación de la izquierda, el número de sitios que tiene en la cuenta aparece junto al icono Web Sites y el número de bases de datos aparece junto al icono SQL Databases.

Implementación de la aplicación en Windows Azure

  1. En Visual Studio, haga clic con el botón derecho en el proyecto, en el Explorador de soluciones y seleccione Publicar en el menú contextual.

    Publish in project context menu

  2. En la pestaña Profile (Perfil) del asistente Publish Web (Publicar web), haga clic en Import (Importar).

    Import publish settings

  3. Si no ha agregado previamente la suscripción de Windows Azure en Visual Studio, siga estos pasos. En estos pasos, agregará la suscripción para que la lista desplegable debajo de Import from a Windows Azure web site (Importar desde un sitio web de Windows Azure) incluya el sitio web.

    a. En el cuadro de diálogo Import Publish Profile (Importar perfil de publicación), haga clic en Import from a Windows Azure web site (Importar desde un sitio web de Windows Azure) y, a continuación, haga clic en Add Windows Azure subscription (Agregar suscripción de Windows Azure).

    add Windows Azure subscription

    b. En el cuadro de diálogo Import Windows Azure Subscriptions (Importar suscripciones de Windows Azure), haga clic en Download subscription file (Descargar archivo de suscripción).

    download subscription file

    c. En la ventana del explorador, guarde el archivo .publishsettings.

    download .publishsettings file

    Advertencia

    Seguridad: el archivo .publishsettings contiene las credenciales (sin codificar) que se usan para administrar los servicios y suscripciones de Windows Azure. El procedimiento recomendado de seguridad para este archivo es almacenarlo temporalmente fuera de los directorios de origen (por ejemplo, en la carpeta Libraries\Documents) y, a continuación, eliminarlo una vez completada la importación. Un usuario malintencionado que consiga acceso al archivo .publishsettings puede editar, crear y eliminar los servicios de Windows Azure.

    d. En el cuadro de diálogo Import Windows Azure Subscriptions (Importar suscripciones de Windows Azure), haga clic en Browse (Examinar) y vaya al archivo .publishsettings.

    download sub

    e. Haga clic en Import.

    import

  4. En el cuadro de diálogo Import Publish Profile (Importar perfil de publicación), seleccione Import from a Windows Azure web site (Importar desde un sitio web de Windows Azure), seleccione el sitio web en la lista desplegable y, a continuación, haga clic en OK (Aceptar).

    Import Publish Profile

  5. En la pestaña Connection (Conexión), haga clic en Validate Connection (Validar conexión) para asegurarse de que la configuración es correcta.

    Validate connection

  6. Cuando se haya validado la conexión, se muestra una marca de verificación verde junto al botón Validate Connection (Validar conexión). Haga clic en Next.

    Successfully validated connection

  7. Abra la lista desplegable Remote connection string (Cadena de conexión remota) en SchoolContext y seleccione la cadena de conexión de la base de datos que creó.

  8. Seleccione Ejecutar Migraciones de Code First (se ejecuta al iniciarse la aplicación).

  9. DesactiveUse this connection string at runtime (Usar esta cadena de conexión en tiempo de ejecución) para UserContext (DefaultConnection), ya que esta aplicación no usa la base de datos de pertenencia.

    Settings tab

  10. Haga clic en Next.

  11. En la pestaña Preview (Vista previa), haga clic en Start Preview (Iniciar vista previa).

    StartPreview button in the Preview tab

    La pestaña muestra una lista de los archivos que se copiarán en el servidor. No es necesario mostrar la vista previa para publicar la aplicación, pero es una función útil para tener en cuenta. En este caso, no es necesario hacer nada con la lista de archivos que se muestran. La próxima vez que implemente esta aplicación, solo los archivos que han cambiado estarán en esta lista.

    StartPreview file output

  12. Haga clic en Publicar.
    Visual Studio comienza el proceso de copiar los archivos en el servidor de Windows Azure.

  13. La ventana Salida muestra qué acciones de implementación se realizaron e informa de la correcta finalización de la implementación.

    Output window reporting successful deployment

  14. Tras una implementación correcta, el explorador predeterminado se abre automáticamente en la dirección URL del sitio web implementado.
    La aplicación creada ahora se ejecuta en la nube. Haga clic en la pestaña Students (Alumnos).

    Students_index_page_with_paging

En este punto, la base de datos SchoolContext se ha creado en la base de datos de Windows Azure SQL Database porque ha seleccionado Ejecutar Migraciones de Code First (se ejecuta al iniciar la aplicación). El archivo Web.config del sitio web implementado se ha cambiado para que el inicializador MigrateDatabaseToLatestVersion se ejecute la primera vez que su código lea o escriba datos en la base de datos (lo que ocurrió cuando seleccionó la pestaña Students (Alumnos)):

Screenshot of the code with Migrate Database To Latest Version highlighted.

El proceso de implementación también creó una nueva cadena de conexión (SchoolContext_DatabasePublish) para que las Migraciones de Code First la usaran para actualizar el esquema de la base de datos y propagarla.

Database_Publish connection string

La cadena de conexión DefaultConnection es para la base de datos de pertenencia (que no se usa en este tutorial). La cadena de conexión SchoolContext es para la base de datos ContosoUniversity.

Puede encontrar la versión implementada del archivo Web.config en su propio equipo en ContosoUniversity\obj\Release\Package\PackageTmp\Web.config. Puede acceder al propio archivo Web.config implementado usando FTP. Para obtener instrucciones, vea Implementación web de ASP.NET usando Visual Studio: Implementación de una actualización de código. Siga las instrucciones que comienzan con "Para usar una herramienta FTP, necesita tres cosas: la URL de FTP, el nombre de usuario y la contraseña".

Nota:

La aplicación web no implementa la seguridad, por lo que cualquiera que encuentre la URL puede cambiar los datos. Para obtener instrucciones sobre cómo proteger el sitio web, consulte Implementación de una aplicación MVC de ASP.NET segura con Pertenencia, OAuth y base de datos SQL en un sitio web de Windows Azure. Puede evitar que otras personas usen el sitio deteniendo el servicio mediante el Portal de administración de Windows Azure o el Explorador de servidores en Visual Studio.

Screenshot of Server Explorer that shows The Windows Azure Website tab expanded and Con U below it selected. A dialog menu with the option Stop Web Site is highlighted.

Inicializadores de Code First

En la sección de implementación, ha visto que se está usando el inicializador MigrateDatabaseToLatestVersion. Code First también proporciona otros inicializadores que puede utilizar, incluyendo CreateDatabaseIfNotExists (el predeterminado), DropCreateDatabaseIfModelChanges y DropCreateDatabaseAlways. El inicializador DropCreateAlways puede ser útil para configurar condiciones para pruebas unitarias. También puede escribir sus propios inicializadores, y puede llamar a un inicializador explícitamente si no quiere esperar a que la aplicación lea de la base de datos o escriba en ella. Para obtener una explicación completa de los inicializadores, vea el capítulo 6 del libro Programming Entity Framework: Code First de Julie Lerman y Rowan Miller.

Resumen

En este tutorial ha visto cómo crear un modelo de datos e implementar CRUD básico, ordenar, filtrar, paginar y agrupar funcionalidades. En el siguiente, comenzará examinando temas más avanzados expandiendo el modelo de datos.

En el mapa de contenido de acceso a datos de ASP.NET se pueden encontrar vínculos a otros recursos de Entity Framework.