Dodawanie warstwy logiki biznesowej do projektu korzystającego z powiązania modelu i formularzy internetowych

Autor: Tom FitzMacken

W tej serii samouczków przedstawiono podstawowe aspekty używania powiązania modelu z projektem ASP.NET Web Forms. Powiązanie modelu sprawia, że interakcja danych jest bardziej prosta niż w przypadku obiektów źródła danych (takich jak ObjectDataSource lub SqlDataSource). Ta seria rozpoczyna się od materiałów wprowadzających i przechodzi do bardziej zaawansowanych pojęć w kolejnych samouczkach.

W tym samouczku pokazano, jak używać powiązania modelu z warstwą logiki biznesowej. Należy ustawić element członkowski OnCallingDataMethods, aby określić, że obiekt inny niż bieżąca strona jest używany do wywoływania metod danych.

Ten samouczek opiera się na projekcie utworzonym we wcześniejszych częściach serii.

Kompletny projekt można pobrać w języku C# lub VB. Kod do pobrania działa z programem Visual Studio 2012 lub Visual Studio 2013. Używa szablonu programu Visual Studio 2012, który jest nieco inny niż szablon programu Visual Studio 2013 przedstawiony w tym samouczku.

Co będziesz tworzyć

Wiązanie modelu umożliwia umieszczenie kodu interakcji danych w zapleczu kodu dla strony internetowej lub w oddzielnej klasie warstwy logiki biznesowej. W poprzednich samouczkach pokazano, jak używać plików code-behind do interakcji z danymi. Takie podejście działa w przypadku małych witryn, ale może prowadzić do powtórzeń kodu i większych trudności podczas zarządzania dużą stroną. Programowe testowanie kodu znajdującego się w kodzie za plikami może być bardzo trudne, ponieważ nie ma warstwy abstrakcji.

Aby scentralizować kod interakcji danych, możesz utworzyć warstwę logiki biznesowej zawierającą całą logikę do interakcji z danymi. Następnie należy wywołać warstwę logiki biznesowej ze stron internetowych. W tym samouczku pokazano, jak przenieść cały kod napisany w poprzednich samouczkach do warstwy logiki biznesowej, a następnie użyć tego kodu ze stron.

W tym samouczku nauczysz się:

  1. Przenieś kod z plików code-behind na warstwę logiki biznesowej
  2. Zmień kontrolki powiązane z danymi, aby wywoływały metody w warstwie logiki biznesowej

Tworzenie warstwy logiki biznesowej

Teraz utworzysz klasę, którą wywołuje się ze strony internetowej. Metody w tej klasie wyglądają podobnie do metod używanych w poprzednich samouczkach i zawierają atrybuty dostawcy wartości.

Najpierw dodaj nowy folder o nazwie BLL.

dodaj folder

W folderze BLL utwórz nową klasę o nazwie SchoolBL.cs. Będzie zawierać wszystkie operacje danych, które pierwotnie znajdowały się w plikach z kodem za kulisami. Metody są prawie takie same jak w pliku code-behind, ale będą zawierać pewne zmiany.

Najważniejszą zmianą jest to, że nie wykonujesz już kodu z poziomu wystąpienia klasy Page . Klasa Page zawiera metodę TryUpdateModel i właściwość ModelState . Po przeniesieniu tego kodu do warstwy logiki biznesowej nie będziesz miał już wystąpienia klasy Page do wywoływania tych metod i właściwości. Aby obejść ten problem, należy dodać parametr ModelMethodContext do dowolnej metody, która uzyskuje dostęp do modelu TryUpdateModel lub ModelState. Użyjesz tego parametru ModelMethodContext, aby wywołać metodę TryUpdateModel lub pobrać modelState. Nie musisz zmieniać niczego na stronie internetowej, aby uwzględnić ten nowy parametr.

Zastąp kod w SchoolBL.cs następującym kodem.

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

Poprawianie istniejących stron w celu pobierania danych z warstwy logiki biznesowej

Na koniec przekonwertujesz strony Students.aspx, AddStudent.aspx i Courses.aspx z używania zapytań w pliku code-behind na używanie warstwy logiki biznesowej.

W plikach zaplecza kodowego dla Students, AddStudent i Courses usuń lub skomentuj następujące metody zapytań:

  • studentsGrid_GetData
  • studentsGrid_UpdateItem
  • studentsGrid_DeleteItem
  • addStudentForm_InsertItem
  • coursesGrid_GetData

Teraz w pliku code-behind nie powinno być żadnego kodu dotyczącego operacji na danych.

Procedura obsługi zdarzeń OnCallingDataMethods umożliwia określenie obiektu do użycia dla metod danych. W Students.aspx dodaj wartość dla tej procedury obsługi zdarzeń i zmień nazwy metod danych na nazwy metod w klasie logiki biznesowej.

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

W pliku z logiką dla Students.aspx zdefiniuj procedurę obsługi dla zdarzenia CallingDataMethods. W tym programie obsługi zdarzeń należy określić klasę logiki biznesowej dla operacji na danych.

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

W AddStudent.aspx wprowadź podobne zmiany.

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

W Courses.aspx wprowadź podobne zmiany.

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

Uruchom aplikację i zwróć uwagę, że wszystkie strony działają tak, jak wcześniej. Logika walidacji działa również poprawnie.

Podsumowanie

W tym samouczku przekształciłeś swoją aplikację, aby korzystać z warstwy dostępu do danych i warstwy logiki biznesowej. Określono, że kontrolki danych używają obiektu, który nie jest bieżącą stroną dla operacji na danych.