Asp.Net MVC4 系列--进阶篇之路由 (2)

2016-12-30 09:56:59来源:oschina作者:深圳大道人点击

第七城市

上一篇介绍了Asp.Net MVC 中,从Http Pipeline上接收到请求如何匹配,匹配限制,以及如何控制在指定命名空间查找,解析出controller和action,并传参。


这篇主要介绍如何使用路由完成url生成,实现页面跳转,以及customize一个路由。


在view中生成一个url连接


路由配置使用默认生成的:



routes.MapRoute(
name:"Default",
url:"{controller}/{action}/{id}",
defaults: new { controller ="Home", action = "Index", id = UrlParameter.Optional }
);

最简单的方法是使用Html.ActionLink ,在home View里添加代码:




@{
Layout = null;
}




ActionName


The controller is:@ViewBag.Controller

The action is: @ViewBag.Action


@Html.ActionLink("This is an outgoing URL", "CustomVariable")



这样就会生成:


This is anoutgoing URL

这样,实际上是生成了在当前controller内,指向另一个action的url。


使用Html.ActionLink生成链接的好处是什么,可以根据当前的路由配置,自动维护生成好的url,上例使用的是默认配置。例如如果路由配置改为:


routes.MapRoute("NewRoute","App/Do{action}",
new { controller = "Home" });

使用同样的代码:


@Html.ActionLink("This is an outgoing URL","CustomVariable")

此时url连接就会生成为:



This is anoutgoing URL

因为当我们访问home controller时,NewRoute 在默认路由之前被匹配到了,就会拿它的pattern来生成url了。


当一个请求来时,路由会检测:


1.Pattern


2.路由限制


3.Assign给匿名对象的默认值,就是解析存在Route Dictionary 里面的那些值



跳转到其他controller

最简单的方式:


@Html.ActionLink("Thistargets another controller", "Index", "Admin")

直接传入第二个参数,指向”admin”controller



生成url连接,同时传参


对于同一个controller:


@Html.ActionLink("This is anoutgoing URL",
"CustomVariable", new {id = "Hello" })

跨controller传值:



@Html.ActionLink("Click me to go to anotherarea","Index", "Test",new {Id="aaa"},null)
意,如果路由成功匹配了传值的参数名称,那么url就会以匹配的格式生成;如果路由匹配成功,可是传的值没有在路由模式中指定,那么就会以?param=value的形式传值。例如,对于以上actionlink,如果是路由:routes.MapRoute("NewRoute","App/Do{action}",
new { controller ="Home" })
那么生成的url连接就是:This is an outgoingURL
如果对于路由:routes.MapRoute("MyRoute","{controller}/{action}/{id}",
new { controller ="Home", action = "Index",
id = UrlParameter.Optional });
那么生成的url就是:


This is an outgoingURL
设定html属性

简单的,还是同样使用Html.ActionLink:


@Html.ActionLink("This is anoutgoing URL",
"Index","Home", null, new {id = "myAnchorID",
@class = "myCSSClass"})

这样就可以生成一个连接,class设为了myCssClass



This is an outgoing URL
生成一个绝对路径的url连接


@Html.ActionLink("This is anoutgoing URL", "Index", "Home",
"https","myserver.mydomain.com", " myFragmentName",
new { id = "MyId"},
new { id ="myAnchorID", @class = "myCSSClass"})
生成:href="https://myserver.mydomain.com/Home/Index/MyId#myFragmentName"
id="myAnchorID">This is an outgoing URL

通常,不建议生成绝对路径的url,如需指向外部连接,可以直接使用html标签。



生成URL

有些场景,只需要生成一个连接,而不想和html.ActionLink建立耦合,那么就可以使用Url.Action:


@Url.Action("Index","Home", new { id = "MyId" })

对于默认route({controller}/{action}/{id})生成:


Home/Index/MyId



在action内生成url
public ViewResult MyActionMethod() {
string myActionUrl = Url.Action("Index",new { id = "MyID" });
string myRouteUrl =Url.RouteUrl(new { controller = "Home", action = "Index"});
//... do something with URLs...
return View();
}

当然,更推荐简单的使用 RedirectToAction(),返回值为RedirectToRouteResult:


public RedirectToRouteResult MyActionMethod() {
return RedirectToAction("Index");
}

如果想跳出当前的controller,使用另一个重载:



