Maison  >  Article  >  développement back-end  >  La configuration de routage ASP.NET MVC la plus complète de l'histoire

La configuration de routage ASP.NET MVC la plus complète de l'histoire

巴扎黑
巴扎黑original
2017-04-09 11:15:115332parcourir

Parlons d’abord des principes de base des règles de routage. Les règles de routage de base sont classées du spécial au général, c'est-à-dire que les règles les plus spéciales (non traditionnelles) se trouvent au début et les règles les plus générales (taille unique) se trouvent à la fin. En effet, les règles de routage correspondantes suivent également cet ordre. Si vous l'écrivez à l'envers, même si vous écrivez correctement les règles de routage, vous attendrez toujours 404.

XD Parlons d’abord de la structure de l’URL. En fait, il ne s’agit pas d’une structure, mais simplement d’une caractéristique grammaticale.

Construction d'URL

Spécification du paramètre nommé + objet anonyme

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

Construisez l'itinéraire et ajoutez

Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler());
routes.Add("MyRoute", myRoute);

Surcharge de méthode directe + objet anonyme

routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" });

Personnellement, je pense que le premier est plus facile à comprendre, le second est plus facile à déboguer et le troisième est plus efficace à écrire. Prenez ce dont vous avez besoin. La rédaction de cet article est orientée vers le troisième type.

Règles de routage

1.Routage par défaut (livré avec MVC)

routes.MapRoute(
"Default", // 路由名称
"{controller}/{action}/{id}", // 带有参数的 URL
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值 (UrlParameter.Optional-可选的意思) );

2. Segment d'URL statique

routes.MapRoute("ShopSchema2", "Shop/OldAction", new { controller = "Home", action = "Index" });
 
routes.MapRoute("ShopSchema", "Shop/{action}", new { controller = "Home" });
routes.MapRoute("ShopSchema2", "Shop/OldAction.js",
 new { controller = "Home", action = "Index" });

Sans routage d'espace réservé, il est prêt à l'emploi et codé en dur.

Par exemple, si vous écrivez ainsi et visitez ensuite http://localhost:XXX/Shop/OldAction.js, la réponse ne posera aucun problème. Les trois mots réservés contrôleur, action et zone ne doivent pas être placés dans des variables statiques.

3. Personnalisez le segment d'URL variable régulier (enfin, cette traduction expose votre QI)

routes.MapRoute("MyRoute2", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "DefaultId" });

Dans ce cas, si vous accédez à /Home/Index, car le troisième segment (id) n'a aucune valeur, ce paramètre sera défini sur DefaultId

selon les règles de routage. Cela peut être clairement vu en utilisant viewbag pour attribuer une valeur au titre

ViewBag.Title = RouteData.Values["id"];

L'image n'est plus publiée et le résultat est que le titre s'affiche comme DefaultId. Notez que vous devez attribuer des valeurs dans le contrôleur. L'attribution de valeurs dans la vue ne sera pas compilée.

4. Rappeler l'itinéraire par défaut

Revenez ensuite à l'itinéraire par défaut. UrlParameter.Optional est appelé un segment d'URL facultatif. S'il n'y a pas de paramètre de ce type dans l'itinéraire, l'identifiant sera nul. Selon l'article original, ce segment d'URL facultatif peut être utilisé pour parvenir à une séparation des préoccupations. Il n'est en fait pas très bon de définir directement la valeur par défaut du paramètre dans l'itinéraire pour le moment. D'après ma compréhension, les paramètres réels sont envoyés par l'utilisateur et tout ce que nous faisons est de définir les noms formels des paramètres. Cependant, si vous insistez pour attribuer des valeurs par défaut aux paramètres, il est recommandé d'utiliser du sucre syntaxique pour les écrire dans les paramètres d'action. Par exemple :

public ActionResult Index(string id = "abcd"){ViewBag.Title = RouteData.Values["id"];return View();}

5. Routage de longueur variable.

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });

Ici, l'identifiant et le dernier segment sont tous deux variables, donc /Home/Index/dabdafdaf est équivalent à /Home/Index//abcdefdjldfiaeahfoeiho est équivalent à /Home/Index/All/Delete/Perm/.....

6. Routage inter-espaces de noms

Ceci est un rappel de ne pas oublier de citer l'espace de noms et d'ouvrir le site Web IIS, sinon il obtiendra un 404. Ceci est très peu courant et il n’est pas recommandé de s’en occuper.

routes.MapRoute("MyRoute","{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "URLsAndRoutes.AdditionalControllers", "UrlsAndRoutes.Controllers" });

Mais si vous l'écrivez de cette façon, le classement du tableau ne sera pas dans un ordre particulier. S'il existe plusieurs itinéraires correspondants, une erreur sera signalée. L'auteur a ensuite proposé une méthode d'écriture améliorée.

routes.MapRoute("AddContollerRoute","Home/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "URLsAndRoutes.AdditionalControllers" });
 
routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}", new { controller = "Home", action = "Index", id = UrlParameter.Optional },new[] { "URLsAndRoutes.Controllers" });

De cette façon, si le premier segment d'URL n'est pas Home, il sera transmis au second pour traitement. Enfin, vous pouvez également définir que si cette route n'est pas trouvée, elle ne laissera pas de chemin pour les routes suivantes, donc. il ne baissera plus les yeux.

Route myRoute = routes.MapRoute("AddContollerRoute",
"Home/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "URLsAndRoutes.AdditionalControllers" });  myRoute.DataTokens["UseNamespaceFallback"] = false;

7. Itinéraire de correspondance d'expressions régulières

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
 new { controller = "Home", action = "Index", id = UrlParameter.Optional },
 new { controller = "^H.*"},
new[] { "URLsAndRoutes.Controllers"});

Contraindre plusieurs URL

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { controller = "^H.*", action = "^Index$|^About$"},
new[] { "URLsAndRoutes.Controllers"});

8. Précisez la méthode de demande

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
 
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
 
new { controller = "^H.*", action = "Index|About", httpMethod = new HttpMethodConstraint("GET") },
 
new[] { "URLsAndRoutes.Controllers" });

9. Prise en charge du formulaire Web

routes.MapPageRoute("", "", "~/Default.aspx");
 
 routes.MapPageRoute("list", "Items/{action}", "~/Items/list.aspx", false, new RouteValueDictionary { { "action", "all" } });
 
 routes.MapPageRoute("show", "Show/{action}", "~/show.aspx", false, new RouteValueDictionary { { "action", "all" } });
 
 routes.MapPageRoute("edit", "Edit/{id}", "~/edit.aspx", false, new RouteValueDictionary { { "id", "1" } }, new RouteValueDictionary { { "id", @"\d+" } });

Pour plus de détails, veuillez consulter

Créer une application WebForm à l'aide du nouveau routage de fonctionnalités Asp.Net4

Ou msdn officiel

10.RouteAttribute de MVC5

Tout d'abord, accédez à la méthode d'enregistrement du routage

//启用路由特性映射
routes.MapMvcAttributeRoutes();

Par ici

[Route("Login")]

La fonctionnalité d'itinéraire n'est efficace que. Cette fonctionnalité présente plusieurs surcharges. Il existe également des contraintes de routage, l'ordre, les noms d'itinéraire, etc.

.

其他的还有路由前缀,路由默认值

[RoutePrefix("reviews")]<br>[Route("{action=index}")]<br>public class ReviewsController : Controller<br>{<br>}

 路由构造

