zoukankan      html  css  js  c++  java
  • (19)URL—其实我更想懂你:路由用户到特定的Controller和Action

    问题

    当今如此对搜索引擎霸主的争夺战是如此激烈,像下边这样的网站地址很难在这场比赛中获胜:http://www.example.com/books/details?id=4

    使用路由,网站可以变成这样:

    http://www.example.com/20-recipes-for-mvc3

    无论是对用户还是搜索引擎,这将提供更多的语境。

    解决方案

    使用RouteCollectionExtensions 类下的MapRoute 函数去生成更友好的名字去展示内容而不是数字ID。

    讨论

    在MVC中可以通过Web.config和Global.asax.cs文件设置路由。在web.config中包含 System.Web.Routing程序集并且在Global.asax.cs中使用它去对在它其中的所有controller和action创建一个默认的路由机制。因此在添加BooksController的时候,可以通过/Books 访问不带扩展名的 URL,就像在ASP.NET 官网那样。

    接下来的秘方将演示设立几个不同的有用的技术去创建路由。

    第一个路由将允许网站直接连接到book的title上。例如,有一本书叫MVC3的20个秘方,它可以通过http://localhost /20 Recipes for Programming MVC 3这个地址被直接访问。然而当前的解决方案就需要一个更复杂的URL就像:http://localhost/Books/Details?id=1。要开始创建这个路由,打开在MVC project里的Global.asax.cs文件。在RegisterRoutes()函数里创建里了一个默认的路由。在第一次加载网站的时候 Application_Start()函数会调用它。下边的例子包含一个更新的RegisterRoutes 函数,添加了一个新的路由到MapRoute函数中:

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using MvcApplication.Models;
    using System.Data.Entity;
    using System.Globalization;
    using System.Threading;
    namespace MvcApplication
    {
        public class MvcApplication : System.Web.HttpApplication
        {
            public static void RegisterGlobalFilters(
            GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
            }
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                routes.MapRoute(
                "BookName", // Route name
                "{Keyword}", // URL with parameters
                new
                {
                    controller = "Books",
                    action = "Index",
                    id = UrlParameter.Optional
                },
                new { Keyword = "w+" });
                routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}",
                    // URL with parameters
                new
                {
                    controller = "Home",
                    action = "Index",
                    id = UrlParameter.Optional
                }
                );
            }
            protected void Application_Start()
            {
                Database.SetInitializer<BookDBContext>(
                new BookInitializer());
                AreaRegistration.RegisterAllAreas();
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
            }
            protected void Application_AcquireRequestState(
            object sender, EventArgs e)
            {
                if (HttpContext.Current.Session != null)
                {
                    CultureInfo ci =
                    (CultureInfo)this.Session["CurrentLanguage"];
                    if (ci == null)
                    {
                        ci = new CultureInfo("en");
                        this.Session["CurrentLanguage"] = ci;
                    }
                    Thread.CurrentThread.CurrentUICulture = ci;
                    Thread.CurrentThread.CurrentCulture =
                    CultureInfo.CreateSpecificCulture(ci.Name);
                }
            }
        }
    }
     

    在上边的例子里,MapRoute 函数接收4个参数。

    1. route name,在这里是BookName。
    2. 附带任何参数的URL。在这里是{Keyword},这是可变的,一会儿会用到。
    3. 这个参数默认的是controller ,action和任何附加的变量。在这个例子里,默认的controller是Books 并且Action是Index
    4. 他包含(例如,变量)对于URL。在这里,前边提到的Keyword变量传递到BooksController的Index action上。

    当搜索关键字时,他可以在URL的域名后边输入一个书名或关键字,如果仅仅返回了一个结果,用户将被重定向到详细信息页面,并看到那本书。否则用户将看到一个根据他关键字的搜索结果。在下一个例子里。一个新的路由将被创建。它将口占RouteBase类。均需一个更复杂的路由。将用一个子域名替代在域名后边输入书名。例如 http://mvc3book.localhost/ 将返回上述图书的详细内容-MVC3编程的20个秘方。

    为了让这成为可能,BOOK model 需要被更新去包含一个新的参数,名为“ShortName”。      此参数将被用来作为子域,并允许书籍通过创建扩展的RouteBase类的类进行搜索。

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.ComponentModel.DataAnnotations;
    using MvcApplication.Validations;
     
    namespace MvcApplication.Models
    {
        public class Book
        {
            public int ID { get; set; }
     
            [Required]
            public string ShortName { get; set; }
     
            [Required]
            [Display(Name = "TitleDisplay", ResourceType = typeof(Resources.Resource1))]
            public string Title { get; set; }
     
            [Display(Name = "IsbnDisplay", ResourceType = typeof(Resources.Resource1))]
            [Required]
            [IsbnValidation]
            public string Isbn { get; set; }
     
            [Display(Name = "SummaryDisplay", ResourceType = typeof(Resources.Resource1))]
            [Required]
            public string Summary { get; set; }
     
            [Display(Name = "AuthorDisplay", ResourceType = typeof(Resources.Resource1))]
            [Required]
            public string Author { get; set; }
     
            [Display(Name = "ThumbnailDisplay", ResourceType = typeof(Resources.Resource1))]
            public string Thumbnail { get; set; }
     
            [Display(Name = "PriceDisplay", ResourceType = typeof(Resources.Resource1))]
            [Range(1, 100)]
            public double Price { get; set; }
     
            [Display(Name = "PublishedDisplay", ResourceType = typeof(Resources.Resource1))]
            [DataType(DataType.Date)]
            [Required]
            public DateTime Published { get; set; }
        }
     
    }
     

    现在必须创建一个新的类将包含新的路由背后的逻辑。选择Utils文件夹中,右键单击并选择“添加→类。这个新的类将被称为 BookDomainRoute.cs。下面的类将从Request.Headers为当前HttpContext检索域名。该域名将被.”操作符的分成 “数组。执行一些错误检查以确保我们有一个子域名不是WWW。

    第一块子域,例如,ShortName,是用来执行书本上表的搜索,找到特定书籍。如果查找到了书籍,创建一个新的对象类RouteData,设置 Controller为Books,Action 设置为Detail,最后的ID是这本书的ID。如果没有找到书籍,主页将显示出来。在下面的例子,它可以很容易改变以直接导航用户到一个错误页或根据 Keyword 跳转到Books/index 页(在前面的例子)。

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Routing;
    using System.Web.Mvc;
    using MvcApplication.Models;
     
    namespace MvcApplication.Utils
    {
        public class BookDomainRoute : RouteBase
        {
            private BookDBContext db = new BookDBContext();
     
            public override RouteData GetRouteData(HttpContextBase httpContext)
            {
                // Get the domain name
                var url = httpContext.Request.Url.Authority;
                // Split into array of parts
                var pieces = url.Split('.');
      
                // Ensure there is a subdomain and it's not www
                if (pieces.Length < 2 && pieces[0] != "www")
                {
                    return null;
                }
     
                string ShortName = pieces[0];
      
                // Find the book by ShortName
                var books = from b in db.Books select b;
                books = books.Where(b => b.ShortName.ToUpper().Contains(ShortName.ToUpper()));
     
                // Check to make sure a book was found
                if (books.Count() == 0)
                {
                    return null;
                }
     
                // Get the first result
                Book book = books.First();
     
                // Set the route data
                RouteData routeData = new RouteData(this, new MvcRouteHandler());
                routeData.Values.Add("controller", "Books");
                routeData.Values.Add("action", "Details");
                routeData.Values.Add("id", book.ID);
     
                return routeData;
            }
      
            public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
            {
                return null;
            }
        }
    }
     

    最后Global.asax.cs文件必须再次更新,包括新创建的路由。为了使新的路由类可以找到。需要添加using语句到utils目录。

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using MvcApplication.Models;
    using System.Data.Entity;
    using System.Globalization;
    using System.Threading;
    using MvcApplication.Utils;
     
    namespace MvcApplication
    {
        // Note: For instructions on enabling IIS6 or IIS7 classic mode,
     
        public class MvcApplication : System.Web.HttpApplication
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
            }
     
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
     
                routes.Add(new BookDomainRoute());
     
                routes.MapRoute(
                    "BookName", // Route name
                    "{Keyword}", // URL with parameters
                    new { controller = "Books", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
                    new { Keyword = "w+" });
     
                routes.MapRoute(
                    "Default", // Route name
                    "{controller}/{action}/{id}", // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
                );
     
            }
     
            protected void Application_Start()
            {
                Database.SetInitializer<BookDBContext>(new BookInitializer());
     
                AreaRegistration.RegisterAllAreas();
     
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
     
                String connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["BooksDBContext"].ConnectionString;
                System.Web.Caching.SqlCacheDependencyAdmin.EnableNotifications(connectionString);
                System.Web.Caching.SqlCacheDependencyAdmin.EnableTableForNotifications(connectionString, "Books");
            }
     
            protected void Application_AcquireRequestState(object sender, EventArgs e)
            {
                if (HttpContext.Current.Session != null)
                {
                    CultureInfo ci = (CultureInfo)this.Session["CurrentLanguage"];
                    if (ci == null)
                    {
                        ci = new CultureInfo("en");
                        this.Session["CurrentLanguage"] = ci;
                    }
       
                    Thread.CurrentThread.CurrentUICulture = ci;
                    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name);
                }
            }
        }
    }
     

    上述的例子包含良好的使用路由的伟大的开始。两者都可以很容易地更新执行其他路由,例如,子域名可以用来显示用户的特定的个人资料页,或以前实施的多语种秘方可更新为使用一个路由类允许象en.example.com或fr.example.com一样的URL设置当前的语言文化。

    年轻不是你玩的理由,而是你奋斗的资本
  • 相关阅读:
    好学习法
    error execution phase upload-config/kubelet: Error writing Crisocket information for the control-plane node: timed out waiting for the condition
    linux 大实话
    解决vi/vim中粘贴 格式错乱
    centos7 调试系统服务命令
    gitlab jenkins docker kubernetes
    修改centos7主机名
    野战ci/cd
    相互交流生成快捷网页链接
    设置centos7静态网卡配置文件
  • 原文地址:https://www.cnblogs.com/lyaxx1314/p/3603526.html
Copyright © 2011-2022 走看看