publicRedirectToRouteResultTestRedirect()
{
returnRedirectToAction("TestAction", "AnotherController");
}
如果这个请求handle不掉,也不想跳到哪个controller,那就还给route吧(这种场景不多):public RedirectToRouteResult MyActionMethod() {
return RedirectToRoute(new {
controller = "Home",
action = "Index",
id = "MyID" });
}
自定义route system

如果当前route的行为还不能满足场景需要,那么可以自定义route,例如,对于刚从asp.netweb form移植到mvc上的网站,对于旧版本的url,我们也需要支持。


创建controller:


namespace UrlsAndRoutes.Controllers {
public class LegacyController : Controller {
public ActionResult GetLegacyURL(string legacyURL) {
return View((object)legacyURL);
}
}
}

这个controller接收传来的url,打印出当前的url(真正的行为应该是显示出该文件内容)。


View里面显示出controller拿来的url值:


@model string
@{
ViewBag.Title = "GetLegacyURL";
Layout = null;
}

GetLegacyURL


The URL requested was: @Model

完成了简单的controller和view,重点在于后面的route。



public class LegacyRoute : RouteBase {
privatestring[] urls;
publicLegacyRoute(params string[] targetUrls) {
urls = targetUrls;
}
public override RouteData GetRouteData(HttpContextBase httpContext) {
RouteData result = null;
string requestedURL =
httpContext.Request.AppRelativeCurrentExecutionFilePath;
if (urls.Contains(requestedURL, StringComparer.OrdinalIgnoreCase)) {
result = new RouteData(this, new MvcRouteHandler());
result.Values.Add("controller", "Legacy");
result.Values.Add("action", "GetLegacyURL");
result.Values.Add("legacyURL", requestedURL);
}
return result;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext,
RouteValueDictionary values) {
return null;
}

创建一个类,继承了routeBase,重点在后面的那两个需要重写的方法:


GetRouteData和GetVirtualPath


对于getroutedata,我们做的操作时从httpcontext对象里拿当前的requesturl,如果是旧版本url里面的,那么直接就把controller指向legacy,action指向GetLegacyURL,并且把参数一起给了:LegacyURL设为当前的url。如果这个请求不是旧版本url里面,那么简单的返回null,让其他的route对象来handle吧。


对于GetVirtualPath,用于生产Url时,先简单的返回null,后面章节会介绍如何生成url。


最后,注册一下自定义的route:


routes.Add(new LegacyRoute(
"~/articles/test1 ",
"~/old/.NET_1.0_Class_Library"));

可以看到,自定义的route已经生效了。



在自定义route中生成URL

把刚才那个GetVirtualPath的函数做个简单实现:


public override VirtualPathData GetVirtualPath(RequestContext requestContext,
RouteValueDictionary values) {
VirtualPathData result = null;
if(values.ContainsKey("legacyURL") &&
urls.Contains((string)values["legacyURL"],StringComparer.OrdinalIgnoreCase)) {
result = newVirtualPathData(this,
new UrlHelper(requestContext)
.Content((string)values["legacyURL"]).Substring(1));
}
return result;
}

函数功能:把传入的匿名对象的legacyURL的值做字符串截取,把首字符滤掉。


在view加入代码:


@Html.ActionLink("Clickme", "GetLegacyURL",
new { legacyURL = "~https://my.oschina.net/articles/Windows_3.1_Overview" })

就会生成:


Click me
自定义Route Handler

前面的例子,我们都是用MvcRouteHandler,对于场景:http请求需要被httphandler来处理掉,那么就需要customize一个routehandler了。


1.提供一个类继承IRouteHandler


public class CustomRouteHandler : IRouteHandler {
public IHttpHandler GetHttpHandler(RequestContext requestContext) {
return new CustomHttpHandler();
}
}

2.准备好HttpHandler


public class CustomHttpHandler : IHttpHandler {
public bool IsReusable {
get { return false; }
}
public void ProcessRequest(HttpContext context) {
context.Response.Write("Hello");
}
}

用于展示,这个handler拿到httpcontext后仅仅打印出hello。



3.注册一个路由,对于相应的pattern,指向这个routehandler


utes.Add(newRoute("SayHello", new CustomRouteHandler()));routes.Add(new Route("SayHello", new CustomRouteHandler()));


routes.Add(new Route("SayHello", new CustomRouteHandler()));

访问SayHello,验证结果正确。


第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台