Фреймворки Python всегда предоставляют способы обработки URL-адресов, которые передают данные запроса элегантным способом, например, http://somewhere.overtherainbow.com/userid/123424/
Я хочу, чтобы вы обратили внимание на конечный путь / userid / 123424 /
Как это сделать в ASP.NET?





Также обратите внимание на ASP.NET MVC или, если вы настроены на веб-формы, на новое пространство имен System.Web.Routing в ASP.NET 3.5 SP1.
В этом примере для реализации понятных URL-адресов используется маршрутизация ASP.NET.
Примеры отображений, которые обрабатывает приложение:
http: // samplesite / userid / 1234 - http: //samplesite/users.aspx? userid = 1234
http: // samplesite / userid / 1235 - http: //samplesite/users.aspx? userid = 1235
В этом примере используются строки запроса и не требуется изменять код на странице aspx.
<system.web>
<compilation debug = "true">
<assemblies>
…
<add assembly = "System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</assemblies>
</compilation>
…
<httpModules>
…
<add name = "UrlRoutingModule" type = "System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</httpModules>
</system.web>
<system.webServer>
…
<modules>
…
<add name = "UrlRoutingModule" type = "System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</modules>
<handlers
…
<add name = "UrlRoutingHandler" preCondition = "integratedMode" verb = "*" path = "UrlRouting.axd" type = "System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</handlers>
</system.webServer>
Определите отображение удобного URL-адреса на страницу aspx, сохранив запрошенный ИД пользователя для дальнейшего использования.
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add("UseridRoute", new Route
(
"userid/{userid}",
new CustomRouteHandler("~/users.aspx")
));
}
Добавьте строку запроса в текущий контекст до того, как начнется маршрутизация.
using System.Web.Compilation;
using System.Web.UI;
using System.Web;
using System.Web.Routing;
public class CustomRouteHandler : IRouteHandler
{
public CustomRouteHandler(string virtualPath)
{
this.VirtualPath = virtualPath;
}
public string VirtualPath { get; private set; }
public IHttpHandler GetHttpHandler(RequestContext
requestContext)
{
// Add the querystring to the URL in the current context
string queryString = "?userid = " + requestContext.RouteData.Values["userid"];
HttpContext.Current.RewritePath(
string.Concat(
VirtualPath,
queryString));
var page = BuildManager.CreateInstanceFromVirtualPath
(VirtualPath, typeof(Page)) as IHttpHandler;
return page;
}
}
Код на странице aspx для справки.
protected void Page_Load(object sender, EventArgs e)
{
string id = Page.Request.QueryString["userid"];
switch (id)
{
case "1234":
lblUserId.Text = id;
lblUserName.Text = "Bill";
break;
case "1235":
lblUserId.Text = id;
lblUserName.Text = "Claire";
break;
case "1236":
lblUserId.Text = id;
lblUserName.Text = "David";
break;
default:
lblUserId.Text = "0000";
lblUserName.Text = "Unknown";
break;
}
Это альтернативный пример, который также использует маршрутизацию ASP.NET для реализации удобных URL-адресов.
Примеры отображений, которые обрабатывает приложение:
http: // samplesite / userid / 1234 - http: //samplesite/users.aspx? userid = 1234
http: // samplesite / userid / 1235 - http: //samplesite/users.aspx? userid = 1235
В этом примере не использует строки запроса, но требуется дополнительный код на странице aspx.
<system.web>
<compilation debug = "true">
<assemblies>
…
<add assembly = "System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</assemblies>
</compilation>
…
<httpModules>
…
<add name = "UrlRoutingModule" type = "System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</httpModules>
</system.web>
<system.webServer>
…
<modules>
…
<add name = "UrlRoutingModule" type = "System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</modules>
<handlers
…
<add name = "UrlRoutingHandler" preCondition = "integratedMode" verb = "*" path = "UrlRouting.axd" type = "System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</handlers>
</system.webServer>
Определите отображение удобного URL-адреса на страницу aspx, сохранив запрошенный ИД пользователя для дальнейшего использования.
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add("UseridRoute", new Route
(
"userid/{userid}",
new CustomRouteHandler("~/users.aspx")
));
}
Передайте на страницу контекст маршрутизации, содержащий параметр. (Обратите внимание на определение IRoutablePage)
using System.Web.Compilation;
using System.Web.UI;
using System.Web;
using System.Web.Routing;
public interface IRoutablePage
{
RequestContext RequestContext { set; }
}
public class CustomRouteHandler : IRouteHandler
{
public CustomRouteHandler(string virtualPath)
{
this.VirtualPath = virtualPath;
}
public string VirtualPath { get; private set; }
public IHttpHandler GetHttpHandler(RequestContext
requestContext)
{
var page = BuildManager.CreateInstanceFromVirtualPath
(VirtualPath, typeof(Page)) as IHttpHandler;
if (page != null)
{
var routablePage = page as IRoutablePage;
if (routablePage != null) routablePage.RequestContext = requestContext;
}
return page;
}
}
Обратите внимание на реализацию IRoutablePage.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Routing;
public partial class users : System.Web.UI.Page, IRoutablePage
{
protected RequestContext requestContext;
protected object RouteValue(string key)
{
return requestContext.RouteData.Values[key];
}
protected void Page_Load(object sender, EventArgs e)
{
string id = RouteValue("userid").ToString();
switch (id)
{
case "1234":
lblUserId.Text = id;
lblUserName.Text = "Bill";
break;
case "1235":
lblUserId.Text = id;
lblUserName.Text = "Claire";
break;
case "1236":
lblUserId.Text = id;
lblUserName.Text = "David";
break;
default:
lblUserId.Text = "0000";
lblUserName.Text = "Unknown";
break;
}
}
#region IRoutablePage Members
public RequestContext RequestContext
{
set { requestContext = value; }
}
#endregion
}
С этой реализацией мне повезло больше, чем с другой. У queryString были проблемы при использовании Ajax. Эта реализация немного сложнее, но она того стоила.
Во-первых, вот код контроллера с двумя действиями. Индекс получает список пользователей из модели, идентификатор пользователя получает отдельного пользователя:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace MvcApplication1.Controllers
{
public class UsersController : Controller
{
public ActionResult Index()
{
return View(Models.UserDB.GetUsers());
}
public ActionResult userid(int id)
{
return View(Models.UserDB.GetUser(id));
}
}
}
Вот представление Index.asp, оно использует ActionLink для создания ссылок в правильном формате:
<%@ Page Language = "C#" AutoEventWireup = "true" CodeBehind = "Index.aspx.cs" Inherits = "MvcApplication1.Views.Index" %>
<%@ Import Namespace = "MvcApplication1.Controllers" %>
<%@ Import Namespace = "MvcApplication1.Models" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml" >
<head runat = "server">
<title></title>
</head>
<body>
<div>
<h2>Index of Users</h2>
<ul>
<% foreach (User user in (IEnumerable)ViewData.Model) { %>
<li>
<%= Html.ActionLink(user.name, "userid", new {id = user.id })%>
</li>
<% } %>
</ul>
</div>
</body>
</html>
А вот представление userid.aspx, в котором отображаются сведения о человеке:
<%@ Page Language = "C#" AutoEventWireup = "true" CodeBehind = "userid.aspx.cs" Inherits = "MvcApplication1.Views.Users.userid" %>
<%@ Import Namespace = "MvcApplication1.Controllers" %>
<%@ Import Namespace = "MvcApplication1.Models" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml">
<head runat = "server">
<title></title>
</head>
<body>
<div>
<table border = "1">
<tr>
<td>
ID
</td>
<td>
<%=((User)ViewData.Model).id %>
</td>
</tr>
<tr>
<td>
Name
</td>
<td>
<%=((User)ViewData.Model).name %>
</td>
</tr>
</table>
</div>
</body>
</html>
И, наконец, для полноты картины приведем код модели:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplication1.Models
{
public class UserDB
{
private static List<User> users = new List<User>{
new User(){id=12345, name = "Bill"},
new User(){id=12346, name = "Claire"},
new User(){id=12347, name = "David"}
};
public static List<User> GetUsers()
{
return users;
}
public static User GetUser(int id)
{
return users.First(user => user.id == id);
}
}
public class User
{
public int id { get; set; }
public string name { get; set; }
}
}
Я использую переписчик URL от Intelligencia:
Настроить его было так просто - может быть, час на то, чтобы все это настроить и запустить. Очень мало проблем с этим ...
Я бы порекомендовал это, но должен отметить, что не пробовал других.
Удачи!
Я разработал Библиотека NuGet с открытым исходным кодом для этой проблемы, который неявно преобразует EveryMvc / Url в каждый-mvc / url.
Пунктирные URL-адреса намного удобнее для SEO и легче читаются. URL-адреса в нижнем регистре, как правило, создают меньше проблем. (Подробнее в моем сообщении в блоге)
Пакет NuGet: https://www.nuget.org/packages/LowercaseDashedRoute/
Чтобы установить его, просто откройте окно NuGet в Visual Studio, щелкнув правой кнопкой мыши Project и выбрав NuGet Package Manager, а на вкладке «Online» введите «Lowercase Dashed Route», и он должен появиться.
В качестве альтернативы вы можете запустить этот код в консоли диспетчера пакетов:
Install-Package LowercaseDashedRoute
После этого вы должны открыть App_Start / RouteConfig.cs и закомментировать существующий вызов route.MapRoute (...) и добавить вместо него следующее:
routes.Add(new LowercaseDashedRoute("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
new DashedRouteHandler()
)
);
Вот и все. Все URL-адреса в нижнем регистре, пунктирные и неявно конвертируются без каких-либо дополнительных действий.
URL-адрес проекта с открытым исходным кодом: https://github.com/AtaS/lowercase-dashed-route
Я знаю, что это старый, но он получил высокие оценки в Google. Есть ли причина, по которой GetHttpHandler никогда не вызывается? Я помещаю туда код, генерирующий ошибку времени выполнения, и, конечно же, вызываются все методы, кроме GetHttpHandler, по запросу.