عنوان:

‫بررسی قابلیت Endpoint Routing در ASP.NET Core


نویسنده: محمد جواد ابراهیمی
تاریخ: ۱۳۹۸/۰۲/۱۰ ۱۸:۴۵
آدرس: www.dntips.ir
نحوه کار مکانیزم مسیریابی به این صورت است که ما Route هایمان را مثلا درون میان‌افزار MVC (توسط متد UseMvc) تعریف می‌کنیم و زمانیکه یک درخواست به میان‌افزار MVC میرسد، این میان‌افزار بر اساس اطلاعات Url و Route‌های تعریف شده، اولین Route ایی را که همخوانی داشته باشد، انتخاب کرده و مقادیر مسیر یابی (RouteValues) را استخراج می‌کند و بدین ترتیب می‌فهمد که کدام Controller و Action باید فراخوانی شود.

در Pipeline چون میان‌افزارها به صورت ترتیبی اجرا می‌شوند، تا زمانیکه درخواست ما به میان‌افزار MVC (منظور جایی است که Route‌ها تعریف شده‌اند؛ ولی برای درک بهتر با میان‌افزار MVC مثال میزنیم) نمی‌توانیم از RouteValues استفاده کنیم.
مشکل جایی پیش می‌آید که مثلا برای وبسایت‌های چند زبانه که بر اساس Url کار می‌کنند (مثلا fa/home/index) نیاز داریم قبل از رسیدن به میان‌افزار MVC، زبان جاری (همان fa) را توسط سیستم مسیریابی بخوانیم و Culture برنامه را تغییر بدهیم ولی تا زمانیکه به میان‌افزار MVC نرسیم این کار امکان پذیر نیست.

یک مثال دیگر آن، استفاده از ویژگی EnableCorsAttribute (است که بر خلاف UseCors که مکانیزم CORS را به صورت سراسری اعمال می‌کند) میتوان آن را بر روی یک Action خاص اعمال کرد.
از آنجایی که در مکانیزم مسیریابی قبلی، سیستم Routing بسیار وابسته به MVC است، ما نمی‌توانیم قبل از رسیدن به میان‌افزار MVC، جلوی درخواست‌های غیر مجاز را بگیریم، چرا که به Routing درسترسی نداریم و نمی‌دانیم کدام Controller و Action قرار است فراخوانی بشود.

اما در مکانیزم Endpoint Routing، وقتی یک درخواست می‌آید، همان ابتدا مشخص می‌شود که به کدام Route نگاشت شده؛ درنتیجه بقیه‌ی میان‌افزارهای قبل از MVC هم می‌توانند از سیستم Routing استفاده کرده و اطلاعات داخل Url را درک کنند.

 این قابلیت در ASP Core 2.2، اوایل با نام Dispatcher معرفی شد که بعدا به Endpoint Routing تغییر نام پیدا کرد و به صورت پیشفرض توسط SetCompatibilityVersion ورژن Version_2_2 به بالا فعال می‌شود.
برای استفاده از Endpoint Routing باید میان‌افزار مربوطه را توسط متد UseEndpointRouting اضافه کنیم. کار این میان‌افزار تشخیص Endpoint مورد نظر براساس Url درخواستی و Route‌های تعریف شده است و پس از آن می‌توانیم از مقادیر مسیریابی (RouteValues) استفاده کنیم (حتی قبل از رسیدن به محل تعریف Route ها).
// ASP.NET Core 2.2
public void Configure(IApplicationBuilder app)
{
   app.UseEndpointRouting();

   app.OtherMiddleware(); // Access to route values

   app.UseMvc();
}

نکته : در ASPNET Core 3.0 متد UseEndpointRouting به UseRouting تغییر نام پیدا کرد و نیز تعریف Route (بهتر است بگوییم Endpoint ها) به شکل زیر تغییر پیدا کرده است.
// ASP.NET Core 3.0
public void Configure(IApplicationBuilder app)
{
   app.UseRouting(); 

   app.OtherMiddleware();

   app.UseEndpoints(endpoints =>
   {
      // Mapping of endpoints goes here:
      endpoints.MapControllers()
      endpoints.MapRazorPages()
      endpoints.MapHub<MyChatHub>()
      endpoints.MapGrpcService<MyCalculatorService>()
   });
}

