asp.net-web form-URL 路由
URL 路由
下载 Wingtip Toys 示例项目 (C#)或下载电子书 (PDF)
此教程系列将介绍构建 ASP.NET Web 窗体应用程序使用 ASP.NET 4.5 和 Microsoft Visual Studio Express 2013 for Web 的基础知识。 Visual Studio 2013包含 C# 源代码项目可随附于本系列教程。
在本教程中,您将修改 Wingtip Toys 示例应用程序,支持 URL 路由。 路由,使用 Url 友好、 更轻松地请记住,且被搜索引擎更好地支持将 web 应用程序。 本教程上一教程为基础"成员身份和管理",并为 Wingtip Toys 教程系列的一部分。
你将学习:
ASP.NET 路由概述
URL 路由可配置为接受的应用程序请求不会映射到物理文件的 Url。 请求 URL 是只需用户输入到浏览器在网站上查找页的 URL。 使用路由来定义的语义上对用户有意义以及可帮助使用搜索引擎搜索引擎优化 (SEO) 的 Url。
默认情况下,Web 窗体模板包括ASP.NET 友好 Url。 将通过使用实现大部分基本路由工作友好的 Url。 但是,在本教程将添加自定义的路由功能。
在自定义 URL 的路由之前, Wingtip Toys 示例应用程序可以链接到产品使用以下 URL:
https://localhost:44300/ProductDetails.aspx?productID=2
通过自定义 URL 的路由,Wingtip Toys 示例应用程序将链接到相同的产品使用易于阅读 URL:
https://localhost:44300/Product/Convertible%20Car
路由
路由是映射到处理程序的 URL 模式。 该处理程序可以是物理文件,例如 Web 窗体应用程序中的.aspx 文件。 一个处理程序还可以处理请求的类。 若要定义的路由,请通过指定的 URL 模式、 处理程序和 (可选) 单击路由名称创建路由类的实例。
您通过添加到应用程序添加路由Route
对象对静态Routes
属性的RouteTable
类。 路由属性是RouteCollection
对象,用于存储应用程序的所有路由。
URL 模式
URL 模式可以包含文字值和变量 (称为 URL 参数) 的占位符。 文本和占位符中由斜杠分隔的 URL 段的位置 (/
) 字符。
发出对 web 应用程序的请求后,URL 解析为段和占位符,并且变量值提供给请求处理程序。 此过程是类似于分析查询字符串中的数据并将其传递给请求处理程序的方式。 在这两种情况下,变量信息是包含在 URL 中且传递到中的键 / 值对形式的处理程序。 查询字符串键和值是在 URL 中。 对于路由,密钥是 URL 模式中定义的占位符名称和 URL 中的仅值。
通过将它们括在大括号在 URL 模式中,定义占位符 ({
和}
)。 您可以定义多个占位符在段中,但占位符必须分隔文本值。 例如,{language}-{country}/{action}
是有效的路由模式。 但是,{language}{country}/{action}
不是有效的模式,因为没有文本值或占位符之间的分隔符。 因此,路由不能确定位置的值分隔开的语言占位符的值的国家/地区占位符。
映射和注册的路由
可以包括到 Wingtip Toys 示例应用程序的页面的路由之前,必须在应用程序启动时注册路由。 若要注册的路由,您将修改Application_Start
事件处理程序。
当 Wingtip Toys 示例应用程序启动时,它将调用Application_Start
事件处理程序。 此事件处理程序末尾RegisterCustomRoutes
调用方法。 RegisterCustomRoutes
方法将每个路由添加通过调用MapPageRoute
方法的RouteCollection
对象。 使用路由名称、 路由 URL 和物理 URL 定义路由。
第一个参数 ("ProductsByCategoryRoute
") 是路由名称。 它用于在需要时调用的路由。 第二个参数 ("Category/{categoryName}
") 定义可以是动态的 URL 基于代码友好替换。 将填充与生成基于数据的链接的数据控件时使用此路由。 路由所示,如下所示:
C#复制
routes.MapPageRoute(
"ProductsByCategoryRoute",
"Category/{categoryName}",
"~/ProductList.aspx"
);
路由的第二个参数包含由大括号指定一个动态值 ({ }
)。 在这种情况下,categoryName
是一个变量,用于确定适当的路由路径。
备注
Optional
你可能会发现可以更轻松地管理您的代码通过移动RegisterCustomRoutes
到一个单独的类的方法。在中逻辑文件夹中,创建一个单独RouteActions
类。 移动上述RegisterCustomRoutes
方法从Global.asax.cs到新文件RoutesActions
类。 使用RoleActions
类和createAdmin
为了举例说明如何调用的方法RegisterCustomRoutes
方法从Global.asax.cs文件。
您可能还会发现RegisterRoutes
方法调用使用RouteConfig
对象的开始处Application_Start
事件处理程序。 进行此调用以实现默认路由。 创建使用 Visual Studio 的 Web 窗体模板的应用程序时,它是作为默认代码。
检索和使用路由数据
如上所述,可以定义路由。 添加到代码Application_Start
中的事件处理程序Global.asax.cs文件加载的可定义的路由。
设置路由
路由要求添加额外的代码。 在本教程中,您将使用模型绑定来检索RouteValueDictionary
生成使用数据控件中的数据的路由时使用的对象。 RouteValueDictionary
对象将包含属于产品的特定类别的产品名称的列表。 根据数据和路由每个产品创建的链接。
启用路由的类别和产品
接下来,将更新应用程序以使用ProductsByCategoryRoute
确定正确的路由,以便将包含在每个产品类别链接。 此外会更新ProductList.aspx页以包含每个产品的路由的链接。 链接将显示前更改,但链接现在将使用 URL 路由。
将代码添加有关产品的详细信息
现在,更新代码隐藏 (ProductDetails.aspx.cs) 用于ProductDetails.aspx页后,可以使用路由数据。 请注意,新GetProduct
方法还接受的用户具有设置为书签的链接的情况下,使用较旧的非兼容的、 非路由 URL 的查询字符串值。
运行应用程序
可以运行应用程序现在以查看更新的路由。
总结
在本教程中,您添加了类别和产品的路由。 介绍了如何使用模型绑定的数据控件与集成的路由。 在下一步的教程中,您将实现全局错误处理。
- 如何注册 ASP.NET Web 窗体应用程序的路由。
- 如何将路由添加到 web 页。
- 如何从支持的路由的数据库选择数据。
-
在中解决方案资源管理器的 Visual Studio 中,找到并打开Global.asax.cs文件。
-
添加到的黄色突出显示的代码Global.asax.cs文件,如下所示:
C#复制
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Optimization; using System.Web.Routing; using System.Web.Security; using System.Web.SessionState; using System.Data.Entity; using WingtipToys.Models; using WingtipToys.Logic; namespace WingtipToys { public class Global : HttpApplication { void Application_Start(object sender, EventArgs e) { // Code that runs on application startup RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); // Initialize the product database. Database.SetInitializer(new ProductDatabaseInitializer()); // Create custom role and user. RoleActions roleActions = new RoleActions(); roleActions.AddUserAndRole(); // Add Routes. RegisterCustomRoutes(RouteTable.Routes); } void RegisterCustomRoutes(RouteCollection routes) { routes.MapPageRoute( "ProductsByCategoryRoute", "Category/{categoryName}", "~/ProductList.aspx" ); routes.MapPageRoute( "ProductByNameRoute", "Product/{productName}", "~/ProductDetails.aspx" ); } } }
-
在中解决方案资源管理器,打开Site.Master页上,如果已打开。
-
更新ListView控件命名为"
categoryList
"以黄色突出显示的更改,因此标记将出现,如下所示:ASP.NET复制
<asp:ListView ID="categoryList" ItemType="WingtipToys.Models.Category" runat="server" SelectMethod="GetCategories" > <ItemTemplate> <b style="font-size: large; font-style: normal"> <a href="<%#: GetRouteUrl("ProductsByCategoryRoute", new {categoryName = Item.CategoryName}) %>"> <%#: Item.CategoryName %> </a> </b> </ItemTemplate> <ItemSeparatorTemplate> | </ItemSeparatorTemplate> </asp:ListView>
-
在中解决方案资源管理器,打开ProductList.aspx页。
-
更新
ItemTemplate
的元素ProductList.aspx使标记,如下所示显示以黄色突出显示的更新的页:ASP.NET复制
<ItemTemplate> <td runat="server"> <table> <tr> <td> <a href="<%#: GetRouteUrl("ProductByNameRoute", new {productName = Item.ProductName}) %>"> <image src='/Catalog/Images/Thumbs/<%#:Item.ImagePath%>' width="100" height="75" border="1" /> </a> </td> </tr> <tr> <td> <a href="<%#: GetRouteUrl("ProductByNameRoute", new {productName = Item.ProductName}) %>"> <%#:Item.ProductName%> </a> <br /> <span> <b>Price: </b><%#:String.Format("{0:c}", Item.UnitPrice)%> </span> <br /> <a href="/AddToCart.aspx?productID=<%#:Item.ProductID %>"> <span class="ProductListItem"> <b>Add To Cart<b> </span> </a> </td> </tr> <tr> <td> </td> </tr> </table> </p> </td> </ItemTemplate>
-
打开的代码隐藏ProductList.aspx.cs并将以下命名空间添加以黄色突出显示为:
C#复制
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using WingtipToys.Models; using System.Web.ModelBinding; using System.Web.Routing;
-
替换
GetProducts
方法的代码隐藏 (ProductList.aspx.cs) 使用以下代码:C#复制
public IQueryable<Product> GetProducts( [QueryString("id")] int? categoryId, [RouteData] string categoryName) { var _db = new WingtipToys.Models.ProductContext(); IQueryable<Product> query = _db.Products; if (categoryId.HasValue && categoryId > 0) { query = query.Where(p => p.CategoryID == categoryId); } if (!String.IsNullOrEmpty(categoryName)) { query = query.Where(p => String.Compare(p.Category.CategoryName, categoryName) == 0); } return query; }
-
替换
GetProduct
方法的代码隐藏 (ProductDetails.aspx.cs) 使用以下代码:C#复制
public IQueryable<Product> GetProduct( [QueryString("ProductID")] int? productId, [RouteData] string productName) { var _db = new WingtipToys.Models.ProductContext(); IQueryable<Product> query = _db.Products; if (productId.HasValue && productId > 0) { query = query.Where(p => p.ProductID == productId); } else if (!String.IsNullOrEmpty(productName)) { query = query.Where(p => String.Compare(p.ProductName, productName) == 0); } else { query = null; } return query; }
- 按F5运行 Wingtip Toys 示例应用程序。
在浏览器将打开并显示Default.aspx页。 - 单击产品在页面顶部的链接。
上显示所有产品ProductList.aspx页。 (使用端口号) 的以下 URL 显示为浏览器:https://localhost:44300/ProductList
- 接下来,单击汽车页面顶部附近的类别链接。
上显示仅汽车ProductList.aspx页。 (使用端口号) 的以下 URL 显示为浏览器:https://localhost:44300/Category/Cars
- 单击页面列出包含名称的第一辆车的链接 ("可转换为汽车") 以显示产品详细信息。
(使用端口号) 的以下 URL 显示为浏览器:https://localhost:44300/Product/Convertible%20Car
- 接下来,输入到浏览器中的以下非路由 URL (使用端口号):
https://localhost:44300/ProductDetails.aspx?productID=2
该代码仍会识别包含查询字符串时,用户在其中具有设置为书签的链接的情况下的 URL。