إنشاء عناوين URL Outgoing في Views

-

بنتعلم في هذا الدرس كيفية استخدام URL Routing  أيضًا لإنشاء Outgoing URL(links) في Views. بحيث تعمل على معالجة قضايا مهمة لأن الروابط يتم إنشاؤها تلقائيًا بناءً على المسارات routes  في التطبيق. لذلك إذا قمت بتغيير routes ، فسيتم تغيير links التي تم إنشاؤها في Views  تلقائيًا بناءً على new route ولن تضطر إلى تغيير الروابط يدويًا واحدة تلو الأخرى.

لفهم كيفية إنشاء outgoing links.

خلونا نتأكد أولاً من وجود المسار route التالي فقط في التطبيق الخاص بنا:

app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
            });

بعد ذلك ، تأكد من وجود View من نوع View Imports داخل مجلد Views في حال عدم وجودها تأكد من إضافة View (انقر بزر الماوس الأيمن على مجلد Views وحدد Add ➤ New Item).
الهدف من View Imports   هو ادراج جميع namespaces التي سنحتاج الى استخدامها في التطبيق في مكان واحد بدل من ادراجاها بشكل منفصل في كل Views. 
تأكد من إضافة الكود التالي في View Imports
 
@using StudentsAcademy
@using StudentsAcademy.Models
@using Microsoft.AspNetCore.Http
@inject Microsoft.AspNetCore.Http.IHttpContextAccessor HttpContextAccessor
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

الغرض من  ASP.NET Core Tag Helpers namespace  هو إنشاء links في Views التي سيتم استخدامها في التطبيق.
سنعمل الان على إضافة رابط باسم Outgoing URL AllStudent بغرض فهم المقصود بذلك
انتقل بعد ذلك إلى Index View  في Home Controller لديك وأضف الكود أدناه:

<a asp-action="AllStudent">AllStudent Outgoing URL</a>

نفهم الكود:
الامر "asp-action="AllStudent هي عبارة عن asp-action tag helper حيث تعمل على تشكيل هذا link.
يعمل  tag helper هذا على اخبار MVC باسم action method التي يجب أن تستهدفها href attribute الخاصة ب anchor’s .
لاحظ أن ASP.NET Core هنا يستهدف action محدد في controller نفسها حيث توجد View. وبالتالي فإن outgoing link يستهدف AllStudent action  الخاص ب Home controller.

قم بتشغيل التطبيق بالانتقال الى الرابط 
https://localhost:44382/home/index

استخدم Developer Tools في متصفحك. لذا انقر بزر الماوس الأيمن فوق الرابط ثم اختر Inspect . كما في الصورة في الاسفل



ستجد HTML الخاص بالرابط الذي تم تشكيله هو:
<a href="/Home/AllStudent"> AllStudent Outgoing URL</a> 
انشاء URL Outgoing مع Controller مختلفه
في حال كنا بحاجه الى ربط Action من Controller مع Controller آخر، فسيتعين علينا أيضًا استخدام asp-controller tag helper في anchor tag.
تمام وحتى نفهم الموضوع أضف الكود أدناه في Index View في Home Controller حيث سنقوم بإضافة رابط ل Index action في admin controller :
   <a asp-action="AllStudent">AllStudent Outgoing URL</a>
    <br />
    <a asp-controller="Admin" asp-action="Index">ShowCourses Outgoing URL</a>
سيكون شكل الرابط الجديد عند عمل inspect كالتالي:
<a href="/Admin"> ShowCourses Outgoing URL </a>
يعتبر انشاء Link في Net Core.  ذكي جدا Link Generation is Smart

تمام التمام ننتقل إلى AllStudent View    في Home Controller  وخلونا نشئ a link لفتح Index action method.

  <a asp-action="Index">Go to Index</a>
ستجد الرابط الذي تم تكوينه في هذه الحالة يحتوي فقط / وليس Home/Index ، انظر أدناه:
<a href="/">Go to Index</a>
والسبب في ذلك هو انه حددنا route (في ملف Startup.cs) والي بتكون من : 
Home  هي default Controller 
Index  هي default action. 
MVC framework  ذكي بما يكفي ولهذا لا يضيف اسمي Controller و Action على Href attribute.

إنشاء روابط من Attribute Routes
يمكن أيضًا تكوين Outgoing links بناءً على Attribute Routing.
وحتى نفهم كيف خلونا نرجع الى  Admin controller حيث اضفنا  attribute routing كما هو موضح أدناه:


using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Controllers
{
    [Route("Student/[controller]/DashBoard/[action]/{id:allowCity?}")]
    public class AdminController : Controller
    {
      // [Route("[controller]/DashBoard")]
        
        public string Index()
        {
            return "@@#Admin@@# Controller, @@#Index@@# View";
        }
        public string List()
        {
            return "@@#Admin@@# Controller, @@#List@@# View";
        }
        [Route("[controller]/DashBoard/[action]")]
        public string Show()
        {
            return "@@#Admin@@# Controller, @@#Show@@# View";
        }
    }
}

اكيد بتذكر ان اضافنا سابقا في Index View في Home Controller الكود التالي:
<a asp-controller="Admin" asp-action="Index">ShowCourses Outgoing URL</a>
سيتشكل هذا link بناء على Attribute Routing ، كما هو موضح أدناه:
<a href="/Student/Admin/DashBoard/Index">ShowCourses Outgoing URL</a>

إنشاء Outgoing Links عند وجود مسارات متعددة Multiple Routes

يمكن أن يكون لديك عدة طرق موجودة في التطبيق. عند إنشاء outgoing link، يقوم routing system  بمعالجة routes بالترتيب الذي تم تعريفها به. تعتمد حالة المطابقة على الشروط الثلاثة:
  • تزويد كل URL segment  بقيمة.
  • بالنسبة ل default-only variables ، يجب إما عدم توفير القيمة أو توفير القيمة التي تطابق قيمتها الافتراضية.

Default-only variables  هي تلك الغير الموجودة في عنوان URL ولكن يتم توفير قيمة افتراضية لها عن طريق routes في  ملف Startup.

مثال، افترض أن route الموضح أدناه يحتوي على متغير يسمى myCountry وهو المتغير الافتراضي فقط. لذلك لكي يقوم نظام route بإجراء المطابقة، يجب عليك إما عدم توفير القيمة للمتغير myCountry أو توفير القيمة Jordan له (وهي القيمة الافتراضية).

app.UseEndpoints(endpoints =>
{
    // Outgoing linss generations
    endpoints.MapControllerRoute(
        name: "defaultonly",
        pattern: "{controller}/{action}",
        defaults: new { myCountry = "Jordan" });
});

  • يجب أن تلبي قيم segment variables  قيود المسار route constraint.
مثال: إنشاء  Linkعند وجود مسارات متعددة

لنفترض أن لديك 2 routes في مشروعك كما هو موضح أدناه:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "Student",
        pattern: "Student/{action}",
        defaults: new { controller = "Home" });
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

انتقل الآن إلى Index View  الخاص ب Home Controller  وأضف الكود التالي لإنشاء روابط جديده:

@{ Layout = null; }
<!DOCTYPE html>
<html>
<head>
    <title>Routing</title>
</head>
<body>
    <h1>@@#Home@@# Controller, @@#Index@@# View</h1>
    <hr />
    @ViewBag.CitName
    <a asp-action="AllStudent">AllStudent Outgoing URL</a>
    <br />
    <a asp-controller="Admin" asp-action="Index">ShowCourses Outgoing URL</a>
    <br />
    <a asp-action="Index">Link1</a>
    <br />
    <a asp-controller="Admin">Link2</a>
</body>
</html>
ستجد الرابط الأول يتكون من المسار الأول (AllStudent) ويتكون الارتباط الثاني من المسار الثاني (أي الرابط الافتراضي Admin). يحدث هذا بسبب 3 نقاط من إنشاء الارتباط التي ذكرناها سابقًا.
<a href="/Students/AllStudent">AllStudent Outgoing URL</a>
<a href="/Admin">ShowCourses Outgoing URL</a>

تمرير القيم إلى Segments Variable بخلاف Controller and Action
تعلمنا فيما سبق انشاء روابط باستخدام Controllers and Action methods ، ويمكن أيضا تمرير قيم الى متغير segment variable مثل id 
للقيام بذلك، سنستخدم Tag Helper يسمى
 asp-route- * 
كل ما عيلك فعله هو استبدل * باسم segment variable مثل id.
تمام وحتى نفهم الموضوع نطبق مثال : 

قم بإنشاء Controller تسمى StudentPortalController.cs وأضف Index Action  إليها بحيث يستقبل متغير باسم Id من نوع Int.
الكود :
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Controllers
{
    public class StudentPortalController : Controller
    {
        public string Index(int id)
        {
            return "Id Value is: " + id;
        }
    }
}
لاستدعاء هذه controller وعرض قيمة ال Id الموجود داخلها. سنقوم بربط هذه method من Home Controller’s  بطريقة تمرر فيها قيمة 100 ل Id segment.
سنستخدم هنا tag helper المسمى
 asp-route-*  
وذلك بإضافة رابط الكود أدناه إلى Home Controller’s Index View:

<a asp-controller="StudentPortal" asp-action="Index" asp-route-id="100">Pass 100 to the id segment in Student Portal Index View</a>
قم بتشغيل التطبيق بالانتقال الى الرابط : 
https://localhost:44382/home/index
ستكون نتيجة التنفيذ كما في الصورة: 


عند النقر فوق الرابط سيتم استدعاء StudentPortal controller 
ستكون النتيجة 


يمكن ايضا تمرير قيمة إلى segment variable  غير موجود في route ؟ 
في هذه الحالة ، سيمرر ASP.NET Core هذه القيمة في Query String.
انتقل الى ملف Startup.cs وتأكد من وجود الكود التالي داخله

  app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });

انتقل الى Index Action في StudentPortalController ثم اضف parameter  من نوع  string  كما هو موضح في الاسفل:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace StudentsAcademy.Controllers
{
    public class StudentPortalController : Controller
    {
        public string Index(int id, string name)
        {
            return "Id Value is: " + id + " Name value is: " + name;
        }
    }
}

انتقل الان مجددا الى Index View في Home Controller ، ثم قم بتعديل link السابق بحيث اضفنا كود جديد "asp-route-name="Layan  كما هو موضح أدناه:
<a asp-controller="StudentPortal" asp-action="Index" asp-route-id="100" asp-route-name="Layan">Pass 100 to the id segment in Student Portal Index View</a>
لنقم بتشغيل التطبيق بالانتقال الى الرابط:
https://localhost:44382/home/index

كما تلاحظ في الرابط ان Link يحتوي على name value بقيمة Layan تم تمريرها ك query string وذلك لعدم وجود segment variable باسم name في route.

انقر فوق link ستكون نتيجة التنفيذ كما في الصورة:

يمكنك تمرير أي عدد من query stings  باستخدام الطريقة المذكورة أعلاه.

إنشاء روابط من طريق Route محدد
يمكنك أيضًا إنشاء outgoing link بناء على specific route معرف مسبقا.
لنفترض وجود route افترضي في مشروعك كما في الكود:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "StudentPortal",
        pattern: " StudentPortal/{controller=Home}/{action=Index}");
});

لإنشاء ارتباط بناءً عليه ، يمكنك استخدام tag helper 
asp-route="name of the route".
هذا يعني أنه في View عن إضافة رابط جديد يكون الكود كما في الاسفل:

<a asp-route="StudentPortal"> StudentPortal </a>

تستخدم asp-route attribute فقط عندما تكون سمات asp-controller و asp-action غير موجوده. هذا يعني أن route يجب أن يكون له default value ل Controller and Action.
إنشاء عناوين URL فقط ، مثل HREF للروابط
تُستخدم طريقة
 Url.Action() 
لإنشاء عنوان URL، أي href attribute of Links.
سنقوم باستدعاء الرابط السابق Index action  في StudentPortalController باستخدام طريقة URLs
انتقل الى Index Action في Home Controller، أضف الرابط أدناه:
<p><a href=" @Url.Action("Index", "StudentPortal", new { id = 100 })">Call StudentPortal Index using URL</a></p>
قم بتشغيل التطبيق بالانتقال الى الرابط 
https://localhost:44382/home/index
ستكون نتيجة التنفيذ: 

تأخذ طريقة ()Url.Action  مجموعة من parameters هي:
  • Controller name.
  • Action name.
يمكنك أيضًا استخدام طريقة ()Url.Action في action method باستخدام  #C. الكود في الاسفل يوضح الطريقة.
string url = Url.Action("CustomVariable", "Home", new { id = 100 });


Adding URL Fragment (#)
URL fragment  الذي يُشار إليه بالعلامة (#) هو الجزء الأخير الاختياري من عنوان URL في document، يتم استخدامه عادةً لتحديد جزء من المستند document.
في HTML documents، يبحث المتصفح عن anchor tag بحيث يتطابق اسم  name attribute  مع  fragment.
على سبيل المثال، في عنوان URL الموضح أدناه، يبحث المتصفح على tag مطابقة لها بحيث يكون ال id  لها يسمى Printing  ويقوم بتمرير الصفحة لعرض هذا القسم:
<a href="/StudentPortal/Index#Printing">Printing</a>
لإنشاء URL Fragment ، استخدم  tag helper المسمى
 asp-fragment="fragment-name" .
الكود أدناه يعمل على إنشاء URL Fragment:
<a asp-controller=" StudentPortal" asp-action="Index" asp-fragment="Printing">
    URL Fragment
</a>
شكل URL بعد التنفيذ سيكون 
<a href="/StudentPortal/Index#Printing">URL Fragment</a>
يتم استخدام RouteOptions object أيضًا لعمل configure عند URL generation، حيث يحتوي على شرطة مائلة (/).
لتطبيق ذلك يجب إضافة بعض الكود في ()ConfigureServices  في class Startup.cs كما هو موضح بالأسفل:

لاحظ انه تم إضافة السطر
 options.AppendTrailingSlash = true
إلى الجزء الذي يقوم بعمل  Configure  ل RouteOptions.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<RouteOptions>(options =>
            {
                options.AppendTrailingSlash = true;
            });
    services.AddControllersWithViews();
}
قم بتشغيل التطبيق الخاص بك وستلاحظ ان الروابط التي تم إنشاؤها في View كل منهم تنتهي بشرطة مائلة (/).
 http://localhost:58470/Home/Check/
تغيير URLs الى Lowercase
يمكن جعل جميع الأحرف في عناوين URL أحرف صغيرة، وذلك بإضافة الكود 
options.LowercaseUrls = true
في ConfigureServices  في Startup class كما في الكود في الأسفل:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<RouteOptions>(options =>
    {
        options.AppendTrailingSlash = true;
        options.LowercaseUrls = true;
    });
    services.AddControllersWithViews();
}