استخدام Areas في Routing

-

الفائدة من Areas هو تقسيم التطبيق الى اجزاء، بحيث يكون التطبيق اكثر سهولة ومرونة، مثال ذلك يمكن اضافة مجموعة من Areas مثل administration, billing, sales ... الخ،واكيد في حال تقسيم التطبيق لمجموعة من Areas بنقدر نعمل العديد من  controllers, Models & Views تابعة لكل Areas. بحيث يمكن وبسهولة توزيع ومعرفة الملفات المرتبطة بكل جزء.

تحتوي Areas  على MVC folder structure ، بحيث يمكن اضافة Controllers, Model and Views لكل area

تمام وحتي نفهم الموضوع نبدأ وكالعاده بمثال.

خلونا نعمل Area باسم StudentPortal،والهدف منها هو portal خاص بالطلاب ويمكن من خلاله استعراض الدروس التي تم التسجيل بها، استعراض المعلومات الشخصية، عمليات الدفع... الخ.

لإنشاء new Area  في المشروع، انقر بزر الماوس الأيمن على اسم التطبيق وحدد Add ➤ New Folder  وقم بتسمية هذا المجلد Areas. أنشئ folder آخر داخل مجلد Areas الذي تم إنشاؤه حديثًا وقم بتسميته باسم StudentPortal . الآن قم بإنشاء مجلدات Controllers, Models & Views  بداخلها، كما هو واضح بالأسفل:

 

يوجد طريقة ثانية لاضافة Area في التطبيق وذلك بالنقر يمين فوق مجلد Areas ثم اختر Add-New Scaffolded item


بعدها بنختار  MVC Area

بعد هيك بنحدد اسم Area المطلوب 


انشاء Route ل Areas
اكيد بنحتاج الى إضافة route لهذه Areas في التطبيق. لذلك انتقل الى ملف Startup.cs class ثم أضفroute كما هو موضح بالأسفل:
  app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                name: "Areas",
                pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
نمام نهم شو عملنا .
عرفنا area segment في هذا route بحيث تتطابق مع عناوين URL التي تستهدف controllers في areas المختارة. ويتم استخدام القيد الموجود لمطابقة الطلب ب areas التي تم إنشاؤها.
باستخدام هذه الطريقة يمكن الوصول الى area في التطبيق دون تحديد area معينة. 
يمكن تعيين Route ل area معينة في التطبيق.
مثال ذلك الكود التالي يعرض فقط الarea الخاصة ب Admin : 

 endpoints.MapAreaControllerRoute(
        "Admin",
        "Admin",
        "Admin/{controller=Home}/{action=Index}/{id?}");
تمام خلونا الان نوضح كيفية عمل StudentPortal Area،
اولا انشاء Models
لذا قم بإنشاء class جديد داخل Models folder. ويكون الاسم MyCourses.cs ثم اضف الكود التالي:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Area.StudentPortal.Models
{
    public class MyCourses
    {
        public int ID { get; set; }
        public string CourseNumber { get; set; }
        public string CourseName { get; set; }
        public string CourseDescription { get; set; }
        public decimal Price { get; set; }
        public int Capacity { get; set; }
        public DateTime CreatedDate { get; set; }
    }
}
ثانيا انشاء Controller
الآن قم بإنشاء Controller داخل مجلد Controllers. باسم MyCoursesController.cs.ثم أضف الكود أدناه إليه:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using StudentsAcademy.Area.StudentPortal.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Area.StudentPortal.Controllers
{
    [Area("StudentPortal")]
    public class MyCoursesController : Controller
    {
        public IConfiguration Configuration { get; }
        public MyCoursesController(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IActionResult Index(int StudentID)
        {
            List<MyCourses> MyCoursesList = new List<MyCourses>();
            try
            {
                string connectionString = Configuration["ConnectionStrings:DefaultConnection"];
                using (SqlConnection connection = new SqlConnection(connectionString))
                {
                    DataTable dataTable = new DataTable();
  string sql = @"declare @StudentID int="+ StudentID + " select sc.StudentCourseId, c.CourseNumber, c.CourseName, c.CourseDescription, c.Price, c.Capacity, sc.CreatedDate from StudentCourses sc inner join Courses c on c.CoursesId = sc.CourseId where sc.StudentId = @StudentID";
                    SqlCommand command = new SqlCommand(sql, connection);
                    command.CommandType = CommandType.Text;
                    SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
                    // filling records to DataTable
                    dataAdapter.Fill(dataTable);
                    foreach (DataRow item in dataTable.Rows)
                    {
                        MyCoursesList.Add(new MyCourses
                        {
                            ID = Convert.ToInt32(item["StudentCourseId"]),
                            CourseNumber = Convert.ToString(item["CourseNumber"]),
                            CourseName = Convert.ToString(item["CourseName"]),
                            CourseDescription = Convert.ToString(item["CourseDescription"]),
                            Price = Convert.ToDecimal(item["Price"]),
                            Capacity = Convert.ToInt32(item["Capacity"]),
                            CreatedDate = Convert.ToDateTime(item["CreatedDate"]),
                        });
                    }
                }
            }
            catch (Exception ex)
            {
            }
            finally
            {
            }
            return View(MyCoursesList);
        }
    }
}
لاحظ attribute المسمى [Area("StudentPortal")]  المطبقة على Controller. الهدف منها هو استخدامها لربط هذا Controller ب StudentPortal area.
في هذا Action استخدمنا SQL Query من نوع Text بغرض ارجاع المواد الخاصة بطالب معين، حيث تم تمرير رقم الطالب Id ك Parameter الى هذه action ثم تم الحصول على البيانات المطلوبة من قاعدة البيانات، وبعدها عرفنا List من نوع MyCourses لحفظ البيانات بشكل مؤقت ثم عرضها في View 
تأكد من إضافة ملف (ViewImports.cshtml_) في مجلد Areas ➤ StudentPortal ➤ Views 
وذلك بهدف تضمين مساحات الأسماء والاستفادة من Tag Helpers
  ثم اضف الكود التالي إليه:
using StudentsAcademy.Area.StudentPortal.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
شكل التطبيق مه Areas



إضافة View
تبقي آخر جزء وهو إضافة View  لذلك انتقل الى مجلد View ثم انقر يمين واختر Add- New Folder باسم MyCourses ثم داخل هذا المجلد اضف View  باسم Index كما في الصورة: 


بعد الاضافة سيكون شكل التطبيق : 



تمام الان خلونا نضيف الكود التالي الى هذه Index View حيث نقوم بعرض المواد الخاصة بالطالب التي تم ارجاعها من Index action

@model IEnumerable<MyCourses>
@{ ViewBag.Title = "All Courses";}
<h2>All Reservations</h2>
<table class="table table-sm table-striped table-bordered m-2">
    <thead><tr><th>CourseNumber</th><th>CourseName</th><th>Course Description</th><th>Course Price</th><th>Capacity</th><th>CreatedDate</th></tr></thead>
    <tbody>
        @if (Model != null)
        {
            foreach (var r in Model)
            {
        <tr>
            <td>@r.CourseNumber</td>
            <td>@r.CourseName</td>
            <td>@r.CourseDescription</td>
            <td>@r.Price</td>
            <td>@r.Capacity</td>
            <td>@r.CreatedDate</td>
        </tr>
            }
        }
    </tbody>
</table>
قم بتشغيل التطبيق الخاص بك وانتقل إلى

https://localhost:44382/StudentPortal/MyCourses?ID=1
شوف النتيجة وراسلنا اذا في ملاحظات او استفسارات. 

انشاء الروابط في Areas

يمكن استخدام   Tag Helper التالية لانشاء link  في action method  في نفس area.
asp-action = "action_name" 
asp-controller="controller Name"
مثال: تأكد من إضافة HomeController في مجلد Controllers ومن ثم اضف View باسم Index داخل مجلد Home . حيث سنقوم بانشاء روابط مع هذا action 
سنقوم بانشاء رابط في Index View  في MyCourses لاستدعاء Index Action في Home Controller 
 انتقل الى Index View  في MyCourses وقم بانشاء link عن طريق اضافة الكود ادناه 
<a asp-action="Index" asp-controller="Home">Back</a>
سيكون شكل الصفحة كالتالي : 



لاحظ انه بهذه الطريقة سيتم الرجوع الى Home في Student Portal . 
ملاحظة : عند اضافة اي Controller تأكد من اضافة Route في هذا Controller 
مثلا في Home Controller  تأك من اضافة  [Area("StudentPortal")] 

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Areas.StudentPortal.Controllers
{
    [Area("StudentPortal")]
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

The ‘asp-route-area’ Tag Helper
للتنقل بين Areas في التطبيق يمكن استخدام Tag Helper المسمى asp-area=" area  name"
سنقوم بإنشاء area جديدة في التطبيق باسم  Teachers.كما في الصورة: 


ثانيًا ، أضف Controller باسم Home في Controllers folder ثم اضف الكود التالي:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Areas.Teachers.Controllers
{
    public class HomeController : Controller
    {
        [Area("Teachers")]
        public IActionResult Index()
        {
            return View();
        }
    }
}
اضف View بالنقر يمين فوق Index action في HomeController في هذه area.  ثم اضف الكود التالي اليها: 

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    This Home View from Student Portal Teachers Area
</body>
</html>
لنعد الان الى Index View في MyCourses ثم اضف الكود التالي: 

<a asp-route-area="Teachers" asp-action="Index" asp-controller="Home" >Teacher List</a> 
الكود كامل لهذا ال View سيكون : 
@model IEnumerable<MyCourses>
@{ ViewBag.Title = "All Courses";}
<h2>All Reservations</h2>
<link href="~/lib/bootstrap/dist/css/bootstrap.css.map" rel="stylesheet" />
<a asp-action="Index" asp-controller="Home">Back</a>
<a asp-route-area="Teachers" asp-action="Index" asp-controller="Home" >Teacher List</a>
<table class="table table-bordered table-sm table-striped">
    <thead>
        <tr>
            <th scope="col">CourseNumber</th>
            <th scope="col">CourseName</th>
            <th scope="col">Course Description</th>
            <th scope="col">Course Price</th>
            <th scope="col">Capacity</th>
            <th scope="col">CreatedDate</th>
        </tr>
    </thead>
    <tbody>
        @if (Model != null)
        {
            foreach (var r in Model)
            {
                <tr>
                    <td>@r.CourseNumber</td>
                    <td>@r.CourseName</td>
                    <td>@r.CourseDescription</td>
                    <td>@r.Price</td>
                    <td>@r.Capacity</td>
                    <td>@r.CreatedDate</td>
                </tr>
            }
        }
    </tbody>
</table>
قم بتشغيل المشروع ستكون نتيجة التشغيل كالتالي: 

يعمل هذا الكود على استدعاء Index Action  في Controllers Home  في Teachers area 
جرب شغل الصفحة وحاول التنقل بين الصفحات