برای غیر فعال کردن قابلیت Endpoint Routing می‌توانید توسط MvcOptions.EnableEndpointRouting = false آن را غیرفعال کنید.

منابع و اطلاعات بیشتر:

نظرات

  • وحید نصیری در ۱۳۹۸/۰۵/۱۹ ۱۲:۵۰
    ارتقاء به ASP.NET Core 3.0 : تغییرات مورد نیاز در فایل آغازین برنامه جهت ارتقاء به Endpoint routing

    اگر در نگارش 2.2، فایل کلاس آغازین برنامه‌ی شما چنین شکلی را دارد:
    public void Configure(IApplicationBuilder app)
    {
        ...
    
        app.UseStaticFiles();
        
        app.UseAuthentication();
    
        app.UseSignalR(hubs =>
        {
            hubs.MapHub<ChatHub>("/chat");
        });
    
        app.UseMvc(routes =>
        {
            routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
        });
    }
    در نگارش 3x به صورت زیر تغییر می‌کند:
    public void Configure(IApplicationBuilder app)
    {
        ...
    
        app.UseStaticFiles();
        
        app.UseRouting();
    
        app.UseAuthentication();
        app.UseAuthorization();
        app.UseCors();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<ChatHub>("/chat");
            endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
        });
    }
    نکاتی که در اینجا حائز اهمیت هستند:
    - متد UseRouting اضافه شده‌است.
    - UseStaticFiles (در صورت نیاز) باید قبل از UseRouting فراخوانی شود.
    - اگر برنامه‌ی شما به مباحث اعتبارسنجی پرداخته و در کنترلرهای آن از فیلتر Authorize استفاده می‌شود، دو تغییر مهم فراخوانی UseAuthentication و سپس UseAuthorization (که این مورد جدید هست) را پس از فراخوانی UseRouting باید انجام دهید. در غیر اینصورت در حین مرور این صفحات و قسمت‌های محافظت شده، برنامه با خطای زیر متوقف خواهد شد:
    Endpoint xyz contains authorization metadata, but a middleware was not found that supports authorization.
    Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code.
    - محل فراخوانی UseCors را (در صورت نیاز) دقیقا مطابق کدهای فوق و به ترتیبی که ذکر شده باید انجام دهید.
    - متدهای UseMvc و یا UseSignalR قبلی، به متد UseEndpoints تبدیل شده‌اند.
    • وحید نصیری در ۱۳۹۸/۰۵/۲۱ ۱۱:۱۹
      ارتقاء به ASP.NET Core 3.0: تغییرات نام متدهای تعاریف مسیریابی

      در اینجا نگاشت کنترلرها داخل متد UseEndpoints انجام می‌شود:
      - اگر از attribute routing استفاده می‌کنید، متد MapControllers را فراخوانی کنید که البته به صورت ضمنی هم فراخوانی می‌شود.
      - متد MapRoute پیشین به MapControllerRoute تغییر نام یافته‌است.
      - متد MapAreaRoute پیشین به MapAreaControllerRoute تغییر نام یافته‌است.
      علت این نوع نامگذاری‌های صریح، این است که اکنون سیستم مسیریابی، فراتر از سیستم MVC را پشتیبانی می‌کند.
      - همانند سابق متدهای MapControllerRoute/MapAreaControllerRoute/MapDefaultControllerRoute به ترتیبی که تعریف می‌شوند، تاثیرگذار خواهند بود.

      در مثال زیر:
      public void Configure(IApplicationBuilder app)
      {
          ...
      
          app.UseRouting();
      
          app.UseEndpoints(endpoints =>
          {
              endpoints.MapControllers();
              endpoints.MapAreaControllerRoute(
                  "admin", 
                  "admin", 
                  "Admin/{controller=Home}/{action=Index}/{id?}");
              endpoints.MapControllerRoute(
                  "default", "{controller=Home}/{action=Index}/{id?}");
          });
      }
      - متد MapControllers، کار پشتیبانی از کنترلرهای attribute-routed را انجام می‌دهد.
      - متد MapAreaControllerRoute، مسیریابی سنتی کنترلرهای درون یک Area را تعریف می‌کند.
      - متد MapControllerRoute، مسیریابی سنتی کنترلرها را تعریف می‌کند.

      اگر از Razor pages استفاده می‌کنید، در اینجا باید متد MapRazorPages را نیز فراخوانی کنید:
      public void Configure(IApplicationBuilder app)
      {
          ...
      
          app.UseRouting();
      
          app.UseEndpoints(endpoints =>
          {
              endpoints.MapRazorPages();
          });
      }
  • وحید نصیری در ۱۳۹۸/۰۵/۲۳ ۱۱:۱۹
    ارتقاء به ASP.NET Core 3.0: دریافت مقادیر Routing پس از فعالسازی Endpoint routing

    تا پیش از معرفی Endpoint routing، اطلاعات مسیریابی جاری را می‌شد از طریق یکی از روش‌های زیر به دست آورد:
      // services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
        private readonly IActionContextAccessor _actionContext;
    
    public MyClass(IActionContextAccessor actionContext)
        {
            _actionContext = actionContext;
        }
    
        public string GetData()
        {
            var routes = _actionContext.ActionContext.RouteData;
            var val = routes.Values["action"]?.ToString() as string;
            return val;
        }
    در اینجا سرویس IActionContextAccessor امکان دسترسی به Context اکشن متد در حال اجرا را در قسمت‌های مختلف برنامه میسر می‌کرد و یا شبیه به آن در یک AuthorizationHandler سفارشی، context آن از نوع AuthorizationFilterContext بود که آن نیز دسترسی به اطلاعات context اکشن متد در حال اجرا را در اختیار برنامه قرار می‌داد:
    protected override async Task HandleRequirementAsync(
       AuthorizationHandlerContext context,
       DynamicPermissionRequirement requirement)
    {
        if (!(context.Resource is AuthorizationFilterContext mvcContext))
        {
          return;
        }
    
        var actionDescriptor = mvcContext.ActionDescriptor;
        actionDescriptor.RouteValues.TryGetValue("area", out var areaName);
        var area = string.IsNullOrWhiteSpace(areaName) ? string.Empty : areaName;
    این روش‌ها دیگر در ASP.NET Core 3.0 کار نمی‌کنند. در اینجا پس از تزریق IHttpContextAccessor به سازنده‌ی کلاس مدنظر، می‌توان توسط متد الحاقی ()HttpContext.GetRouteData به اطلاعات مسیریابی دسترسی داشت:
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Routing;
    
    namespace ASPNETCoreIdentitySample.Services.Identity
    {
        public class DynamicPermissionsAuthorizationHandler : AuthorizationHandler<DynamicPermissionRequirement>
        {
            private readonly IHttpContextAccessor _httpContextAccessor;
    
            public DynamicPermissionsAuthorizationHandler(IHttpContextAccessor httpContextAccessor)
            {
                _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
            }
    
            protected override async Task HandleRequirementAsync(
                 AuthorizationHandlerContext context,
                 DynamicPermissionRequirement requirement)
            {
                var routeData = _httpContextAccessor.HttpContext.GetRouteData();
    
                var areaName = routeData?.Values["area"]?.ToString();
                var area = string.IsNullOrWhiteSpace(areaName) ? string.Empty : areaName;
  • نقوی در ۱۳۹۹/۰۲/۰۷ ۱۵:۲۳
    سلام؛ اگر بخواهیم برای بحث سئو ، www اجباری شود و آدرس از حروف کوچیک تشکیل شده باشد. چه اقدامی باید انجام شود؟