Heim  >  Artikel  >  Backend-Entwicklung  >  Die umfassendste ASP.NET MVC-Routing-Konfiguration in der Geschichte

Die umfassendste ASP.NET MVC-Routing-Konfiguration in der Geschichte

巴扎黑
巴扎黑Original
2017-04-09 11:15:115281Durchsuche

Lassen Sie uns zunächst über die Grundprinzipien der Routing-Regeln sprechen. Die grundlegenden Routing-Regeln sind von speziell nach allgemein geordnet, d. h. die speziellsten (nicht zum Mainstream gehörenden) Regeln stehen vorne und die allgemeinsten Regeln (einheitlich für alle) stehen am Ende. Dies liegt daran, dass übereinstimmende Routing-Regeln ebenfalls dieser Reihenfolge folgen. Wenn Sie es rückwärts schreiben, warten Sie immer noch auf 404, selbst wenn Sie die Routing-Regeln korrekt schreiben.

XD Lassen Sie uns zunächst über die Struktur der URL sprechen. Tatsächlich handelt es sich hierbei nicht um eine Struktur, sondern nur um ein grammatikalisches Merkmal.

URL-Konstruktion

Benannte Parameterspezifikation + anonymes Objekt

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

Konstruieren Sie die Route und fügen Sie

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

hinzu Direkte Methodenüberladung + anonymes Objekt

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

Persönlich denke ich, dass der erste einfacher zu verstehen ist, der zweite einfacher zu debuggen ist und der dritte effizienter zu schreiben ist. Nehmen Sie, was Sie brauchen. Der Text dieses Artikels ist auf den dritten Typ ausgerichtet.

Routing-Regeln

1.Standardrouting (im Lieferumfang von MVC enthalten)

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

2. Statisches URL-Segment

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" });

Ohne Platzhalter-Routing ist es vorgefertigt und fest codiert.

Wenn Sie beispielsweise so schreiben und dann http://localhost:XXX/Shop/OldAction.js besuchen, ist die Antwort kein Problem. Die drei reservierten Wörter Controller, Action und Area sollten nicht in statischen Variablen platziert werden.

3. Passen Sie das reguläre variable URL-Segment an (naja, diese Übersetzung verrät Ihren IQ)

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

Wenn Sie in diesem Fall auf /Home/Index zugreifen, wird dieser Parameter gemäß den Routing-Regeln auf DefaultId

gesetzt, da das dritte Segment (ID) keinen Wert hat. Dies lässt sich deutlich erkennen, indem man viewbag verwendet, um dem Titel

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

einen Wert zuzuweisen Das Bild wird nicht mehr gepostet und der Titel wird als DefaultId angezeigt. Beachten Sie, dass Sie Werte im Controller zuweisen müssen. Das Zuweisen von Werten in der Ansicht wird nicht kompiliert.

4. Rufen Sie die Standardroute ab

Kehren Sie dann zur Standardroute zurück. UrlParameter.Optional wird als optionales URL-Segment bezeichnet. Wenn in der Route kein solcher Parameter vorhanden ist, ist die ID null. Laut Originalartikel kann dieses optionale URL-Segment genutzt werden, um eine Trennung der Anliegen zu erreichen. Es ist eigentlich nicht sehr gut, den Parameter-Standardwert gerade direkt in der Route festzulegen. Nach meinem Verständnis werden die tatsächlichen Parameter vom Benutzer gesendet und wir definieren lediglich die formalen Parameternamen. Wenn Sie jedoch darauf bestehen, Parametern Standardwerte zuzuweisen, empfiehlt es sich, diese mit syntaktischem Zucker in die Aktionsparameter zu schreiben. Zum Beispiel:

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

5. Routing mit variabler Länge.

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

Hier sind sowohl die ID als auch das letzte Segment variabel, sodass /Home/Index/dabdafdaf äquivalent zu /Home/Index//abcdefdjldfiaeahfoeiho ist äquivalent zu /Home/Index/All/Delete/Perm/.....

6. Namensraumübergreifendes Routing

Dies ist eine Erinnerung daran, den Namespace anzugeben und die IIS-Website zu öffnen, da sonst ein 404-Fehler auftritt. Das ist sehr untypisch und es ist nicht empfehlenswert, sich damit herumzuschlagen.

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

Wenn Sie es jedoch so schreiben, erfolgt die Array-Rangfolge in keiner bestimmten Reihenfolge. Wenn mehrere übereinstimmende Routen vorhanden sind, wird ein Fehler gemeldet. Dann schlug der Autor eine verbesserte Schreibmethode vor.

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" });

Auf diese Weise wird das erste URL-Segment, wenn es nicht Home ist, zur Verarbeitung an das zweite übergeben. Schließlich können Sie auch festlegen, dass, wenn diese Route nicht gefunden wird, kein Weg für nachfolgende Routen frei bleibt es wird nicht mehr nach unten schauen.

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. Route zum Abgleich regulärer Ausdrücke

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

Beschränken Sie mehrere URLs

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. Geben Sie die Anforderungsmethode an

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. WebForm-Unterstützung

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+" } });

Einzelheiten finden Sie unter

Erstellen Sie eine WebForm-Anwendung mit dem Asp.Net4-Routing neuer Funktionen

Oder offizielles MSDN

10. RouteAttribute von MVC5

Gehen Sie zunächst zur Routing-Registrierungsmethode

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

Hier entlang

[Route("Login")]

Die Routenfunktion ist nur wirksam. Es gibt auch Routing-Einschränkungen, Reihenfolge, Routennamen usw.

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

[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的风格我就很喜欢,都是实例写作,然后还在那边书里面专门写了大量的测试。

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

Das obige ist der detaillierte Inhalt vonDie umfassendste ASP.NET MVC-Routing-Konfiguration in der Geschichte. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn