zoukankan      html  css  js  c++  java
  • Asp.Net MVC4 系列--进阶篇之路由 (2)

    上一篇介绍了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;
    }
    <!DOCTYPE html>
    <html>
    <head>
    <meta name="viewport"content="width=device-width" />
    <title>ActionName</title>
    </head>
    <body>
    <div>The controller is:@ViewBag.Controller</div>
    <div>The action is: @ViewBag.Action</div>
    <div>
    @Html.ActionLink("This is an outgoing URL", "CustomVariable") 
    </div>
    </body>
    </html>

    这样就会生成:

    <a href="/Home/CustomVariable">This is anoutgoing URL</a>

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

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

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

    使用同样的代码:

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

    此时url连接就会生成为:

    <a href="/App/DoCustomVariable">This is anoutgoing URL</a>

    因为当我们访问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连接就是:
    <a href="/Home/CustomVariable?id=Hello">This is an outgoingURL</a>
    如果对于路由:
    routes.MapRoute("MyRoute","{controller}/{action}/{id}",
    new { controller ="Home", action = "Index",
    id = UrlParameter.Optional });
    那么生成的url就是:

    <a href="/Home/CustomVariable/Hello">This is an outgoingURL</a>

    设定html属性

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

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

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

    <a class="myCSSClass"href="/"id="myAnchorID">This is an outgoing URL</a>
    生成一个绝对路径的url连接

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

    通常,不建议生成绝对路径的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,使用另一个重载:

    public  RedirectToRouteResult  TestRedirect()
            {
                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; 
    } 
    <h2>GetLegacyURL</h2> 
    The URL requested was: @Model

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

    public class LegacyRoute : RouteBase { 
    private  string[] urls; 
    public  LegacyRoute(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 = "~/articles/Windows_3.1_Overview" })

    就会生成:

    <a href="/articles/Windows_3.1_Overview">Click me</a>

    自定义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,验证结果正确。

  • 相关阅读:
    67家基金子公司背景脉络梳理
    港股奇葩术语知多少
    68家信托公司7大派系股东分食图谱
    港股术语
    流动性陷阱
    ORACLE归档模式和非归档模式的利与弊
    肥尾效应
    DVP
    金融衍生品如何定价
    绿鞋机制
  • 原文地址:https://www.cnblogs.com/smartsmile/p/6234080.html
Copyright © 2011-2022 走看看