Ajout d’une couche logique métier à un projet qui utilise la liaison de modèle et les formulaires web

par Tom FitzMacken

Cette série de tutoriels illustre les aspects de base de l’utilisation de la liaison de modèle avec un projet web Forms ASP.NET. La liaison de modèle rend l’interaction des données plus simple que la gestion des objets de source de données (par exemple, ObjectDataSource ou SqlDataSource). Cette série commence par le matériel d’introduction et passe à des concepts plus avancés dans les didacticiels ultérieurs.

Ce tutoriel montre comment utiliser la liaison de modèle avec une couche logique métier. Vous allez définir le membre OnCallingDataMethods pour spécifier qu’un objet autre que la page active est utilisé pour appeler les méthodes de données.

Ce didacticiel s’appuie sur le projet créé dans les parties antérieures de la série.

Vous pouvez télécharger le projet complet en C# ou VB. Le code téléchargeable fonctionne avec Visual Studio 2012 ou Visual Studio 2013. Il utilise le modèle Visual Studio 2012, légèrement différent du modèle Visual Studio 2013 présenté dans ce tutoriel.

Ce que vous allez construire

La liaison de modèle vous permet de placer votre code d’interaction de données dans le fichier code-behind d’une page web ou dans une classe de logique métier distincte. Les didacticiels précédents ont montré comment utiliser les fichiers de code-behind pour le code destiné à l'interaction avec les données. Cette approche fonctionne pour les petits sites, mais elle peut entraîner une répétition du code et une plus grande difficulté lors de la maintenance d’un site volumineux. Il peut également être très difficile de tester par programmation le code qui réside dans le code behind des fichiers, car il n’existe aucune couche d’abstraction.

Pour centraliser le code d’interaction des données, vous pouvez créer une couche logique métier qui contient toute la logique permettant d’interagir avec les données. Vous appelez ensuite la couche logique métier à partir de vos pages web. Ce tutoriel montre comment déplacer tout le code que vous avez écrit dans les didacticiels précédents dans une couche logique métier, puis utiliser ce code à partir des pages.

Dans ce didacticiel, vous allez :

  1. Déplacer le code des fichiers code-behind vers une couche logique métier
  2. Modifier vos contrôles liés aux données pour appeler les méthodes dans la couche logique métier

Créer une couche logique métier

À présent, vous allez créer la classe appelée à partir des pages web. Les méthodes de cette classe ressemblent aux méthodes que vous avez utilisées dans les didacticiels précédents et incluent les attributs du fournisseur de valeurs.

Tout d’abord, ajoutez un nouveau dossier appelé BLL.

ajouter un dossier

Dans le dossier BLL, créez une classe nommée SchoolBL.cs. Cela contiendra toutes les opérations de données qui résidaient initialement dans les fichiers de code-behind. Les méthodes sont presque identiques aux méthodes du fichier code-behind, mais incluent certaines modifications.

La modification la plus importante à noter est que vous n’exécutez plus le code à partir d’une instance de la classe Page . La classe Page contient la méthode TryUpdateModel et la propriété ModelState . Lorsque ce code est déplacé vers une couche logique métier, vous n’avez plus d’instance de la classe Page pour appeler ces membres. Pour contourner ce problème, vous devez ajouter un paramètre ModelMethodContext à n’importe quelle méthode qui accède à TryUpdateModel ou ModelState. Vous utilisez ce paramètre ModelMethodContext pour appeler TryUpdateModel ou récupérer ModelState. Vous n’avez pas besoin de modifier quoi que ce soit dans la page web pour prendre en compte ce nouveau paramètre.

Remplacez le code dans SchoolBL.cs par le code suivant.

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);
        }
    }
}

Réviser les pages existantes pour récupérer des données à partir de la couche logique métier

Enfin, vous allez convertir les pages Students.aspx, AddStudent.aspx et Courses.aspx à partir de l'utilisation de requêtes dans le fichier code-behind vers l'utilisation de la couche de logique métier.

Dans les fichiers code-behind pour Students, AddStudent et Courses, supprimez ou commentez les méthodes de requête suivantes :

  • grilleÉtudiants_ObtenirDonnées
  • studentsGrid_UpdateItem
  • studentsGrid_DeleteItem
  • ajouterÉtudiantFormulaire_InsererÉlément
  • coursesGrid_GetData

Vous ne devez maintenant avoir aucun code dans le fichier code-behind qui se rapporte aux opérations de données.

Le gestionnaire d’événements OnCallingDataMethods vous permet de spécifier un objet à utiliser pour les méthodes de données. Dans Students.aspx, ajoutez une valeur pour ce gestionnaire d’événements et remplacez les noms des méthodes de données par les noms des méthodes dans la classe logique métier.

<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">

Dans le fichier code-behind de Students.aspx, définissez le gestionnaire d’événements pour l’événement CallingDataMethods. Dans ce gestionnaire d’événements, vous spécifiez la classe logique métier pour les opérations de données.

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

Dans AddStudent.aspx, apportez des modifications similaires.

<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();
}

Dans Courses.aspx, apportez des modifications similaires.

<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();
}

Exécutez l’application et notez que toutes les pages fonctionnent comme elles l’avaient précédemment. La logique de validation fonctionne également correctement.

Conclusion

Dans ce tutoriel, vous restructiez votre application pour utiliser une couche d’accès aux données et une couche logique métier. Vous avez spécifié que les contrôles de données utilisent un objet qui n’est pas la page active pour les opérations de données.