Adición de la capa de lógica de negocios a un proyecto que usa el enlace de modelos y los formularios web

por Tom FitzMacken

En esta serie de tutoriales se muestran aspectos básicos del uso del enlace de modelos con un proyecto de web Forms de ASP.NET. El enlace de modelos hace que la interacción de datos sea más sencilla que tratar con objetos de origen de datos (como ObjectDataSource o SqlDataSource). Esta serie comienza con material introductorio y pasa a conceptos más avanzados en tutoriales posteriores.

En este tutorial se muestra cómo usar el enlace de modelos con una capa de lógica de negocios. Establecerás el miembro OnCallingDataMethods para especificar que se utilizará un objeto diferente de la página actual para invocar los métodos de datos.

Este tutorial se basa en el proyecto creado en las partes anteriores de la serie.

Puede descargar el proyecto completo en C# o VB. El código descargable funciona con Visual Studio 2012 o Visual Studio 2013. Usa la plantilla de Visual Studio 2012, que es ligeramente diferente de la plantilla de Visual Studio 2013 que se muestra en este tutorial.

Lo que vas a desarrollar

El enlace de modelos permite colocar el código de interacción de datos en el archivo de código subyacente de una página web o en una clase lógica de negocios independiente. Los tutoriales anteriores han mostrado cómo usar los archivos de código subyacente para el código de interacción de datos. Este enfoque funciona para sitios pequeños, pero puede provocar repetición de código y mayor dificultad al mantener un sitio grande. También puede ser muy difícil probar el código mediante programación que reside en archivos de código subyacente porque no hay ninguna capa de abstracción.

Para centralizar el código de interacción de datos, puede crear una capa de lógica de negocios que contenga toda la lógica para interactuar con los datos. A continuación, llame a la capa de lógica de negocios desde las páginas web. En este tutorial se muestra cómo mover todo el código que ha escrito en los tutoriales anteriores a una capa de lógica de negocios y, a continuación, usar ese código de las páginas.

En este tutorial, hará lo siguiente:

  1. Mover el código de los archivos de código subyacente a una capa de lógica de negocios
  2. Cambie sus controles enlazados a datos para llamar a los métodos en la capa de lógica de negocios

Creación de una capa de lógica de negocios

Ahora, creará la clase a la que se llama desde las páginas web. Los métodos de esta clase tienen un aspecto similar a los métodos que usó en los tutoriales anteriores e incluyen los atributos del proveedor de valores.

En primer lugar, agregue una nueva carpeta denominada BLL.

agregar carpeta

En la carpeta BLL, cree una nueva clase denominada SchoolBL.cs. Contendrá todas las operaciones de datos que residían originalmente en archivos de código subyacente. Los métodos son casi los mismos que los métodos del archivo de código subyacente, pero incluirán algunos cambios.

El cambio más importante que se debe tener en cuenta es que ya no está ejecutando el código desde una instancia de la clase Page . La clase Page contiene el método TryUpdateModel y la propiedad ModelState . Cuando este código se mueve a una capa de lógica de negocios, ya no tiene una instancia de la clase Page para llamar a estos miembros. Para solucionar este problema, debe agregar un parámetro ModelMethodContext a cualquier método que tenga acceso a TryUpdateModel o ModelState. Use este parámetro ModelMethodContext para llamar a TryUpdateModel o recuperar ModelState. No es necesario cambiar nada en la página web para tener en cuenta este nuevo parámetro.

Reemplace el código de SchoolBL.cs por el código siguiente.

using System;
using System.Linq;
using ContosoUniversityModelBinding.Models;
using System.Web.ModelBinding;
using System.Web.UI.WebControls;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;

namespace ContosoUniversityModelBinding.BLL
{
    public class SchoolBL : IDisposable
    {
        SchoolContext db = new SchoolContext();

        public IQueryable<Student> GetStudents([Control] AcademicYear? displayYear)
        {
            var query = db.Students.Include(s => s.Enrollments.Select(e => e.Course));

            if (displayYear != null)
            {
                query = query.Where(s => s.Year == displayYear);
            }

            return query;
        }

        public void InsertStudent(ModelMethodContext context)
        {
            var item = new Student();

            context.TryUpdateModel(item);
            if (context.ModelState.IsValid)
            {
                db.Students.Add(item);
                db.SaveChanges();
            }
        }

