معماری سه لایه در ASP.NET

دوشنبه 16 آذر 1394

در برنامه نویسی برای کاهش پیچیدگی کدها و پشتیبانی و نگهداری راحت آنها ، برنامه را به چند لایه می شکنند هر کدام از این لایه ها با لایه های دیگر ارتباط دارد.در این مقاله راجع به معماری سه لایه صحبت خواهیم کرد.

معماری سه لایه در ASP.NET

معماری سه لایه چیست؟
در برنامه نویسی برای کاهش پیچیدگی کدها و پشتیبانی و نگهداری راحت آنها ، برنامه را به چند لایه می شکنند هر کدام از این لایه ها با لایه های دیگر ارتباط دارد.
در معماری سه لایه و چند لایه هر لایه سرویسی برای لایه های دیگر فراهم می کند و در عین حال سرویس هایی را هم دریافت می کند .
به طور کلی در معماری سه لایه برنامه به لایه های Presentation Layer  ، Business Logic Layer ، Data Access Layer شکسته می شود.
لایه نمایش : چیزی که با کاربر در ارتباط است مانند فرم ها ، صفحات وب و اجزای آنها و ...این لایه در ارتباط با کاربر است و حاوی عناصر گرافیکی است .
لایه منطق یا Business Logic Layer : در این لایه اعمال اصلی برنامه نوشته شده است .این لایه به صورت مستقیم با دیتابیس ارتباط ندارد.این لایه به عنوان واسط بین لایه نمایش و لایه دیتابیس است
درخواست کاربر از لایه نمایش به لایه منطق آمده و این لایه با تعاملی که با لایه داده انجام می دهد با به دست آوردن داده های مورد نیاز و انجام عملیات بر روی آنها پاسخ کاربر را می دهد.
لایه دسترسی به داده و با (Data Access Layer(DAL
این لایه اطلاعاتی که در داخل دیتابیس وجود دارد را مدیریت می کند .عملیات اصلی در داخل این لایه شامل اضافه، حذف، ویرایش و یا جستجو داده ها در بانک است .

  لایه DAL وظیفه مدیریت اطلاعات موجود در دیتابیس را بر عهده دارد و بر اساس دستوراتی که لایه Business به آن می دهد، اطلاعاتی را در دیتابیس اضافه، حذف، ویرایش و یا جستجو می کند و نتیجه این اعمال را به Business Layer باز می گرداند.
شکل زیر شمای کلی معماری سه لایه را بیان می کند

تفاوت لایه با Tire
لایه یک تقسیم بندی در سطح منطقی است که برای جداسازی بخش های مختلف استفاده می شود اما Tire کدها را به صورت فیزیکی تقسیم بندی می کند .مثلا لایه منطقی سرویسی می شود که میتواند برروی کامپیوتر دیگری قرار گیرد و به ارائه سرویس بپردازد.به شکل زیر توجه کنید

برای تشریح بهتر مفهوم معماری سه لایه ، برنامه ای که ضمیمه این مقاله می باشد را ملاحظه کنید .برای اجرای این پروژه در داخل فولدر Administrator صفحه product را اجرا کنید .بعد از اجرا شکل زیر را خواهید دید .

در این صفحه یک GridView   قرار داده ایم در داخل این GridView   اعمال ایجاد ، ویرایش ، و حذف محصولات قرار داده شده است .
همان طور که در Solution Explorer می بینید برای پیاده سازی لایه های Dal,BL,UI به این صورت عمل کرده ایم که یک پروژه جدید از نوع Class Library ایجاد می کنیم و در داخل کلاسی کد ها را می نویسیم .بعد از اینکه این سه پروژه از نوع Class Library را ایجاد کردیم (که در واقع در حکم سه لایه ما هستند) باید ارتباط بین این لایه ها را تعیین کنیم .برای این کار بر روی پروژه کلیک میکنیم تا ساختار درختی آن باز شود سپس بر روی Refrences کلیک می کنیم و Add Refrences را می زنیم در پنجره باز شده گزینه Solution را کلیک می کنیم .در اینجا پروژه هایی که همگی در داخل این solution قرار دارند دیده می شوند .برای لایه Multitire که در واقع همان لایه نمایش ما است لایه DataAccess و لایه Entity را اضافه می کنیم .
همین کار را با لایه های دیگر که قرار است به هم دسترسی داشته باشند انجام می دهیم .
لایه دسترسی به داده یا همان DAL ما در این پروژه به نام Dataaccess است که در آن به ازای تمام کلاس هایی که در داخل entity تعریف کرده ایم (entity موجودیت هایی هستند که در داخل پروژه به آن نیاز داریم ( یک کلاس با نام همان موجودیت به علاوه یک Dac در انتهای آن تعریف شده است . در داخل این کلاس ها به ازای روال های ذخیره شده در پایگاه داده خود توابع مختلفی تعریف کرده و توسط متد ADO به بانک وصل شده و کارهای لازم بر روی دیتا را انجام میدهیم
یکی از کلاس های این لایه به نام ProductDac است که ساختار کد آن در زیر آورده شده است

  public class ProductDac
    {
        public List<entity.Product> SelectAll()
        {
            SqlConnection con = new SqlConnection(Framework.databacemanager.GetStrCnn());
            con.Open();
            SqlCommand com = new SqlCommand("Product_SelectAll", con);
            com.CommandType = System.Data.CommandType.StoredProcedure;
            SqlDataReader dtr = com.ExecuteReader();
            List<entity.Product> lisproduct = new List<entity.Product>();
            while (dtr.Read())
            {
                entity.Product p = new entity.Product();
                p.CategoryID = Convert.ToInt32(dtr["categoryid"]);
                p.ProductName = dtr["productname"].ToString();
                p.ProductID = Convert.ToInt32(dtr["productid"]);
                p.UnitPrice = Convert.ToInt32(dtr["unitprice"]);
                p.Description = dtr["Description"].ToString();
                p.Picture = dtr["picture"].ToString();
                lisproduct.Add(p);
            }

            con.Close();
            return lisproduct;
        }

        public void InsProduct(entity.Product p)
        {
            SqlConnection con = new SqlConnection(Framework.databacemanager.GetStrCnn());
            con.Open();
            SqlCommand com = new SqlCommand("Product_Insert", con);
            com.Parameters.AddWithValue("@ProductName", p.ProductName);
            com.Parameters.AddWithValue("@UnitPrice", p.UnitPrice);
            com.Parameters.AddWithValue("@Picture", p.Picture);
            com.Parameters.AddWithValue("@Description", p.Description);
            com.Parameters.AddWithValue("@CategoryID", p.CategoryID);
            com.CommandType = System.Data.CommandType.StoredProcedure;
            com.ExecuteScalar();

        }
        public entity.Product SelectByPk (int id)
        {
            SqlConnection con = new SqlConnection(Framework.databacemanager.GetStrCnn());
            con.Open();
            SqlCommand com = new SqlCommand("Product_SelectRow", con);
            com.CommandType = System.Data.CommandType.StoredProcedure;
            com.Parameters.AddWithValue("@ProductID", id);
            entity.Product p = new entity.Product();
            SqlDataReader dtr = com.ExecuteReader();
            if (dtr.Read())
            {
               
                p.CategoryID = Convert.ToInt32(dtr["categoryid"]);
                p.ProductName = dtr["productname"].ToString();
                p.ProductID = Convert.ToInt32(dtr["productid"]);
                p.UnitPrice = Convert.ToInt32(dtr["unitprice"]);
                p.Description = dtr["description"].ToString();
                p.Picture = dtr["picture"].ToString(); 
            }
            con.Close()  ;
            return p;     
        }
        public void UpdateProduct(entity.Product p)
        {
            SqlConnection con = new SqlConnection(Framework.databacemanager.GetStrCnn());
            con.Open();
            SqlCommand com = new SqlCommand("Product_Update", con);
            com.Parameters.AddWithValue("@ProductID",p.ProductID);
            com.Parameters.AddWithValue("@ProductName", p.ProductName);
            com.Parameters.AddWithValue("@UnitPrice", p.UnitPrice);
            com.Parameters.AddWithValue("@Picture", p.Picture);
            com.Parameters.AddWithValue("@Description", p.Description);
            com.Parameters.AddWithValue("@CategoryID", p.CategoryID);
            com.CommandType = System.Data.CommandType.StoredProcedure;
            com.ExecuteNonQuery();
        }
        public void DelProduct(int id)
        {
      SqlConnection con = new SqlConnection(Framework.databacemanager.GetStrCnn());
            con.Open();
            SqlCommand com = new SqlCommand("Product_DeleteRow", con);
            com.Parameters.AddWithValue("@ProductID",id);
            com.CommandType = System.Data.CommandType.StoredProcedure;
            com.ExecuteNonQuery();
        }
    }
}


در داخل لایه Framework متدهای مهمی که در کل پروژه از آنها استفاده می شود آورده شده است .در این پروژه سختگیری زیادی انجام نداده ایم و لایه DAL را به صورت مستقیم به لایه نمایش دسترسی داده ایم .بنابراین همانطور که در کد های زیر می بینید برای لود شدن اطلاعات در داخل Grid همچنین ثبت و ویرایش اطلاعات از لایه DAL به صورت مستقیم استفاده کرده ایم .البته استاندارد این است که ابتدا یک لایه BL داشته باشیم و این لایه امکان دسترسی ما را به لایه داده فراهم کند .
کد های مربوط به صفحه product در زیر آورده شده است
 

 public partial class Product : System.Web.UI.Page
    {
        private void messagebox(string message)
        {
            string mes = string.Format(@"<script>alert ('{0}')</script>", message);
            //        string msg = string.Format(@"<script type ='text/javascript'>
            //                           alert('{0}') 
            //</script>", str);
            Page.RegisterClientScriptBlock("x", mes);
        }
        private void gonaturalmode()
        {
            btnCancel.Visible = false;
            btnRegister.Visible = true;
            btnUpdate.Visible = false;
        }
        private void goeditmode()
        {
            btnRegister.Visible = false;
            btnCancel.Visible = true;
            btnUpdate.Visible = true;
        }
        public void bindgvproduct()
        {
            Dataaccess.ProductDac dacprod = new Dataaccess.ProductDac();
            gvProduct.DataSource = dacprod.SelectAll();
            gvProduct.DataBind();
        }
        public void binddrpcategory()
        {
            Dataaccess.CategoryDac daccat = new Dataaccess.CategoryDac();
            drpCatgeory.DataSource = daccat.SelectallCategory();
            drpCatgeory.DataTextField = "categoryname";
            drpCatgeory.DataValueField = "categoryid";
            drpCatgeory.Items.Insert(0, "...Please Choose a Category");
            drpCatgeory.DataBind();
        }
        private void clearForm()
        {
            Img.ImageUrl = "";
            txtProductName.Text = "";
            txtDescription.Text = "";
            txtUnitPrice.Text = "";
            drpCatgeory.SelectedIndex = 0;
        }

        private bool CanSaveFile()
        {
            bool CanSave = true;
            if (FileImage.PostedFile.ContentLength == 0)
            {
                messagebox("Please Choos a File");
                return false;
            }
            if (FileImage.PostedFile.ContentLength > 2000000)
            {
                messagebox("the file size must be between 10000 & 2000000");
                return false;
            }

            if (System.IO.Path.GetExtension(FileImage.PostedFile.FileName).ToLower() != ".jpg")
            {
                messagebox("You can choose only  jpg file");
                return false;
            }
            return CanSave;

        }
        private string GetPhisicalFileName(string FileName, ref  string RelativeAddress)
        {
            //string t = Framework.DateManager.getpersiondate(DateTime.Now);
            //FileName = System.IO.Path.GetFileName(FileName);
            //FileName = t + "_" + FileName;
            //"~/Images/"
            RelativeAddress = FileName;
            FileName = Server.MapPath(Request.ApplicationPath) + FileName;
            return FileName;
        }
        protected void Page_Load(object sender, EventArgs e)
        {

            if (!IsPostBack)
            {
                binddrpcategory();
                bindgvproduct();
                gonaturalmode();
            }

        }

        protected void btnRegister_Click(object sender, EventArgs e)
        {
            //if (drpCatgeory.SelectedIndex != 0)
            //   {
            entity.Product p = new entity.Product();
            p.ProductName = txtProductName.Text;
            p.Description = txtDescription.Text;
            p.UnitPrice = Convert.ToInt32(txtUnitPrice.Text);
            if (CanSaveFile())
            {
                string fn = FileImage.PostedFile.FileName;
                string rfn = "";
                fn = GetPhisicalFileName(fn, ref rfn);
                p.Picture = rfn;
                FileImage.PostedFile.SaveAs(fn);

            }
            p.CategoryID = Convert.ToInt32(drpCatgeory.SelectedValue);


            Dataaccess.ProductDac dac = new Dataaccess.ProductDac();
            dac.InsProduct(p);

            clearForm();
            bindgvproduct();
            gonaturalmode();
            messagebox("اطلاعات ثبت شد");
            //new DataAccess.ProductDAC().Add(new Entity.Product { CategoryID = Convert.ToInt32(txtCategoryID), ProductName = txtProductName.Text});
            //    }
            //else
            //{
            //    messagebox("لطفا نوع محصول را وارد کنید");
            //}


        }

        protected void gvProduct_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            if (e.CommandName == "ed")
            {

                int pid = Convert.ToInt32(e.CommandArgument);
                Dataaccess.ProductDac dac = new Dataaccess.ProductDac();
                entity.Product product = new entity.Product();
                product = dac.SelectByPk(pid);
                txtDescription.Text = product.Description;
                txtProductName.Text = product.ProductName;
                txtUnitPrice.Text = product.UnitPrice.ToString();
                if (FileImage.PostedFile.FileName=="")
                {
                    Img.ImageUrl = "~/Images/" + product.Picture;
                }
                else
                {
                    Img.ImageUrl = product.Picture;
                }
                ViewState["id"] = pid;
                goeditmode();
            }
            if (e.CommandName == "del")
            {

                int id = Convert.ToInt32(e.CommandArgument);
                Dataaccess.ProductDac dac = new Dataaccess.ProductDac();
                dac.DelProduct(id);
                bindgvproduct();
            }
        }

        protected void btnCancel_Click(object sender, EventArgs e)
        {
            gonaturalmode();
            clearForm();

        }

        protected void btnUpdate_Click(object sender, EventArgs e)
        {
            Dataaccess.ProductDac dac = new Dataaccess.ProductDac();
            entity.Product p = new entity.Product();
            p.CategoryID = Convert.ToInt32(drpCatgeory.SelectedValue);
            p.Description = txtDescription.Text;
            p.Picture = Img.ImageUrl;
            if (FileImage.PostedFile.FileName == "")
            {
                p.Picture = Img.ImageUrl;

            }
            else
            {
                p.Picture = FileImage.PostedFile.FileName;
            }
            p.ProductID = Convert.ToInt32(ViewState["id"]);
            p.ProductName = txtProductName.Text;
            p.UnitPrice = Convert.ToInt32(txtUnitPrice.Text);
            dac.UpdateProduct(p);
            clearForm();
            bindgvproduct();
            gonaturalmode();
        }
    }
}

 

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید