我知道Route這裡東西應該算路由,這裡把它放到mvc裡面有些不怎麼合適,但是我想大家多數遇到路由都是在mvc的時候吧.首先我們還是來看看GetRouteData方法吧
[csharp]
public override RouteData GetRouteData(HttpContextBase httpContext)
{
string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults);
if (values == null)
{
return null;
}
RouteData data = new RouteData(this, this.RouteHandler);
if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
{
return null;
}
foreach (KeyValuePair<string, object> pair in values)
{
data.Values.Add(pair.Key, pair.Value);
}
if (this.DataTokens != null)
{
foreach (KeyValuePair<string, object> pair2 in this.DataTokens)
{
data.DataTokens[pair2.Key] = pair2.Value;
}
}
return data;
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults);
if (values == null)
{
return null;
}
RouteData data = new RouteData(this, this.RouteHandler);
if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
{
return null;
}
foreach (KeyValuePair<string, object> pair in values)
{
data.Values.Add(pair.Key, pair.Value);
}
if (this.DataTokens != null)
{
foreach (KeyValuePair<string, object> pair2 in this.DataTokens)
{
data.DataTokens[pair2.Key] = pair2.Value;
}
}
return data;
}
我還是沿用以前的思路,已一個demo來便說明吧,現在假設我的路由信息是:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });
routes.MapRoute(
"Default", // 路由名稱
"{controller}/{action}/{id}", // 帶有參數的 URL
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // 參數默認值
new { controller="([A-Za-z])*" },
new string[] { "MvcApp.Controllers" }
);
我們知道httpContext.Request.AppRelativeCurrentExecutionFilePath的返回值都是以~/打頭的,這裡httpContext.Request.PathInfo為空,多數情況下該屬性也是空的,所以這裡的virtualPath=Home/index。
有關MapRoute的代碼可以參照
[csharp]
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
if (routes == null) {
throw new ArgumentNullException("routes");
}
if (url == null) {
throw new ArgumentNullException("url");
}
Route route = new Route(url, new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0)) {
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
if (routes == null) {
throw new ArgumentNullException("routes");
}
if (url == null) {
throw new ArgumentNullException("url");
}
Route route = new Route(url, new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0)) {
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
首先調用_parsedRoute.Match(virtualPath, this.Defaults)獲取一個RouteValueDictionary ,至於這個方法的具體實現放到後面來說,然後實例化一個RouteData ,並且把先前的RouteValueDictionary的值添加到先前實例化的 RouteData中,如果DataTokens有元素的話也加入到RouteData的DataTokens中來。不過這個過程有個約束的處理
if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
{
return null;
}
其中RouteDirection的定義如下:
public enum RouteDirection
{
IncomingRequest,
UrlGeneration
}
約束檢查失敗而返回null,現在我們來看看ProcessConstraints方法:
private bool ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection)
{
if (this.Constraints != null)
{
foreach (KeyValuePair<string, object> pair in this.Constraints)
{
if (!this.ProcessConstraint(httpContext, pair.Value, pair.Key, values, routeDirection))
{
return false;
}
}
}
return true;
}
如果Constraints有元素,依次檢查每個成員,檢查方法主要是調用ProcessConstraint方法,
[csharp]
protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
object obj2;
IRouteConstraint constraint2 = constraint as IRouteConstraint;
if (constraint2 != null)
{
return constraint2.Match(httpContext, this, parameterName, values, routeDirection);
}
string str = constraint as string;
if (str == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_ValidationMustBeStringOrCustomConstraint"), new object[] { parameterName, this.Url }));
}
values.TryGetValue(parameterName, out obj2);
string input = Convert.ToString(obj2, CultureInfo.InvariantCulture);
string pattern = "^(" + str + ")$";
return Regex.IsMatch(input, pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase);
}
protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
object obj2;
IRouteConstraint constraint2 = constraint as IRouteConstraint;
if (constraint2 != null)
{
return constraint2.Match(httpContext, this, parameterName, values, routeDirection);
}
string str = constraint as string;
if (str == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_ValidationMustBeStringOrCustomConstraint"), new object[] { parameterName, this.Url }));
}
values.TryGetValue(parameterName, out obj2);
string input = Convert.ToString(obj2, CultureInfo.InvariantCulture);
string pattern = "^(" + str + ")$";
return Regex.IsMatch(input, pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase);
}這裡首先檢查我們的約束類型,如果它是IRouteConstraint那麼就直接調用它的Match方法,約束不是IRouteConstraint那麼就轉化為字符串,再把約束驗證的值從RouteValueDictionary 中取出來轉化為字符串,最後在用正則表達式來驗證我們的值是否通過。
好,現在讓我們來看看this._parsedRoute.Match(virtualPath, this.Defaults);這個方法是然後獲取RouteValueDictionary的:
[csharp]
public RouteValueDictionary Match(string virtualPath, RouteValueDictionary defaultValues)
{
IList<string> source = RouteParser.SplitUrlToPathSegmentStrings(virtualPath);
if (defaultValues == null)
{
defaultValues = new RouteValueDictionary();
}
RouteValueDictionary matchedValues = new RouteValueDictionary();
bool flag = false;
bool flag2 = false;
for (int i = 0; i < this.PathSegments.Count; i++)
{
PathSegment segment = this.PathSegments[i];
if (source.Count <= i)
{
flag = true;
}
string a = flag ? null : source[i];
if (segment is SeparatorPathSegment)
{
if (!flag && !string.Equals(a, "/", StringComparison.Ordinal))
{
return null;
}
}
else
{
ContentPathSegment contentPathSegment = segment as ContentPathSegment;
if (contentPathSegment != null)
{
if (contentPathSegment.IsCatchAll)
{
this.MatchCatchAll(contentPathSegment, source.Skip<string>(i), defaultValues, matchedValues);
flag2 = true;
}
else if (!this.MatchContentPathSegment(contentPathSegment, a, defaultValues, matchedValues))
{
return null;
}
}
}
}
if (!flag2 && (this.PathSegments.Count < source.Count))
{
for (int j = this.PathSegments.Count; j < source.Count; j++)
{
if (!RouteParser.IsSeparator(source[j]))
{
return null;
}
}
}
if (defaultValues != null)
{
foreach (KeyValuePair<string, object> pair in defaultValues)
{
if (!matchedValues.ContainsKey(pair.Key))
{
matchedValues.Add(pair.Key, pair.Value);
}
}
}
return matchedValues;
}
public RouteValueDictionary Match(string virtualPath, RouteValueDictionary defaultValues)
{
IList<string> source = RouteParser.SplitUrlToPathSegmentStrings(virtualPath);
if (defaultValues == null)
{
defaultValues = new RouteValueDictionary();
}
RouteValueDictionary matchedValues = new RouteValueDictionary();
bool flag = false;
bool flag2 = false;
for (int i = 0; i < this.PathSegments.Count; i++)
{
PathSegment segment = this.PathSegments[i];
if (source.Count <= i)
{
flag = true;
}
string a = flag ? null : source[i];
if (segment is SeparatorPathSegment)
{
if (!flag && !string.Equals(a, "/", StringComparison.Ordinal))
{
return null;
}
}
else
{
ContentPathSegment contentPathSegment = segment as ContentPathSegment;
if (contentPathSegment != null)
{
if (contentPathSegment.IsCatchAll)
{
this.MatchCatchAll(contentPathSegment, source.Skip<string>(i), defaultValues, matchedValues);
flag2 = true;
}
else if (!this.MatchContentPathSegment(contentPathSegment, a, defaultValues, matchedValues))
{
return null;
}
}
}
}
if (!flag2 && (this.PathSegments.Count < source.Count))
{
for (int j = this.PathSegments.Count; j < source.Count; j++)
{
if (!RouteParser.IsSeparator(source[j]))
{
return null;
}
}
}
if (defaultValues != null)
{
foreach (KeyValuePair<string, object> pair in defaultValues)
{
if (!matchedValues.ContainsKey(pair.Key))
{
matchedValues.Add(pair.Key, pair.Value);
}
}
}
return matchedValues;
}這裡RouteParser的SplitUrlToPathSegmentStrings方法很簡單,就是把url字符串按照”/“來分割[csharp] view plaincopyprint?internal static IList<string> SplitUrlToPathSegmentStrings(string url)
{
List<string> list = new List<string>();
if (!string.IsNullOrEmpty(url))
{
int index;
for (int i = 0; i < url.Length; i = index + 1)
{
index = url.IndexOf('/', i);
if (index == -1)
{
string str = url.Substring(i);
if (str.Length > 0)
{
list.Add(str);
}
return list;
}
string item = url.Substring(i, index - i);
if (item.Length > 0)
{
list.Add(item);
}
list.Add("/");
}
}
return list;
}
internal static IList<string> SplitUrlToPathSegmentStrings(string url)
{
List<string> list = new List<string>();
if (!string.IsNullOrEmpty(url))
{
int index;
for (int i = 0; i < url.Length; i = index + 1)
{
index = url.IndexOf('/', i);
if (index == -1)
{
string str = url.Substring(i);
if (str.Length > 0)
{
list.Add(str);
}
return list;
}
string item = url.Substring(i, index - i);
if (item.Length > 0)
{
list.Add(item);
}
list.Add("/");
}
}
return list;
}所以Match方法中的source 是成員是很好明白的,我的示例中它的值是:
在ParsedRoute的Match方法中用到了一個PathSegments屬性。該屬性定義為:private IList<PathSegment> PathSegments { get; set; }真正該改屬性復制的是ParsedRoute的構造函數。而Route中的_parsedRoute的獲取是在Url屬性中
public string Url
{
get
{
return (this._url ?? string.Empty);
}
set
{
this._parsedRoute = RouteParser.Parse(value);
this._url = value;
}
}
在我們這個例子中url的value={controller}/{action}/{id}。
其中RouteParser的Parse方法如下:
[csharp]
public static ParsedRoute Parse(string routeUrl)
{
if (routeUrl == null)
{
routeUrl = string.Empty;
}
if ((routeUrl.StartsWith("~", StringComparison.Ordinal) || routeUrl.StartsWith("/", StringComparison.Ordinal)) || (routeUrl.IndexOf('?') != -1))
{
throw new ArgumentException(SR.GetString("Route_InvalidRouteUrl"), "routeUrl");
}
IList<string> pathSegments = SplitUrlToPathSegmentStrings(routeUrl);
Exception exception = ValidateUrlParts(pathSegments);
if (exception != null)
{
throw exception;
}
return new ParsedRoute(SplitUrlToPathSegments(pathSegments));
}
public static ParsedRoute Parse(string routeUrl)
{
if (routeUrl == null)
{
routeUrl = string.Empty;
}
if ((routeUrl.StartsWith("~", StringComparison.Ordinal) || routeUrl.StartsWith("/", StringComparison.Ordinal)) || (routeUrl.IndexOf('?') != -1))
{
throw new ArgumentException(SR.GetString("Route_InvalidRouteUrl"), "routeUrl");
}
IList<string> pathSegments = SplitUrlToPathSegmentStrings(routeUrl);
Exception exception = ValidateUrlParts(pathSegments);
if (exception != null)
{
throw exception;
}
return new ParsedRoute(SplitUrlToPathSegments(pathSegments));
}在這裡我們知道url不能以~ /打頭,也不能含有?。這裡的pathSegments也很好理解,其值:
這裡的ValidateUrlParts主要就是驗證這裡的pathSegments集合,ValidateUrlParts這裡的具體是怎麼驗證的很是復雜,這裡就忽略了它吧。
有關SplitUrlToPathSegments的方法比較復雜,分為兩部分,把urlParts中的"/" 變成SeparatorPathSegment對象作為站位,像{controller}這樣轉換為ContentPathSegment對象,其中它的subsegments是一個List<PathSubsegment>實例,
[csharp]
private static IList<PathSegment> SplitUrlToPathSegments(IList<string> urlParts)
{
List<PathSegment> list = new List<PathSegment>();
foreach (string str in urlParts)
{
if (IsSeparator(str))
{
list.Add(new SeparatorPathSegment());
}
else
{
Exception exception;
IList<PathSubsegment> subsegments = ParseUrlSegment(str, out exception);
list.Add(new ContentPathSegment(subsegments));
}
}
return list;
}
internal static bool IsSeparator(string s)
{
return string.Equals(s, "/", StringComparison.Ordinal);
}
private static IList<PathSubsegment> ParseUrlSegment(string segment, out Exception exception)
{
int startIndex = 0;
List<PathSubsegment> list = new List<PathSubsegment>();
while (startIndex < segment.Length)
{
int num2 = IndexOfFirstOpenParameter(segment, startIndex);
if (num2 == -1)
{
string str = GetLiteral(segment.Substring(startIndex));
if (str == null)
{
exception = new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_MismatchedParameter"), new object[] { segment }), "routeUrl");
return null;
}
if (str.Length > 0)
{
list.Add(new LiteralSubsegment(str));
}
break;
}
int index = segment.IndexOf('}', num2 + 1);
if (index == -1)
{
exception = new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_MismatchedParameter"), new object[] { segment }), "routeUrl");
return null;
}
string literal = GetLiteral(segment.Substring(startIndex, num2 - startIndex));
if (literal == null)
{
exception = new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_MismatchedParameter"), new object[] { segment }), "routeUrl");
return null;
}
if (literal.Length > 0)
{
list.Add(new LiteralSubsegment(literal));
}
string parameterName = segment.Substring(num2 + 1, (index - num2) - 1);
list.Add(new ParameterSubsegment(parameterName));
startIndex = index + 1;
}
exception = null;
return list;
}
private static int IndexOfFirstOpenParameter(string segment, int startIndex)
{
while (true)
{
startIndex = segment.IndexOf('{', startIndex);
if (startIndex == -1)
{
return -1;
}
if (((startIndex + 1) == segment.Length) || (((startIndex + 1) < segment.Length) && (segment[startIndex + 1] != '{')))
{
return startIndex;
}
startIndex += 2;
}
}
private static string GetLiteral(string segmentLiteral)
{
string str = segmentLiteral.Replace("{{", "").Replace("}}", "");
if (!str.Contains("{") && !str.Contains("}"))
{
return segmentLiteral.Replace("{{", "{").Replace("}}", "}");
}
return null;
}
internal sealed class LiteralSubsegment : PathSubsegment
{
// Methods
public LiteralSubsegment(string literal)
{
this.Literal = literal;
}
// Properties
public string Literal { get; private set; }
}
internal sealed class ParameterSubsegment : PathSubsegment
{
// Methods
public ParameterSubsegment(string parameterName)
{
if (parameterName.StartsWith("*", StringComparison.Ordinal))
{
this.ParameterName = parameterName.Substring(1);
this.IsCatchAll = true;
}
else
{
this.ParameterName = parameterName;
}
}
// Properties
public bool IsCatchAll { get; private set; }
public string ParameterName { get; private set; }
}
internal sealed class ContentPathSegment : PathSegment
{
// Methods
public ContentPathSegment(IList<PathSubsegment> subsegments)
{
this.Subsegments = subsegments;
}
// Properties
public bool IsCatchAll
{
get
{
return this.Subsegments.Any<PathSubsegment>(seg => ((seg is ParameterSubsegment) && ((ParameterSubsegment)seg).IsCatchAll));
}
}
public IList<PathSubsegment> Subsegments { get; private set; }
}
private static IList<PathSegment> SplitUrlToPathSegments(IList<string> urlParts)
{
List<PathSegment> list = new List<PathSegment>();
foreach (string str in urlParts)
{
if (IsSeparator(str))
{
list.Add(new SeparatorPathSegment());
}
else
{
Exception exception;
IList<PathSubsegment> subsegments = ParseUrlSegment(str, out exception);
list.Add(new ContentPathSegment(subsegments));
}
}
return list;
}
internal static bool IsSeparator(string s)
{
return string.Equals(s, "/", StringComparison.Ordinal);
}
private static IList<PathSubsegment> ParseUrlSegment(string segment, out Exception exception)
{
int startIndex = 0;
List<PathSubsegment> list = new List<PathSubsegment>();
while (startIndex < segment.Length)
{
int num2 = IndexOfFirstOpenParameter(segment, startIndex);
if (num2 == -1)
{
string str = GetLiteral(segment.Substring(startIndex));
if (str == null)
{
exception = new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_MismatchedParameter"), new object[] { segment }), "routeUrl");
return null;
}
if (str.Length > 0)
{
list.Add(new LiteralSubsegment(str));
}
break;
}
int index = segment.IndexOf('}', num2 + 1);
if (index == -1)
{
exception = new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_MismatchedParameter"), new object[] { segment }), "routeUrl");
return null;
}
string literal = GetLiteral(segment.Substring(startIndex, num2 - startIndex));
if (literal == null)
{
exception = new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_MismatchedParameter"), new object[] { segment }), "routeUrl");
return null;
}
if (literal.Length > 0)
{
list.Add(new LiteralSubsegment(literal));
}
string parameterName = segment.Substring(num2 + 1, (index - num2) - 1);
list.Add(new ParameterSubsegment(parameterName));
startIndex = index + 1;
}
exception = null;
return list;
}
private static int IndexOfFirstOpenParameter(string segment, int startIndex)
{
while (true)
{
startIndex = segment.IndexOf('{', startIndex);
if (startIndex == -1)
{
return -1;
}
if (((startIndex + 1) == segment.Length) || (((startIndex + 1) < segment.Length) && (segment[startIndex + 1] != '{')))
{
return startIndex;
}
startIndex += 2;
}
}
private static string GetLiteral(string segmentLiteral)
{
string str = segmentLiteral.Replace("{{", "").Replace("}}", "");
if (!str.Contains("{") && !str.Contains("}"))
{
return segmentLiteral.Replace("{{", "{").Replace("}}", "}");
}
return null;
}
internal sealed class LiteralSubsegment : PathSubsegment
{
// Methods
public LiteralSubsegment(string literal)
{
this.Literal = literal;
}
// Properties
public string Literal { get; private set; }
}
internal sealed class ParameterSubsegment : PathSubsegment
{
// Methods
public ParameterSubsegment(string parameterName)
{
if (parameterName.StartsWith("*", StringComparison.Ordinal))
{
this.ParameterName = parameterName.Substring(1);
this.IsCatchAll = true;
}
else
{
this.ParameterName = parameterName;
}
}
// Properties
public bool IsCatchAll { get; private set; }
public string ParameterName { get; private set; }
}
internal sealed class ContentPathSegment : PathSegment
{
// Methods
public ContentPathSegment(IList<PathSubsegment> subsegments)
{
this.Subsegments = subsegments;
}
// Properties
public bool IsCatchAll
{
get
{
return this.Subsegments.Any<PathSubsegment>(seg => ((seg is ParameterSubsegment) && ((ParameterSubsegment)seg).IsCatchAll));
}
}
public IList<PathSubsegment> Subsegments { get; private set; }
}
ParseUrlSegment方法主要就是獲取代碼是:
string parameterName = segment.Substring(num2 + 1, (index - num2) - 1);
list.Add(new ParameterSubsegment(parameterName));
例如我們傳進來的字符串是{controller},那麼這裡parameterName就會處理為controller。如果傳入的參數沒有{、}如Channel,那麼ParseUrlSegment將處理為
if (str.Length > 0)
{
list.Add(new LiteralSubsegment(str));
}
break;
現在是時候回到ParsedRoute的Match方法了,首先我們來看看這個方法用到的PathSegments是個什麼東東,我的url是{controller}/{action}/{id}它對應的PathSegments如圖:
著了我們看看幾次循環的主要變量取值:
當前ContentPathSegment的IsCatchAll為false。那麼我們現在主要關心的是MatchContentPathSegment方法了。
[csharp]
private bool MatchContentPathSegment(ContentPathSegment routeSegment, string requestPathSegment, RouteValueDictionary defaultValues, RouteValueDictionary matchedValues)
{
if (string.IsNullOrEmpty(requestPathSegment))
{
if (routeSegment.Subsegments.Count <= 1)
{
object obj2;
ParameterSubsegment subsegment = routeSegment.Subsegments[0] as ParameterSubsegment;
if (subsegment == null)
{
return false;
}
if (defaultValues.TryGetValue(subsegment.ParameterName, out obj2))
{
matchedValues.Add(subsegment.ParameterName, obj2);
return true;
}
}
return false;
}
int length = requestPathSegment.Length;
int num2 = routeSegment.Subsegments.Count - 1;
ParameterSubsegment subsegment2 = null;
LiteralSubsegment subsegment3 = null;
while (num2 >= 0)
{
int num3 = length;
ParameterSubsegment subsegment4 = routeSegment.Subsegments[num2] as ParameterSubsegment;
if (subsegment4 != null)
{
subsegment2 = subsegment4;
}
else
{
LiteralSubsegment subsegment5 = routeSegment.Subsegments[num2] as LiteralSubsegment;
if (subsegment5 != null)
{
subsegment3 = subsegment5;
int startIndex = length - 1;
if (subsegment2 != null)
{
startIndex--;
}
if (startIndex < 0)
{
return false;
}
int num5 = requestPathSegment.LastIndexOf(subsegment5.Literal, startIndex, StringComparison.OrdinalIgnoreCase);
if (num5 == -1)
{
return false;
}
if ((num2 == (routeSegment.Subsegments.Count - 1)) && ((num5 + subsegment5.Literal.Length) != requestPathSegment.Length))
{
return false;
}
num3 = num5;
}
}
if ((subsegment2 != null) && (((subsegment3 != null) && (subsegment4 == null)) || (num2 == 0)))
{
int num6;
int num7;
if (subsegment3 == null)
{
if (num2 == 0)
{
num6 = 0;
}
else
{
num6 = num3 + subsegment3.Literal.Length;
}
num7 = length;
}
else if ((num2 == 0) && (subsegment4 != null))
{
num6 = 0;
num7 = length;
}
else
{
num6 = num3 + subsegment3.Literal.Length;
num7 = length - num6;
}
string str = requestPathSegment.Substring(num6, num7);
if (string.IsNullOrEmpty(str))
{
return false;
}
matchedValues.Add(subsegment2.ParameterName, str);
subsegment2 = null;
subsegment3 = null;
}
length = num3;
num2--;
}
if (length != 0)
{
return (routeSegment.Subsegments[0] is ParameterSubsegment);
}
return true;
}
private bool MatchContentPathSegment(ContentPathSegment routeSegment, string requestPathSegment, RouteValueDictionary defaultValues, RouteValueDictionary matchedValues)
{
if (string.IsNullOrEmpty(requestPathSegment))
{
if (routeSegment.Subsegments.Count <= 1)
{
object obj2;
ParameterSubsegment subsegment = routeSegment.Subsegments[0] as ParameterSubsegment;
if (subsegment == null)
{
return false;
}
if (defaultValues.TryGetValue(subsegment.ParameterName, out obj2))
{
matchedValues.Add(subsegment.ParameterName, obj2);
return true;
}
}
return false;
}
int length = requestPathSegment.Length;
int num2 = routeSegment.Subsegments.Count - 1;
ParameterSubsegment subsegment2 = null;
LiteralSubsegment subsegment3 = null;
while (num2 >= 0)
{
int num3 = length;
ParameterSubsegment subsegment4 = routeSegment.Subsegments[num2] as ParameterSubsegment;
if (subsegment4 != null)
{
subsegment2 = subsegment4;
}
else
{
LiteralSubsegment subsegment5 = routeSegment.Subsegments[num2] as LiteralSubsegment;
if (subsegment5 != null)
{
subsegment3 = subsegment5;
int startIndex = length - 1;
if (subsegment2 != null)
{
startIndex--;
}
if (startIndex < 0)
{
return false;
}
int num5 = requestPathSegment.LastIndexOf(subsegment5.Literal, startIndex, StringComparison.OrdinalIgnoreCase);
if (num5 == -1)
{
return false;
}
if ((num2 == (routeSegment.Subsegments.Count - 1)) && ((num5 + subsegment5.Literal.Length) != requestPathSegment.Length))
{
return false;
}
num3 = num5;
}
}
if ((subsegment2 != null) && (((subsegment3 != null) && (subsegment4 == null)) || (num2 == 0)))
{
int num6;
int num7;
if (subsegment3 == null)
{
if (num2 == 0)
{
num6 = 0;
}
else
{
num6 = num3 + subsegment3.Literal.Length;
}
num7 = length;
}
else if ((num2 == 0) && (subsegment4 != null))
{
num6 = 0;
num7 = length;
}
else
{
num6 = num3 + subsegment3.Literal.Length;
num7 = length - num6;
}
string str = requestPathSegment.Substring(num6, num7);
if (string.IsNullOrEmpty(str))
{
return false;
}
matchedValues.Add(subsegment2.ParameterName, str);
subsegment2 = null;
subsegment3 = null;
}
length = num3;
num2--;
}
if (length != 0)
{
return (routeSegment.Subsegments[0] is ParameterSubsegment);
}
return true;
}這個方法就是真正把路由參數和路由的值給關聯起來,如果參數requestPathSegment為null則參數值從defaultValues中獲取,
if (defaultValues.TryGetValue(subsegment.ParameterName, out obj2))
{
matchedValues.Add(subsegment.ParameterName, obj2);
return true;
}
否則從我們傳遞進來的requestPathSegment獲取。
string str = requestPathSegment.Substring(num6, num7);
if (string.IsNullOrEmpty(str))
{
return false;
}
matchedValues.Add(subsegment2.ParameterName, str);
Match方法在結束之前會檢查我們的defaultValues字典,把defaultValues中的key(matchedValues不存在對應的key)加到matchedValues中來。整個match方法及結束了,結合前面的東西我們也就可以明白Route類的GetRouteData方法了。
為了跟好的理解上面個方法,我這裡再舉一個demo:
路由信息: routes.MapRoute("Default", "{ChannelName}/{action}", new { controller = "Home", action = "Index" });
調用Match方法的 virtualPath=men/index,
source取值:
PathSegments取值:
至於Match方法中的有一種路徑是調用MatchCatchAll方法,
[csharp]
private void MatchCatchAll(ContentPathSegment contentPathSegment, IEnumerable<string> remainingRequestSegments, RouteValueDictionary defaultValues, RouteValueDictionary matchedValues)
{
object obj2;
string str = string.Join(string.Empty, remainingRequestSegments.ToArray<string>());
ParameterSubsegment subsegment = contentPathSegment.Subsegments[0] as ParameterSubsegment;
if (str.Length > 0)
{
obj2 = str;
}
else
{
defaultValues.TryGetValue(subsegment.ParameterName, out obj2);
}
matchedValues.Add(subsegment.ParameterName, obj2);
}
private void MatchCatchAll(ContentPathSegment contentPathSegment, IEnumerable<string> remainingRequestSegments, RouteValueDictionary defaultValues, RouteValueDictionary matchedValues)
{
object obj2;
string str = string.Join(string.Empty, remainingRequestSegments.ToArray<string>());
ParameterSubsegment subsegment = contentPathSegment.Subsegments[0] as ParameterSubsegment;
if (str.Length > 0)
{
obj2 = str;
}
else
{
defaultValues.TryGetValue(subsegment.ParameterName, out obj2);
}
matchedValues.Add(subsegment.ParameterName, obj2);
}
它要求contentPathSegment.IsCatchAll為true。從 ParameterSubsegment類的定義可以知道當且僅當傳進來parameterName以*打頭才是True。parameterName是從url中來的,也就是說url中要含有*,IsCatchAll才為true。在前面提到的ValidateUrlParts方法會驗證url的,其主要代碼如下:
private static Exception ValidateUrlParts(IList<string> pathSegments)
{
HashSet<string> usedParameterNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
bool? nullable = null;
bool flag = false;
foreach (string str in pathSegments)
{
bool flag2;
if (flag)
{
return new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_CatchAllMustBeLast"), new object[0]), "routeUrl");
}
if (!flag2)
{
Exception exception;
IList<PathSubsegment> pathSubsegments = ParseUrlSegment(str, out exception);
flag = pathSubsegments.Any<PathSubsegment>(seg => (seg is ParameterSubsegment) && ((ParameterSubsegment) seg).IsCatchAll);
}
}
return null;
}
所以以上的那個MatchCatchAll執行的條件也很明顯就是url中帶有*號,並且是最後一個參數帶有*,希望大家注意一下。大家看到這裡相信對Route類的GetRouteData方法有個大致的了解了吧。