        public void DeleteStudent(int studentID, ModelMethodContext context)
        {
            var item = new Student { StudentID = studentID };
            db.Entry(item).State = EntityState.Deleted;
            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                context.ModelState.AddModelError("",
                    String.Format("Item with id {0} no longer exists in the database.", studentID));
            }
        }

        public void UpdateStudent(int studentID, ModelMethodContext context)
        {
            Student item = null;
            item = db.Students.Find(studentID);
            if (item == null)
            {
                context.ModelState.AddModelError("", String.Format("Item with id {0} was not found", studentID));
                return;
            }

            context.TryUpdateModel(item);
            if (context.ModelState.IsValid)
            {
                db.SaveChanges();
            }
        }

        public IQueryable<Enrollment> GetCourses([QueryString] int? studentID)
        {
            var query = db.Enrollments.Include(e => e.Course)
                .Where(e => e.StudentID == studentID);
            return query;
        }

        private bool disposedValue = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposedValue)
            {
                if (disposing)
                {
                    db.Dispose();
                }
            }
            this.disposedValue = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}

Revisión de las páginas existentes para recuperar datos de la capa de lógica de negocios

Por último, convertirá las páginas Students.aspx, AddStudent.aspx y Courses.aspx para que dejen de usar consultas en el archivo de código subyacente y pasen a utilizar la capa de lógica de negocios.

En los archivos de código subyacente de Students, AddStudent y Courses, elimine o comente los métodos de consulta siguientes:

  • studentsGrid_GetData
  • studentsGrid_ActualizarElemento
  • studentsGrid_DeleteItem
  • FormularioAgregarEstudiante_InsertarElemento
  • coursesGrid_GetData

Ahora no debería tener ningún código en el archivo de código subyacente que pertenezca a las operaciones de datos.

El controlador de eventos OnCallingDataMethods permite especificar un objeto que se usará para los métodos de datos. En Students.aspx, agregue un valor para ese controlador de eventos y cambie los nombres de los métodos de datos a los nombres de los métodos de la clase lógica de negocios.

<asp:GridView runat="server" ID="studentsGrid"
    ItemType="ContosoUniversityModelBinding.Models.Student" DataKeyNames="StudentID"
    SelectMethod="GetStudents"
    UpdateMethod="UpdateStudent" DeleteMethod="DeleteStudent"
    AllowSorting="true" AllowPaging="true" PageSize="4"
    AutoGenerateEditButton="true" AutoGenerateDeleteButton="true"
    AutoGenerateColumns="false" 
    OnCallingDataMethods="studentsGrid_CallingDataMethods">

En el archivo de código subyacente para Students.aspx, defina el controlador de eventos para el evento CallingDataMethods. En este controlador de eventos, se especifica la clase lógica de negocios para las operaciones de datos.

protected void studentsGrid_CallingDataMethods(object sender, CallingDataMethodsEventArgs e)
{
    e.DataMethodsObject = new ContosoUniversityModelBinding.BLL.SchoolBL();
}

En AddStudent.aspx, realice cambios similares.

<asp:FormView runat="server" ID="addStudentForm"
    ItemType="ContosoUniversityModelBinding.Models.Student"
    InsertMethod="InsertStudent" DefaultMode="Insert"
    OnCallingDataMethods="addStudentForm_CallingDataMethods"
    RenderOuterTable="false" OnItemInserted="addStudentForm_ItemInserted">
protected void addStudentForm_CallingDataMethods(object sender, CallingDataMethodsEventArgs e)
{
    e.DataMethodsObject = new ContosoUniversityModelBinding.BLL.SchoolBL();
}

En Courses.aspx, realice cambios similares.

<asp:GridView runat="server" ID="coursesGrid"
    ItemType="ContosoUniversityModelBinding.Models.Enrollment"
    SelectMethod="GetCourses" AutoGenerateColumns="false"
    OnCallingDataMethods="coursesGrid_CallingDataMethods">
protected void coursesGrid_CallingDataMethods(object sender, CallingDataMethodsEventArgs e)
{
    e.DataMethodsObject = new ContosoUniversityModelBinding.BLL.SchoolBL();
}

Ejecute la aplicación y observe que todas las páginas funcionan como tenían anteriormente. La lógica de validación también funciona correctamente.

Conclusión

En este tutorial, reestructurará la aplicación para usar una capa de acceso a datos y una capa de lógica de negocios. Especificó que los controles de datos usan un objeto que no es la página actual para las operaciones de datos.