Tutorial: Uso de migraciones de EF en una aplicación MVC de ASP.NET e implementación en Azure

Hasta ahora, la aplicación web de muestra de Contoso University se ha estado ejecutando localmente en IIS Express en su equipo de desarrollo. Para que una aplicación real esté disponible para que otras personas la usen a través de Internet, debe tenerla implementada en un proveedor de hospedaje web. En este tutorial, habilitará las migraciones de Code First e implementará la aplicación en la nube en Azure:

  • Habilitar las migraciones de Code First. La característica Migraciones permite cambiar el modelo de datos e implementar los cambios en producción mediante la actualización del esquema de la base de datos sin tener que quitar y volver a crear la base de datos.
  • Implementación en Azure. Este paso es opcional; puede continuar con el resto de tutoriales sin haber implementado el proyecto.

Le recomendamos que use un proceso de integración continua con control de código fuente para la implementación, pero este tutorial no cubre esos temas. Para más información, consulte los capítulos de control de código fuente e integración continua de Compilar aplicaciones en la nube del mundo real con Azure.

En este tutorial, hizo lo siguiente:

  • Habilitación de migraciones de Code First
  • Implementación de la aplicación en Azure (opcional)

Requisitos previos

Habilitación de migraciones de Code First

Al desarrollar una aplicación nueva, el modelo de datos cambia con frecuencia y, cada vez que lo hace, se deja de sincronizar con la base de datos. Ha configurado Entity Framework para quitar y volver a crear automáticamente la base de datos cada vez que cambie el modelo de datos. Cuando agregue, elimine o cambie las clases de entidad o cambie su clase de DbContext, la próxima vez que ejecute la aplicación, se eliminará automáticamente la base de datos existente, se creará una nueva que coincida con el modelo y se propagará con los datos de prueba.

Este método para mantener la base de datos sincronizada con el modelo de datos funciona bien hasta que la aplicación se implemente en producción. Cuando la aplicación se ejecuta en producción, normalmente almacena los datos que le interesa mantener y no querrá perderlo todo cada vez que realice un cambio, como al agregar una columna nueva. La característica Migraciones de Code First resuelve este problema habilitando a Code First para que actualice el esquema de la base de datos en lugar de anularla y volver a crearla. En este tutorial, implementará la aplicación y, para prepararse, habilitará las Migraciones.

  1. Deshabilite el inicializador que configuró anteriormente marcando como comentario o eliminando el elemento contexts que agregó al archivo Web.config de la aplicación.

    <entityFramework>
      <!--<contexts>
        <context type="ContosoUniversity.DAL.SchoolContext, ContosoUniversity">
          <databaseInitializer type="ContosoUniversity.DAL.SchoolInitializer, ContosoUniversity" />
        </context>
      </contexts>-->
      <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
        <parameters>
          <parameter value="v11.0" />
        </parameters>
      </defaultConnectionFactory>
      <providers>
        <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      </providers>
    </entityFramework>
    
  2. También en el archivo Web.config de la aplicación, cambie el nombre de la base de datos en la cadena de conexión a ContosoUniversity2.

    <connectionStrings>
      <add name="SchoolContext" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=ContosoUniversity2;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
    </connectionStrings>
    

    Este cambio configura el proyecto para que la primera migración cree una base de datos. Esto no es necesario, pero más adelante verá por qué es una buena idea.

  3. En el menú Herramientas, seleccione Administrador de paquetes NuGet>Consola del Administrador de paquetes.

  4. En la solicitud de PM> escriba los siguientes comandos:

    enable-migrations
    add-migration InitialCreate
    

    El comando enable-migrations crea una carpeta Migrations (Migraciones) en el proyecto ContosoUniversity, y coloca en esa carpeta un archivo Configuration.cs que puede editar para configurar las Migraciones.

    (Si se ha saltado el paso anterior que le indica que cambie el nombre de la base de datos, Migraciones encontrará la base de datos existente y realizará automáticamente el comando add-migration. No pasa nada, solo significa que no realizará una prueba del código de las migraciones antes de implementar la base de datos. Más adelante, cuando ejecute el comando update-database no ocurrirá nada porque la base de datos ya existe).

    Abra el archivo ContosoUniversity\Migrations\Configuration.cs. Al igual que la clase de inicializador que ha visto antes, la clase Configuration incluye un método Seed.

    internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }
    
        protected override void Seed(ContosoUniversity.DAL.SchoolContext context)
        {
            //  This method will be called after migrating to the latest version.
    
            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
    

    El objetivo del método Seed es permitirle insertar o actualizar datos de prueba después de que Code First cree o actualice la base de datos. Se llama al método cuando se crea la base de datos y cada vez que se actualiza el esquema de la base de datos después de cambiar un modelo de datos.

Configuración del método Seed

Cuando se anula y se vuelve a crear la base de datos por cada cambio en el modelo de datos, se usa el método Seed de la clase de inicializador para insertar los datos de prueba, ya que después de cada cambio de modelo se anula la base de datos y se pierden todos los datos de prueba. Con Migraciones de Code First, los datos de prueba se conservan tras los cambios en la base de datos, por lo que incluir datos de prueba en el método Seed no suele ser necesario. De hecho, no querrá que el método Seed inserte datos de prueba si va a usar Migraciones para implementar la base de datos en producción, porque el método Seed se ejecutará en producción. En ese caso, querrá que el método Seed inserte en la base de datos solo los datos que necesite en producción. Por ejemplo, puede querer que la base de datos incluya los nombres reales de los departamentos en la tabla Department cuando la aplicación esté disponible en producción.

Para este tutorial, usará Migraciones para la implementación, pero su método Seed insertará datos de prueba de todos modos para que sea más fácil ver cómo funciona la funcionalidad de la aplicación sin tener que insertar manualmente un montón de datos.

  1. Reemplace el contenido del archivo Configuration.cs por el código siguiente, que carga los datos de prueba en la nueva base de datos.

    namespace ContosoUniversity.Migrations
    {
        using ContosoUniversity.Models;
        using System;
        using System.Collections.Generic;
        using System.Data.Entity;
        using System.Data.Entity.Migrations;
        using System.Linq;
    
        internal sealed class Configuration : DbMigrationsConfiguration<ContosoUniversity.DAL.SchoolContext>
        {
            public Configuration()
            {
                AutomaticMigrationsEnabled = false;
            }
    
            protected override void Seed(ContosoUniversity.DAL.SchoolContext context)
            {
                var students = new List<Student>
                {
                    new Student { FirstMidName = "Carson",   LastName = "Alexander", 
                        EnrollmentDate = DateTime.Parse("2010-09-01") },
                    new Student { FirstMidName = "Meredith", LastName = "Alonso",    
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Arturo",   LastName = "Anand",     
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Gytis",    LastName = "Barzdukas", 
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Yan",      LastName = "Li",        
                        EnrollmentDate = DateTime.Parse("2012-09-01") },
                    new Student { FirstMidName = "Peggy",    LastName = "Justice",   
                        EnrollmentDate = DateTime.Parse("2011-09-01") },
                    new Student { FirstMidName = "Laura",    LastName = "Norman",    
                        EnrollmentDate = DateTime.Parse("2013-09-01") },
                    new Student { FirstMidName = "Nino",     LastName = "Olivetto",  
                        EnrollmentDate = DateTime.Parse("2005-08-11") }
                };
                students.ForEach(s => context.Students.AddOrUpdate(p => p.LastName, s));
                context.SaveChanges();
    
                var courses = new List<Course>
                {
                    new Course {CourseID = 1050, Title = "Chemistry",      Credits = 3, },
                    new Course {CourseID = 4022, Title = "Microeconomics", Credits = 3, },
                    new Course {CourseID = 4041, Title = "Macroeconomics", Credits = 3, },
                    new Course {CourseID = 1045, Title = "Calculus",       Credits = 4, },
                    new Course {CourseID = 3141, Title = "Trigonometry",   Credits = 4, },
                    new Course {CourseID = 2021, Title = "Composition",    Credits = 3, },
                    new Course {CourseID = 2042, Title = "Literature",     Credits = 4, }
                };
                courses.ForEach(s => context.Courses.AddOrUpdate(p => p.Title, s));
                context.SaveChanges();
    
                var enrollments = new List<Enrollment>
                {
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").ID, 
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
                        Grade = Grade.A 
                    },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").ID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID, 
                        Grade = Grade.C 
                     },                            
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Alexander").ID,
                        CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID, 
                        Grade = Grade.B
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").ID,
                        CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                         StudentID = students.Single(s => s.LastName == "Alonso").ID,
                        CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment {
                        StudentID = students.Single(s => s.LastName == "Alonso").ID,
                        CourseID = courses.Single(c => c.Title == "Composition" ).CourseID, 
                        Grade = Grade.B 
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").ID,
                        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Anand").ID,
                        CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
                        Grade = Grade.B         
                     },
                    new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Barzdukas").ID,
                        CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Li").ID,
                        CourseID = courses.Single(c => c.Title == "Composition").CourseID,
                        Grade = Grade.B         
                     },
                     new Enrollment { 
                        StudentID = students.Single(s => s.LastName == "Justice").ID,
                        CourseID = courses.Single(c => c.Title == "Literature").CourseID,
                        Grade = Grade.B         
                     }
                };
    
                foreach (Enrollment e in enrollments)
                {
                    var enrollmentInDataBase = context.Enrollments.Where(
                        s =>
                             s.Student.ID == e.StudentID &&
                             s.Course.CourseID == e.CourseID).SingleOrDefault();
                    if (enrollmentInDataBase == null)
                    {
                        context.Enrollments.Add(e);
                    }
                }
                context.SaveChanges();
            }
        }
    }
    

    El método Seed toma el objeto de contexto de base de datos como parámetro de entrada y el código del método usa ese objeto para agregar nuevas entidades a la base de datos. Para cada tipo de entidad, el código crea una colección de entidades nuevas, las agrega a la propiedad DbSet adecuada y, a continuación, guarda los cambios en la base de datos. No es necesario llamar al método SaveChanges después de cada grupo de entidades, como se hace aquí, pero hacerlo le ayuda a localizar el origen de un problema si se produce una excepción mientras el código está escribiendo en la base de datos.

    Algunas de las instrucciones que insertan datos usan el método AddOrUpdate para realizar una operación "upsert". Dado que el método Seed se ejecuta cada vez que se ejecuta el comando update-database, normalmente después de cada migración, no puede insertar datos sin más, porque las filas que intenta agregar ya estarán ahí después de la primera migración que crea la base de datos. La operación "upsert" evita los errores que se producirían si intentara insertar una fila que ya existe, pero invalida cualquier cambio en los datos que haya podido realizar mientras probaba la aplicación. Con los datos de prueba de algunas tablas puede que no quiera que eso ocurra: en algunos casos, cuando cambia los datos durante las pruebas, quiere que sus cambios permanezcan tras las actualizaciones de la base de datos. En ese caso, querrá realizar una operación de inserción condicional: insertar una fila solo si aún no existe. El método Seed usa ambos enfoques.

    El primer parámetro que se pasa al método AddOrUpdate especifica la propiedad que se usará para comprobar si ya existe una fila. Para los datos de alumnos de prueba que está proporcionando, se puede usar la propiedad LastName para este fin, ya que cada apellido de la lista es único:

    context.Students.AddOrUpdate(p => p.LastName, s)
    

    Este código asume que los apellidos son únicos. Si agrega manualmente un alumno con un apellido duplicado, obtendrá la siguiente excepción la próxima vez que realice una migración:

    La secuencia contiene más de un elemento

    Para obtener información sobre cómo controlar datos redundantes como, por ejemplo, dos alumnos llamados "Alexander Carson", consulte Propagación y depuración de bases de datos de Entity Framework (EF) en el blog de Rick Anderson. Para más información sobre el método AddOrUpdate, consulte Cuidado con el método AddOrUpdate de EF 4.3 en el blog de Julie Lerman.

    El código que crea las entidades de Enrollment asume que usted tiene el valor ID en las entidades de la colección students, aunque no haya establecido esa propiedad en el código que crea la colección.

    new Enrollment { 
        StudentID = students.Single(s => s.LastName == "Alexander").ID, 
        CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID, 
        Grade = Grade.A 
    },
    

    Puede usar la propiedad ID aquí porque el valor de ID se establece al llamar a SaveChanges para la colección students. EF obtiene automáticamente el valor de la clave principal cuando inserta una entidad en la base de datos, y actualiza la propiedad ID de la entidad en memoria.

    El código que agrega cada entidad Enrollment al conjunto de entidades Enrollments no usa el método AddOrUpdate. Comprueba si ya existe una entidad e inserta la entidad si no existe. Este enfoque preservará los cambios que realice en una calificación de inscripción usando la interfaz de usuario de la aplicación. El código recorre en bucle cada uno de los miembros de la ListaEnrollment y, si la inscripción no se encuentra en la base de datos, la agrega a la misma. La primera vez que actualice la base de datos, la base de datos estará vacía, por lo que agregará cada inscripción.

    foreach (Enrollment e in enrollments)
    {
        var enrollmentInDataBase = context.Enrollments.Where(
            s => s.Student.ID == e.Student.ID &&
                 s.Course.CourseID == e.Course.CourseID).SingleOrDefault();
        if (enrollmentInDataBase == null)
        {
            context.Enrollments.Add(e);
        }
    }
    
  2. Compile el proyecto.

Ejecución de la primera migración

Cuando ejecutó el comando add-migration, Migraciones generó el código que crearía la base de datos desde cero. Este código también se encuentra en la carpeta Migrations, en el archivo llamado <timestamp>_InitialCreate.cs. El método Up de la clase InitialCreate crea las tablas de base de datos que corresponden a los conjuntos de entidades del modelo de datos y el método Down las elimina.

public partial class InitialCreate : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.Course",
            c => new
                {
                    CourseID = c.Int(nullable: false),
                    Title = c.String(),
                    Credits = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.CourseID);
        
        CreateTable(
            "dbo.Enrollment",
            c => new
                {
                    EnrollmentID = c.Int(nullable: false, identity: true),
                    CourseID = c.Int(nullable: false),
                    StudentID = c.Int(nullable: false),
                    Grade = c.Int(),
                })
            .PrimaryKey(t => t.EnrollmentID)
            .ForeignKey("dbo.Course", t => t.CourseID, cascadeDelete: true)
            .ForeignKey("dbo.Student", t => t.StudentID, cascadeDelete: true)
            .Index(t => t.CourseID)
            .Index(t => t.StudentID);
        
        CreateTable(
            "dbo.Student",
            c => new
                {
                    ID = c.Int(nullable: false, identity: true),
                    LastName = c.String(),
                    FirstMidName = c.String(),
                    EnrollmentDate = c.DateTime(nullable: false),
                })
            .PrimaryKey(t => t.ID);
        
    }
    
    public override void Down()
    {
        DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
        DropForeignKey("dbo.Enrollment", "CourseID", "dbo.Course");
        DropIndex("dbo.Enrollment", new[] { "StudentID" });
        DropIndex("dbo.Enrollment", new[] { "CourseID" });
        DropTable("dbo.Student");
        DropTable("dbo.Enrollment");
        DropTable("dbo.Course");
    }
}

Las migraciones llaman al método Up para implementar los cambios del modelo de datos para una migración. Cuando se escribe un comando para revertir la actualización, las migraciones llaman al método Down.

Esto es para la migración inicial que se creó cuando se escribió el comando add-migration InitialCreate. El parámetro (InitialCreate en el ejemplo) se usa para el nombre del archivo y puede ser el que usted quiera; normalmente se elige una palabra o frase que resuma lo que se está haciendo en la migración. Por ejemplo, podría denominar "AddDepartmentTable" a una migración posterior.

Si creó la migración inicial cuando la base de datos ya existía, se genera el código de creación de la base de datos pero no es necesario ejecutarlo porque la base de datos ya coincide con el modelo de datos. Al implementar la aplicación en otro entorno donde la base de datos todavía no existe, se ejecutará este código para crear la base de datos, por lo que es recomendable probarlo primero. Por ese motivo se cambió antes el nombre de la base de datos en la cadena de conexión, para que las migraciones puedan crear uno desde cero.

  1. En la ventana Consola del Administrador de paquetas , escriba el siguiente comando:

    update-database

    El comando update-database ejecuta el método Up para crear la base de datos y, a continuación, ejecuta el método Seed para rellenar la base de datos. El mismo proceso se ejecutará automáticamente en producción después de implementar la aplicación, como verá en la sección siguiente.

  2. Use el Explorador de servidores para inspeccionar la base de datos como hizo en el primer tutorial y ejecute la aplicación para comprobar que todo sigue funcionando igual que antes.

