다음을 통해 공유


모델 바인딩 및 웹 양식을 사용하는 프로젝트에 비즈니스 논리 계층 추가

Tom FitzMacken

이 자습서 시리즈에서는 ASP.NET Web Forms 프로젝트에서 모델 바인딩을 사용하는 기본 측면을 보여 줍니다. 모델 바인딩을 사용하면 데이터 원본 개체(예: ObjectDataSource 또는 SqlDataSource)를 처리하는 것보다 데이터 상호 작용이 더 간단해집니다. 이 시리즈는 소개 자료로 시작하여 이후 자습서에서 고급 개념으로 이동합니다.

이 자습서에서는 비즈니스 논리 계층에서 모델 바인딩을 사용하는 방법을 보여줍니다. OnCallingDataMethods 멤버를 설정하여 현재 페이지 이외의 개체가 데이터 메서드를 호출하는 데 사용되도록 지정합니다.

이 자습서는 시리즈의 이전 부분에서 만든 프로젝트를 기반으로 합니다.

C# 또는 VB에서 전체 프로젝트를 다운로드 할 수 있습니다. 다운로드 가능한 코드는 Visual Studio 2012 또는 Visual Studio 2013 작동합니다. 이 자습서에 표시된 Visual Studio 2013 템플릿과 약간 다른 Visual Studio 2012 템플릿을 사용합니다.

빌드할 내용

모델 바인딩을 사용하면 웹 페이지의 코드 숨김 파일 또는 별도의 비즈니스 논리 클래스에 데이터 상호 작용 코드를 배치할 수 있습니다. 이전 자습서에서는 데이터 상호 작용 코드에 코드 숨김 파일을 사용하는 방법을 보여 줍니다. 이 방법은 소규모 사이트에서 작동하지만 대규모 사이트를 유지 관리할 때 코드 반복 및 더 큰 어려움이 발생할 수 있습니다. 추상화 계층이 없으므로 코드 숨김 파일에 있는 코드를 프로그래밍 방식으로 테스트하는 것도 매우 어려울 수 있습니다.

데이터 상호 작용 코드를 중앙 집중화하려면 데이터와 상호 작용하기 위한 모든 논리가 포함된 비즈니스 논리 계층을 만들 수 있습니다. 그런 다음 웹 페이지에서 비즈니스 논리 계층을 호출합니다. 이 자습서에서는 이전 자습서에서 작성한 모든 코드를 비즈니스 논리 계층으로 이동한 다음 페이지에서 해당 코드를 사용하는 방법을 보여 줍니다.

이 자습서에서는 다음을 수행합니다.

  1. 코드 숨김 파일에서 비즈니스 논리 계층으로 코드 이동
  2. 비즈니스 논리 계층에서 메서드를 호출하도록 데이터 바인딩된 컨트롤 변경

비즈니스 논리 계층 만들기

이제 웹 페이지에서 호출되는 클래스를 만듭니다. 이 클래스의 메서드는 이전 자습서에서 사용한 메서드와 유사하며 값 공급자 특성을 포함합니다.

먼저 BLL이라는 새 폴더를 추가합니다.

폴더 추가

BLL 폴더에서 SchoolBL.cs라는 새 클래스를 만듭니다. 원래 코드 숨김 파일에 상주했던 모든 데이터 작업이 포함됩니다. 메서드는 코드 숨김 파일의 메서드와 거의 동일하지만 일부 변경 내용이 포함됩니다.

주의해야 할 가장 중요한 변경 사항은 Page 클래스의 instance 내에서 더 이상 코드를 실행하지 않는다는 것입니다. Page 클래스에는 TryUpdateModel 메서드와 ModelState 속성이 포함됩니다. 이 코드를 비즈니스 논리 계층으로 이동하면 더 이상 이러한 멤버를 호출할 Page 클래스의 instance 없습니다. 이 문제를 해결하려면 TryUpdateModel 또는 ModelState에 액세스하는 모든 메서드에 ModelMethodContext 매개 변수를 추가해야 합니다. 이 ModelMethodContext 매개 변수를 사용하여 TryUpdateModel을 호출하거나 ModelState를 검색합니다. 이 새 매개 변수를 고려하기 위해 웹 페이지에서 아무것도 변경할 필요가 없습니다.

SchoolBL.cs의 코드를 다음 코드로 바꿉니다.

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

비즈니스 논리 계층에서 데이터를 검색하도록 기존 페이지 수정

마지막으로 Students.aspx, AddStudent.aspx 및 Courses.aspx 페이지를 코드 숨김 파일의 쿼리 사용에서 비즈니스 논리 계층 사용으로 변환합니다.

Students, AddStudent 및 Courses의 코드 숨김 파일에서 다음 쿼리 메서드를 삭제하거나 주석 처리합니다.

  • studentsGrid_GetData
  • studentsGrid_UpdateItem
  • studentsGrid_DeleteItem
  • addStudentForm_InsertItem
  • coursesGrid_GetData

이제 데이터 작업과 관련된 코드 숨김 파일에 코드가 없어야 합니다.

OnCallingDataMethods 이벤트 처리기를 사용하면 데이터 메서드에 사용할 개체를 지정할 수 있습니다. Students.aspx에서 해당 이벤트 처리기에 대한 값을 추가하고 데이터 메서드의 이름을 비즈니스 논리 클래스의 메서드 이름으로 변경합니다.

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

Students.aspx에 대한 코드 숨김 파일에서 CallingDataMethods 이벤트에 대한 이벤트 처리기를 정의합니다. 이 이벤트 처리기에서 데이터 작업에 대한 비즈니스 논리 클래스를 지정합니다.

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

AddStudent.aspx에서 비슷한 변경을 합니다.

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

Courses.aspx에서 비슷한 변경 내용을 적용합니다.

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

애플리케이션을 실행하고 모든 페이지가 이전과 같이 작동하는지 확인합니다. 유효성 검사 논리도 올바르게 작동합니다.

결론

이 자습서에서는 데이터 액세스 계층 및 비즈니스 논리 계층을 사용하도록 애플리케이션을 다시 구성했습니다. 데이터 컨트롤이 데이터 작업의 현재 페이지가 아닌 개체를 사용하도록 지정했습니다.