// eg: /users/5
[Route("users/{id:int}"]
public ActionResult GetUserById(int id) { ... }
 
// eg: users/ken
[Route("users/{name}"]
public ActionResult GetUserByName(string name) { ... }

 参数限制

// eg: /users/5
// but not /users/10000000000 because it is larger than int.MaxValue,
// and not /users/0 because of the min(1) constraint.
[Route("users/{id:int:min(1)}")]
public ActionResult GetUserById(int id) { ... }
Constraint Description Example
alpha Matches uppercase or lowercase Latin alphabet characters (a-z, A-Z) {x:alpha}
bool Matches a Boolean value. {x:bool}
datetime Matches a DateTime value. {x:datetime}
decimal Matches a decimal value. {x:decimal}
double Matches a 64-bit floating-point value. {x:double}
float Matches a 32-bit floating-point value. {x:float}
guid Matches a GUID value. {x:guid}
int Matches a 32-bit integer value. {x:int}
length Matches a string with the specified length or within a specified range of lengths. {x:length(6)}  {x:length(1,20)}
long Matches a 64-bit integer value. {x:long}
max Matches an integer with a maximum value. {x:max(10)}
maxlength Matches a string with a maximum length. {x:maxlength(10)}
min Matches an integer with a minimum value. {x:min(10)}
minlength Matches a string with a minimum length. {x:minlength(10)}
range Matches an integer within a range of values. {x:range(10,50)}
regex Matches a regular expression. {x:regex(^\d{3}-\d{3}-\d{4}$)}

具体的可以参考

Attribute Routing in ASP.NET MVC 5

 对我来说,这样的好处是分散了路由规则的定义.有人喜欢集中,我个人比较喜欢这种灵活的处理.因为这个action定义好后,我不需要跑到配置那里定义对应的路由规则

11.最后还是不爽的话自己写个类实现 IRouteConstraint的匹配方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
/// <summary>
/// If the standard constraints are not sufficient for your needs, you can define your own custom constraints by implementing the IRouteConstraint interface.
/// </summary>
public class UserAgentConstraint : IRouteConstraint
{
 
    private string requiredUserAgent;
    public UserAgentConstraint(string agentParam)
    {
        requiredUserAgent = agentParam;
    }
    public bool Match(HttpContextBase httpContext, Route route, string parameterName,
    RouteValueDictionary values, RouteDirection routeDirection)
    {
        return httpContext.Request.UserAgent != null &&
        httpContext.Request.UserAgent.Contains(requiredUserAgent);
    }
}
routes.MapRoute("ChromeRoute", "{*catchall}",
 
new { controller = "Home", action = "Index" },
 
new { customConstraint = new UserAgentConstraint("Chrome") },
 
new[] { "UrlsAndRoutes.AdditionalControllers" });

 比如这个就用来匹配是否是用谷歌浏览器访问网页的。

12.访问本地文档

routes.RouteExistingFiles = true;
 
routes.MapRoute("DiskFile", "Content/StaticContent.html", new { controller = "Customer", action = "List", });

浏览网站,以开启 IIS Express,然后点显示所有应用程序-点击网站名称-配置(applicationhost.config)-搜索UrlRoutingModule节点

<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />

把这个节点里的preCondition删除,变成

<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />

 13.直接访问本地资源,绕过了路由系统

routes.IgnoreRoute("Content/{filename}.html");

文件名还可以用 {filename}占位符。

IgnoreRoute方法是RouteCollection里面StopRoutingHandler类的一个实例。路由系统通过硬-编码识别这个Handler。如果这个规则匹配的话,后面的规则都无效了。 这也就是默认的路由里面routes.IgnoreRoute("{resource}.axd/{*pathInfo}");写最前面的原因。

路由测试(在测试项目的基础上,要装moq)

PM> Install-Package Moq
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web;
using Moq;
using System.Web.Routing;
using System.Reflection;
[TestClass]
public class RoutesTest
{
    private HttpContextBase CreateHttpContext(string targetUrl = null, string HttpMethod = "GET")
    {
        // create the mock request
        Mock<HttpRequestBase> mockRequest = new Mock<HttpRequestBase>();
        mockRequest.Setup(m => m.AppRelativeCurrentExecutionFilePath)
        .Returns(targetUrl);
        mockRequest.Setup(m => m.HttpMethod).Returns(HttpMethod);
        // create the mock response
        Mock<HttpResponseBase> mockResponse = new Mock<HttpResponseBase>();
        mockResponse.Setup(m => m.ApplyAppPathModifier(
        It.IsAny<string>())).Returns<string>(s => s);
        // create the mock context, using the request and response
        Mock<HttpContextBase> mockContext = new Mock<HttpContextBase>();
        mockContext.Setup(m => m.Request).Returns(mockRequest.Object);
        mockContext.Setup(m => m.Response).Returns(mockResponse.Object);
        // return the mocked context
        return mockContext.Object;
    }
 
    private void TestRouteMatch(string url, string controller, string action, object routeProperties = null, string httpMethod = "GET")
    {
        // Arrange
        RouteCollection routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);
        // Act - process the route
        RouteData result = routes.GetRouteData(CreateHttpContext(url, httpMethod));
        // Assert
        Assert.IsNotNull(result);
        Assert.IsTrue(TestIncomingRouteResult(result, controller, action, routeProperties));
    }
 
    private bool TestIncomingRouteResult(RouteData routeResult, string controller, string action, object propertySet = null)
    {
        Func<object, object, bool> valCompare = (v1, v2) =>
        {
            return StringComparer.InvariantCultureIgnoreCase
            .Compare(v1, v2) == 0;
        };
        bool result = valCompare(routeResult.Values["controller"], controller)
        && valCompare(routeResult.Values["action"], action);
        if (propertySet != null)
        {
            PropertyInfo[] propInfo = propertySet.GetType().GetProperties();
            foreach (PropertyInfo pi in propInfo)
            {
                if (!(routeResult.Values.ContainsKey(pi.Name)
                && valCompare(routeResult.Values[pi.Name],
                pi.GetValue(propertySet, null))))
                {
                    result = false;
                    break;
                }
            }
        }
        return result;
    }
 
    private void TestRouteFail(string url)
    {
        // Arrange
        RouteCollection routes = new RouteCollection();
        RouteConfig.RegisterRoutes(routes);
        // Act - process the route
        RouteData result = routes.GetRouteData(CreateHttpContext(url));
        // Assert
        Assert.IsTrue(result == null || result.Route == null);
    }
 
    [TestMethod]
    public void TestIncomingRoutes()
    {
        // check for the URL that we hope to receive
        TestRouteMatch("~/Admin/Index", "Admin", "Index");
        // check that the values are being obtained from the segments
        TestRouteMatch("~/One/Two", "One", "Two");
        // ensure that too many or too few segments fails to match
        TestRouteFail("~/Admin/Index/Segment");//失败
        TestRouteFail("~/Admin");//失败
        TestRouteMatch("~/", "Home", "Index");
        TestRouteMatch("~/Customer", "Customer", "Index");
        TestRouteMatch("~/Customer/List", "Customer", "List");
        TestRouteFail("~/Customer/List/All");//失败
        TestRouteMatch("~/Customer/List/All", "Customer", "List", new { id = "All" });
        TestRouteMatch("~/Customer/List/All/Delete", "Customer", "List", new { id = "All", catchall = "Delete" });
        TestRouteMatch("~/Customer/List/All/Delete/Perm", "Customer", "List", new { id = "All", catchall = "Delete/Perm" });
    }
  
}

  最后还是再推荐一下Adam Freeman写的apress.pro.asp.net.mvc.4这本书。稍微熟悉MVC的从第二部分开始读好了。前面都是入门(对我来说是扯淡)。但总比国内某些写书的人好吧——把个开源项目的源代码下载下来帖到书上面来,然后标题起个深入解析XXXX,然后净瞎扯淡。最后一千多页的巨著又诞生了。Adam Freeman的风格我就很喜欢,都是实例写作,然后还在那边书里面专门写了大量的测试。

  哎没办法啊,技术差距就是这样了。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn