مدیریت Legacy URLs توسط MVC

در این مقاله با کمک کلاس LegacyUrlRoute یک Route اختصاصی خواهیم نوشت و توسط آن آدرس های وارد شده را به آدرس دلخواه تغییر داده و سپس این آدرس را به Action مورد نظر جهت پردازش ارسال می کنیم.

مدیریت Legacy URLs توسط MVC

Routing یا مسیریابی دریافت یک بسته اطلاعاتی از از يک دستگاه و ارسال آن از طريق شبکه برای دستگاهی ديگر و بر روی شبکه ای متفاوت است

در Asp.Net کلاسیک یک رابطه مستقیم بین URL های درخواست شده از سوی کاربر و فایل های هارد دیسک سرور وجود داشت .بعد از دریافت آدرس از URL سرور فایل ها ی درخواست شده را از هارد دیسک خود ارائه می داد..اما این روش در MVC کاربردی ندارد.چرا که درخواست ها داخل Action های کنترلرها پردازش می شوند.برای مدیریت درخواست های وارده از URL فرم ورک MVC از روش Routing System استفاده می کند.

سیستم روتینگ کار نگاشت آدرس به Pattern را انجام می دهد.کاراین سیستم   Map کردن درخواستهای ورودی برای مشخص نمودن کنترلرهای MVC می باشد. اگر این سیستم موفق به مسیردهی درخواستهای ورودی نشود MVC  پیغام خطای 404 تولید می نماید. سیستم مسیریابی ASP.NET از Route Table (جدول مسیر) استفاده می کند.در اولین اجرای برنامه Route Table ایجاد می شود.بار اولی که برنامه MVC اجرا می شود متد Application_Start  که در داخل Global.asax قرار دارد صدا زده می شود و این متد خود RegisterRoutes را صدا می زند.در داخل این کلاس می توانیم توسط دستور routes.IgnoreRouteاز فریم ورک بخواهیم که از بعضی مسیر ها چشم پوشی نماید. همچنین در داخل این کلاس می توانیم Route سفارشی هم اضافه کنیم .توجه داشته باشید که این مسیر جدید باید قبل از Route  اصلی سیستم باشد.نمونه مسیر اضافه شده به صورت زیر است

 routes.MapRoute("Show",
                "{controller}/{id}/{title}",
                new { controller = "Employees", action = "Show", id = UrlParameter.Optional, title = "" });

پس برای Register  کردن مسیر های خود در کلاس Rout.Confige از متد RegisterRoutesاستفاده می کنیم.این متد حداقل دو آرگومان می گیرد .یک نام برای route و دیگری Url ایی که Route با آن همخوانی دارد.

در کد بالا توسط      routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

از آدرس های دارای پسوند .axd که فایل های سیستمی و منابع هستند چشم پوشی می شود و اصلا پردازش نمی شوند.

 متغیر id یک متغیر اختیاری است و  UrlParameter.Optional به آن نسبت داده شده است. با داشتن یک متغیر اختیاری ، route  ما با دامنه وسیع تری از URL ها match خواهد شد. اگر در URL یک سگمنت سومی هم باشد ، به متغیر id نسبت داده خواهد شد، در غیر این صورت از آن صرف نظر خواهد شد.

تا اینجا افزودن یک Route یا مسیر جدید به پروژه خود را آموختید ولی برخی از مواقع نیاز است که از کلاس RouteBase ارث بری کرده و یک کلاس جدید برای مسیریابی بنویسیم .

در چه مواقعی نیاز به این کار است ؟ فرض کنید شما یک سایتی دارید که آن را با Asp.net Web Form نوشته اید .این سایت شما مثلا یک صفحه ای داشته است به نام http://localhost:5485/Employees.aspx?empId=1  و این صفحه هم هزاران بار بازدید شده است و هم اکنون با همین نام در گوگل و یا سایر موتورهای جستجو ایندکس شده است ، حال قصد ارتقا Application خود را دارید و می خواهید آنرا به معماری MVC ارتقا دهید.بعد از انجام این کار آدرس های شما به آدرس ها جدید MVC تغییر پیدا خواهد کرد آیا می خواهید با هزاران بازدید کننده خداحافظی کنید و یا اینکه می خواهید با جایگاه بالای خود در موتو های جستجو خداحافظی کنید؟

در این مواقع یک کلاسی باید بنویسیم که آدرس قبلی ما را دریافت کرده و آنرا به آدرس جدید Map کرده و سپس این آدرس جدید را به Action مورد نظر برای انجام درخواست ارسال کند.

ابتدا یک کلاسی خواهیم نوشت برای اینکه Url دریافتی را از – و فاصله پاک کند و یک Url  تمیز به ما تحویل دهد.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace HandlingRoute.Models
{
   
        public static class UrlTidy
        {
            public static string ToCleanUrl(string urlToTidy)
            {
                var url = urlToTidy.Trim();
                url = url.Replace("  ", " ").Replace(" - ", " ").Replace(" ", "-").Replace(",", "").Replace("...", "");
                return url;
            }
        }
    
}

سپس در Map.route یک Route  تعریف می کنیم

 routes.MapRoute("Show",
                "{controller}/{id}/{title}",
                new { controller = "Employees", action = "Show", id = UrlParameter.Optional, title = "" });

Action مورد نظر هم به صورت زیر است .

   public ActionResult Show(int? id,string title)
        {
            ViewBag.Show = title;
            //repository.GetArticle(id);
            return View(db.Employees.Find(id));
        }

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

 public class LegacyUrlRoute : RouteBase
    {
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            const string status = "301 Moved Permanently";
            var request = httpContext.Request;
            var response = httpContext.Response;
            var title = "";
            var legacyUrl = request.Url.ToString();
            var newUrl = "";
            var id = request.QueryString.Count != 0 ? request.QueryString[0] : "";

            if (legacyUrl.Contains("Employees.aspx"))
            {
                var rep = new EmployeeRepository();
                var emp = rep.GetEmployeeFullName(Convert.ToInt32(id));
                foreach (var a in emp)
                    title = UrlTidy.ToCleanUrl(a.Headline);
                newUrl = "Employees/" + id + "/" + title;
                response.Status = status;
                response.RedirectLocation = newUrl;
                response.End();
            }
            return null;
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext,
                    RouteValueDictionary values)
        {
            return null;
        }
    }

در این کلاس از یک تابع به نام  GetEmployeeFullName استفاده شده است . این تابع از آدرس قبلی و با استفاده از Query String مقدار id را به دست می آورد و با این مقدار نام و نام خانوادگی کارمند را بازیابی می کند.سپس آن را به آدرس جدید تبدیل می کند.

  class EmployeeRepository
    {
        HandlingRouteContext de = new HandlingRouteContext();
        public IEnumerable<EmployeeTitle> GetEmployeeFullName(int id)
        {
            return (de.Employees
                       .Where(a => a.ID == id)
                       .Select(a => new EmployeeTitle
                       {
                           Headline = a.Name + " " + a.Family
                       }));

        }
    }

 حالا کافی است که از این کلاس در  Route.configeاستفاده کنیم .همان طور که در کد زیر می بینید در خط  routes.Add(new LegacyUrlRoute()); مسیریابی جدید خود را به MVC معرفی کرده ایم .

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.Add(new LegacyUrlRoute());

اگر برنامه را اجرا کنید می بیند که با زدن آدرس http://localhost:5485/Employees.aspx?empId=1   به آدرس http://localhost:5485/Employees/1 هدایت میشوید.

فایل های ضمیمه
دانلود نسخه ی PDF این مطلب