Implementación en Azure

Hasta ahora, la aplicación se ha ejecutado localmente en IIS Express en el equipo 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 del tutorial, la implementará en Azure. Esta sección es opcional; puede omitirla y continuar con el siguiente tutorial, o puede adaptar las instrucciones de esta sección para otro proveedor de hospedaje de su elección.

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 Actualizar base de datos. 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 mientras copia el proyecto en el servidor de destino. Cuando ejecute la aplicación implementada y esta acceda a la base de datos por primera vez tras la implementación, Code First comprobará si la base de datos coincide con el modelo de datos. Si hay un error de coincidencia, Code First crea automáticamente la base de datos (si aún no existe) o actualiza el esquema de la base de datos a la versión más reciente (si existe una base de datos pero no coincide con el modelo). 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 Azure

Necesitará una cuenta de Azure. Si aún no tiene una, pero tiene una suscripción de Visual Studio, puede activar las ventajas de la suscripción. De lo contrario, puede crear una cuenta de evaluación gratuita en tan solo un par de minutos. Para obtener más información, consulte Evaluación gratuita de Azure.

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

La aplicación web de 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 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. Para más información sobre las opciones de precios de Azure App Service, lea Precios de Azure App Service.

La implementación se realizará en la base de datos de Azure SQL. La base de datos SQL 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 la base de datos SQL.

  1. En el Portal de administración de Azure, seleccione Crear un recurso en la pestaña izquierda y después seleccione Ver todos en el panel (u hoja) Nuevo para ver todos los recursos disponibles. Seleccione Aplicación web + SQL en la sección Web de la hoja Todo. Por último, elija Crear.

    Create a resource in Azure portal

    Se abre el formulario para crear un nuevo recurso Nueva aplicación web + SQL.

  2. Escriba una cadena en el cuadro Nombre de la aplicación para usarla como URL única de su aplicación. La URL completa estará formada por lo que escriba aquí más el dominio predeterminado de Azure App Services (.azurewebsites.net). Si el nombre de la aplicación ya está ocupado, el asistente se lo notificará con un mensaje en rojo El nombre de la aplicación no está disponible. Si el nombre de la aplicación está disponible, verá una marca de verificación verde.

  3. En el cuadro Suscripción, elija la Suscripción de Azure en la que quiere que resida App Service.

  4. En el cuadro de texto Grupo de recursos, elija un grupo de recursos o cree uno nuevo. Esta configuración especifica en qué centro de datos se ejecutará el sitio web. Para más información sobre los grupos de recursos, consulte Grupos de recursos.

  5. Cree un nuevo Plan de App Service haciendo clic en la sección App Service, Crear nuevo, y rellene Plan de App Service (puede ser el mismo nombre que App Service), Ubicación y Nivel de precios (hay una opción gratuita).

  6. Haga clic en SQL Database, y después seleccione Crear una nueva base de datos o seleccione una base de datos existente.

  7. En el cuadro Nombre, escriba un nombre para su base de datos.

  8. Haga clic en el cuadro Servidor de destino y después seleccione Crear un nuevo servidor. Alternativamente, si ha creado previamente un servidor, puede seleccionar ese servidor de la lista de servidores disponibles.

  9. Elija la sección Plan de tarifa, elija Gratis. Si se necesitan recursos adicionales, la base de datos se puede escalar verticalmente en cualquier momento. Para más información sobre los precios de Azure SQL, consulte Precios de Azure SQL Database.

  10. Modifique la intercalación según sea necesario.

  11. Escriba un nombre de usuario de Administrador de SQL y una contraseña de Administrador de SQL.

    • Si ha seleccionado Nuevo servidor de SQL Database, defina un nuevo nombre y contraseña que usará más adelante cuando acceda a la base de datos.
    • Si seleccionó un servidor que creó anteriormente, escriba las credenciales de ese servidor.
  12. La colección de telemetría puede habilitarse para App Service usando Application Insights. Con poca configuración, Application Insights recopila valiosa información sobre eventos, excepciones, dependencias, solicitudes y seguimiento. Para más información sobre Application Insights, consulte Azure Monitor.

  13. Haga clic en Crear en la parte inferior para indicar que ha terminado.

    El Portal de administración vuelve a la página del panel y el área de Notificaciones de la parte superior de la página muestra que se está creando el sitio. Al cabo de un rato (normalmente menos de un minuto), aparece una notificación de que la implementación se ha realizado correctamente. En la barra de navegación de la izquierda, el nuevo App Service aparece en la sección App Services y la nueva base de datos SQL aparece en la sección Bases de datos SQL.

Implementar la aplicación en 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.

  2. En la página Seleccione un destino de publicación, elija App Service, Seleccionar existente, y después elija Publicar.

    Pick a publish target page

  3. Si no ha agregado previamente su suscripción de Azure en Visual Studio, realice los pasos que aparecen en pantalla. Estos pasos permiten que Visual Studio se conecte a la suscripción de Azure para que la lista de App Services incluya el sitio web.

  4. En la página de App Service, seleccione la Suscripción a la que ha agregado la instancia de App Service. En Vista, seleccione Grupo de recursos. Expanda el grupo de recursos al que agregó la instancia de App Service y, a continuación, seleccione App Service. Elija Aceptar para publicar la aplicación.

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

  6. Tras una implementación correcta, el explorador predeterminado se abre automáticamente en la dirección URL del sitio web implementado.

    Students_index_page_with_paging

    La aplicación ahora se está ejecutando en la nube.

En este punto, la base de datos SchoolContext se ha creado en la base de datos de Azure SQL 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 Alumnos):

Web.config file excerpt

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.

Connection string in Web.config file

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 Azure. Puede evitar que otras personas usen el sitio deteniendo el servicio mediante el Portal de administración de Azure o el Explorador de servidores en Visual Studio.

Stop app service menu item

Escenarios de migraciones avanzadas

Si implementa una base de datos ejecutando migraciones automáticamente como se muestra en este tutorial, y está implementando en un sitio web que se ejecuta en varios servidores, podría tener varios servidores intentando ejecutar migraciones al mismo tiempo. Las migraciones son atómicas, por lo que si dos servidores intentan ejecutar la misma migración, uno lo conseguirá y el otro fallará (suponiendo que las operaciones no puedan realizarse dos veces). En ese caso, si quiere evitar esas incidencias, puede llamar a las migraciones manualmente y establecer su propio código para que solo ocurra una vez. Para más información, consulte Ejecución y scripting de migraciones desde el código en el blog de Rowan Miller y Migrate.exe (para ejecutar migraciones desde la línea de comandos).

Para obtener información sobre otros escenarios de migraciones, consulte Serie de screencasts de migraciones.

Actualización de una migración específica

update-database -target MigrationName

El comando update-database -target MigrationName ejecuta la migración de destino.

Omitir los cambios de migración en la base de datos

Add-migration MigrationName -ignoreChanges

ignoreChanges crea una migración vacía con el modelo actual como instantánea.

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, incluyendo CreateDatabaseIfNotExists (el predeterminado), DropCreateDatabaseIfModelChanges (que usó anteriormente) 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 más información sobre los inicializadores, consulte Descripción de los inicializadores de bases de datos en Entity Framework Code First y el capítulo 6 del libro Programación de Entity Framework: Code First de Julie Lerman y Rowan Miller.

Obtención del código

Descargar el proyecto completado

Recursos adicionales

Encontrará vínculos a otros recursos de Entity Framework en Acceso a datos de ASP.NET: Recursos recomendados.

Pasos siguientes

En este tutorial ha:

  • Ha habilitado las Migraciones de Code First
  • Ha implementado la aplicación en Azure (opcional)

Vaya al siguiente artículo para aprender a crear un modelo de datos más complejo para una aplicación MVC de ASP.NET.