Asp.net mvc5 解析route源码实现自己的route系统

Asp.net mvc5 解析route源码实现自己的route系统

url route


操作

实例


Asp.net mvc5 解析route源码实现自己的route系统

Asp.net mvc5 解析route源码实现自己的route系统

 源码:http://pan.baidu.com/s/1i3lfbaH

具体实现


//存放url 路径片段
    public abstract class PathSegment
        {
        // Methods
        protected PathSegment()
            {

            }

        }
  // 主要存放 url template 的 "/"
    //比如{controller}/{action}中 "/"

    public sealed class SeparatorPathSegment : PathSegment
        {
        // Methods
        public SeparatorPathSegment()
            {
            }



        }
    //存放 url  tamplate  subpathsegment
    //比如A{controller}/{action}中 "controller" 或 action 或 A
    public abstract class PathSubsegment
        {
        // Methods
        protected PathSubsegment() {}
        }
 //存放 url  tamplate  subpathsegment
    //比如A{controller}/{action}中 "controller" 或 action 
    public sealed class ParameterSubsegment : PathSubsegment
        {
        public ParameterSubsegment(string parameterName) {
            if (parameterName.StartsWith("*", StringComparison.Ordinal))
                {
                this.ParameterName = parameterName.Substring(1);
                this.IsCatchAll = true;
                }
            else
                {
                this.ParameterName = parameterName;
                }

            }
        public bool IsCatchAll { get; private set; }
        public string ParameterName { get; private set; }
        }
  //存放 url  tamplate  subpathsegment
    //比如A{controller}/{action}中 A
    public sealed class LiteralSubsegment : PathSubsegment
        {
        // Methods
        public LiteralSubsegment(string literal)
            {
            this.Literal = literal;
            }

        // Properties
        public string Literal { get; private set; }
        }

以上是存放被分割的url 片段的类

myRoute 类

  public class MyRoute: RouteBase

        {

        private ParsedRoute _parsedRoute;
        private string _url;
        private const string HttpMethodParameterName = "httpMethod";

        public MyRoute(string url, IRouteHandler routeHandler) {
            this.Url = url;
            this.RouteHandler = routeHandler;

            }
        public MyRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler) {
            this.Url = url;
            this.Defaults = defaults;
            this.RouteHandler = routeHandler;

            }
        public MyRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
            {
            this.Url = url;
            this.Defaults = defaults;
            this.Constraints = constraints;
            this.RouteHandler = routeHandler;

            }
        public MyRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler) {
            this.Url = url;
            this.Defaults = defaults;
            this.Constraints = constraints;
            this.DataTokens = dataTokens;
            this.RouteHandler = routeHandler;

            }
        //获取routedate
        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);         
            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 VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
            {
            throw new NotImplementedException();
            }      
        public RouteValueDictionary Constraints { get; set; }
        public RouteValueDictionary DataTokens { get; set; }
        public RouteValueDictionary Defaults { get; set; }
        public IRouteHandler RouteHandler { get; set; }
        public string Url
            {
            get
                {
                return (this._url ?? string.Empty);
                }
            set
                {
                //解析路由也就是分割url
                this._parsedRoute = RouteParser.Parse(value);
                this._url = value;
                }
            }


        }

RouteParesed 类负责解析url 模板

关键地方都有注释

  public static class RouteParser
        {
        // 解析route uel
        public static ParsedRoute Parse(string routeUrl)
            {
            if (routeUrl == null)
                {
                routeUrl = string.Empty;
                }
            //判断网址是否有效
            if (IsInvalidRouteUrl(routeUrl))
                {
               // throw new ArgumentException(SR.GetString("Route_InvalidRouteUrl"), "routeUrl");
                }

            //根据/拆分网址
            IList<string> pathSegments = SplitUrlToPathSegmentStrings(routeUrl);

                                  //验证部分url
            Exception exception = ValidateUrlParts(pathSegments);
            if (exception != null)
                {
                throw exception;
                }
            //拆分的url加入到PathSegments
            return new ParsedRoute(SplitUrlToPathSegments(pathSegments));
            }


        public 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.CurrentCulture, SR.GetString("Route_CatchAllMustBeLast"), new object[0]), "routeUrl");
                    }
                if (!nullable.HasValue)
                    {
                    nullable = new bool?(IsSeparator(str));
                    flag2 = nullable.Value;
                    }
                else
                    {
                    flag2 = IsSeparator(str);
                    if (flag2 && nullable.Value)
                        {
                     //   return new ArgumentException(SR.GetString("Route_CannotHaveConsecutiveSeparators"), "routeUrl");
                        }
                    nullable = new bool?(flag2);
                    }
                if (!flag2)
                    {
                    Exception exception2;
                    IList<PathSubsegment> pathSubsegments = ParseUrlSegment(str, out exception2);
                    if (exception2 != null)
                        {
                        return exception2;
                        }
                    exception2 = ValidateUrlSegment(pathSubsegments, usedParameterNames, str);
                    if (exception2 != null)
                        {
                        return exception2;
                        }
                    flag = pathSubsegments.Any<PathSubsegment>(seg => (seg is ParameterSubsegment) && ((ParameterSubsegment)seg).IsCatchAll);
                    }
                }
            return null;
            }




        private static Exception ValidateUrlSegment(IList<PathSubsegment> pathSubsegments, HashSet<string> usedParameterNames, string pathSegment)
            {
            bool flag = false;
            Type type = null;
            foreach (PathSubsegment subsegment in pathSubsegments)
                {
                if ((type != null) && (type == subsegment.GetType()))
                    {
                    //return new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.GetString("Route_CannotHaveConsecutiveParameters"), new object[0]), "routeUrl");
                    }
                type = subsegment.GetType();
                if (!(subsegment is LiteralSubsegment))
                    {
                    ParameterSubsegment subsegment2 = subsegment as ParameterSubsegment;
                    if (subsegment2 != null)
                        {
                        string parameterName = subsegment2.ParameterName;
                        if (subsegment2.IsCatchAll)
                            {
                            flag = true;
                            }
                        if (!IsValidParameterName(parameterName))
                            {
                            object[] args = new object[] { parameterName };
                            //return new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_InvalidParameterName"), args), "routeUrl");
                            }
                        if (usedParameterNames.Contains(parameterName))
                            {
                            object[] objArray2 = new object[] { parameterName };
                            //return new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_RepeatedParameter"), objArray2), "routeUrl");
                            }
                        usedParameterNames.Add(parameterName);
                        }
                    }
                }
            if (flag && (pathSubsegments.Count != 1))
                {
                //return new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.GetString/("Route_CannotHaveCatchAllInMultiSegment"), new object[0]), "routeUrl");

                  
                }
            return null;
            }


        private static bool IsValidParameterName(string parameterName)
            {
            if (parameterName.Length == 0)
                {
                return false;
                }
            for (int i = 0; i < parameterName.Length; i++)
                {
                switch (parameterName[i])
                    {
                    case '/':
                    case '{':
                    case '}':
                        return false;
                    }
                }
            return true;
            }



        public static bool IsInvalidRouteUrl(string routeUrl)
            {
            if (!routeUrl.StartsWith("~", StringComparison.Ordinal) && !routeUrl.StartsWith("/", StringComparison.Ordinal))
                {
                return (routeUrl.IndexOf('?') != -1);
                }
            return true;
            }


        //判断是否是分隔符
        public static bool IsSeparator(string s)
            {
            return string.Equals(s, "/", StringComparison.Ordinal);
            }

        //
        public static IList<PathSegment> SplitUrlToPathSegments(IList<string> urlParts)
            {
            
            List<PathSegment> list = new List<PathSegment>();
            foreach (string str in urlParts)
                {
                //判读是否是分割符
                if (IsSeparator(str))
                    {
                    //如果是分隔符/就加入pathsegment
                    list.Add(new SeparatorPathSegment());
                    }
                else
                    {
                    
                    Exception exception;
                                                        //解析 segment
                    IList<PathSubsegment> subsegments = ParseUrlSegment(str, out exception);
                    list.Add(new ContentPathSegment(subsegments));
                    }
                }
            return list;
            }


        public static IList<PathSubsegment> ParseUrlSegment(string segment, out Exception exception)
            {
            int startIndex = 0;
            List<PathSubsegment> list = new List<PathSubsegment>();
            while (startIndex < segment.Length)
                {
                //获得{索引位置
                //比如{controller} num2=0
                int num2 = IndexOfFirstOpenParameter(segment, startIndex);
                if (num2 == -1)
                    {

                    //获取LiteralSubsegment
                   
                    string str3 = GetLiteral(segment.Substring(startIndex));
                    if (str3 == null)
                        {
                        object[] args = new object[] { segment };
                        //exception = new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_MismatchedParameter"), args), "routeUrl");
                       // return null;
                        }
                    if (str3.Length > 0)
                        {
                        //加入获取LiteralSubsegment

                        list.Add(new LiteralSubsegment(str3));
                        }
                    break;
                    }
                //获得}索引位置
                int index = segment.IndexOf('}', num2 + 1);
                if (index == -1)
                    {
                    object[] objArray2 = new object[] { segment };
                    //exception = new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_MismatchedParameter"), objArray2), "routeUrl");
                    //return null;
                    }
                //获取LiteralSubsegment string
                string literal = GetLiteral(segment.Substring(startIndex, num2 - startIndex));
                if (literal == null)
                    {
                    object[] objArray3 = new object[] { segment };
                    //exception = new ArgumentException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_MismatchedParameter"), objArray3), "routeUrl");
                    //return null;
                    }
                if (literal.Length > 0)
                    {
                    list.Add(new LiteralSubsegment(literal));
                    }
                //获取参数名称
                string parameterName = segment.Substring(num2 + 1, (index - num2) - 1);

                //加入ParameterSubsegment
                list.Add(new ParameterSubsegment(parameterName));

                //继续解析segment ,如果startIndex= segment.length表示解析完毕
                startIndex = index + 1;
                }
            exception = null;
            return list;
            }

        //去除 url template 中的{}获得文字
        public static string GetLiteral(string segmentLiteral)
            {
            string str = segmentLiteral.Replace("{{", "").Replace("}}", "");
            if (!str.Contains("{") && !str.Contains("}"))
                {
                return segmentLiteral.Replace("{{", "{").Replace("}}", "}");
                }
            return null;
            }
       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;
                }
            }
        public 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 str2 = url.Substring(i);
                        if (str2.Length > 0)
                            {
                            list.Add(str2);
                            }
                        return list;
                        }
                    string item = url.Substring(i, index - i);
                    if (item.Length > 0)
                        {
                        list.Add(item);
                        }
                    list.Add("/");
                    }
                }
            return list;
            }
        }



    }

ParsedRoute 类负责解析请求的url

并且返回匹配url的值也就是route的值

关键地方有注释

  public class ParsedRoute
        {

        public ParsedRoute(IList<PathSegment> pathSegments) {

            this.PathSegments = pathSegments;

            }
        
        private static string EscapeReservedCharacters(Match m)
            {
            return ("%" + Convert.ToUInt16(m.Value[0]).ToString("x2", CultureInfo.InvariantCulture));

            }
        private static bool ForEachParameter(IList<PathSegment> pathSegments, Func<ParameterSubsegment, bool> action) {

            for (int i = 0; i < pathSegments.Count; i++)
                {
                PathSegment segment = pathSegments[i];
                if (!(segment is SeparatorPathSegment))
                    {
                    ContentPathSegment segment2 = segment as ContentPathSegment;
                    if (segment2 != null)
                        {
                        foreach (PathSubsegment subsegment in segment2.Subsegments)
                            {
                            if (!(subsegment is LiteralSubsegment))
                                {
                                ParameterSubsegment arg = subsegment as ParameterSubsegment;
                                if ((arg != null) && !action(arg))
                                    {
                                    return false;
                                    }
                                }
                            }
                        }
                    }
                }
            return true;

            }
        private static ParameterSubsegment GetParameterSubsegment(IList<PathSegment> pathSegments, string parameterName) {

            ParameterSubsegment foundParameterSubsegment = null;
            ForEachParameter(pathSegments, delegate (ParameterSubsegment parameterSubsegment) {
                if (string.Equals(parameterName, parameterSubsegment.ParameterName, StringComparison.OrdinalIgnoreCase))
                    {
                    foundParameterSubsegment = parameterSubsegment;
                    return false;
                    }
                return true;
                });
            return foundParameterSubsegment;

            }
        private static bool IsParameterRequired(ParameterSubsegment parameterSubsegment, RouteValueDictionary defaultValues, out object defaultValue)

            {
            if (parameterSubsegment.IsCatchAll)
                {
                defaultValue = null;
                return false;
                }
            return !defaultValues.TryGetValue(parameterSubsegment.ParameterName, out defaultValue);


            }
        private static bool IsRoutePartNonEmpty(object routePart) {

            string str = routePart as string;
            if (str != null)
                {
                return (str.Length > 0);
                }
            return ((int)routePart > null);

            }
        public RouteValueDictionary Match(string virtualPath, RouteValueDictionary defaultValues)
            {
            //分割virtualPath
            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;
                    //判断是否为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;

            }



        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 bool MatchContentPathSegment(ContentPathSegment routeSegment, string requestPathSegment, RouteValueDictionary defaultValues, RouteValueDictionary matchedValues) {

            //判断requestPathSegment 是否为空
            //如果为空直接用默认值
            if (string.IsNullOrEmpty(requestPathSegment))
                {
                if (routeSegment.Subsegments.Count <= 1)
                    {
                    object obj2;
                    ParameterSubsegment subsegment3 = routeSegment.Subsegments[0] as ParameterSubsegment;
                    if (subsegment3 == null)
                        {
                        return false;
                        }
                    if (defaultValues.TryGetValue(subsegment3.ParameterName, out obj2))
                        {
                        matchedValues.Add(subsegment3.ParameterName, obj2);
                        return true;
                        }
                    }
                return false;
                }

            //获取pathsegment.length 长度
            int length = requestPathSegment.Length;

            
            int num2 = routeSegment.Subsegments.Count - 1;
            ParameterSubsegment subsegment = null;
            LiteralSubsegment subsegment2 = null;

            //循环routeSegment
            while (num2 >= 0)
                {
                int num3 = length;
                //判断是否为ParameterSubsegment
                ParameterSubsegment subsegment4 = routeSegment.Subsegments[num2] as ParameterSubsegment;
                if (subsegment4 != null)
                    {
                    subsegment = subsegment4;
                    }
                else
                    {
                    //判断是否为LiteralSubsegment
                    LiteralSubsegment subsegment5 = routeSegment.Subsegments[num2] as LiteralSubsegment;
                    if (subsegment5 != null)
                        {
                        subsegment2 = subsegment5;
                        int startIndex = length - 1;
                        //判断索引是否为空
                        if (subsegment != null)
                            {
                            //startIndex-1 表示从倒数第二个字符开始索引
                            startIndex--;
                            }                     
                        if (startIndex < 0)
                            {
                            return false;
                            }
                        //搜索指定LiteralSubsegment
                        int num5 = requestPathSegment.LastIndexOf(subsegment5.Literal, startIndex, StringComparison.OrdinalIgnoreCase);
                        //num5=-1 表示没有索引到LiteralSubsegment 
                        if (num5 == -1)
                            {
                            return false;
                            }
                      
                        if ((num2 == (routeSegment.Subsegments.Count - 1)) && ((num5 + subsegment5.Literal.Length) != requestPathSegment.Length))
                            {
                            return false;
                            }
                        num3 = num5;
                        }
                    }
                // subsegment!=null subsegment2!=null  subsegment4==null   num2=0
                //表示找到最后一LiteralSubsegment
                if ((subsegment != null) && (((subsegment2 != null) && (subsegment4 == null)) || (num2 == 0)))
                    {
                    int num6;
                    int num7;
                    if (subsegment2 == null)
                        {
                        if (num2 == 0)
                            {
                            num6 = 0;
                            }
                        else
                            {
                            num6 = num3;
                            }
                        num7 = length;
                        }
                    else if ((num2 == 0) && (subsegment4 != null))
                        {
                        num6 = 0;
                        num7 = length;
                        }
                    else
                        {
                        //Substring起始位置
                        num6 = num3 + subsegment2.Literal.Length;
                        //截取的字符个数
                        num7 = length - num6;
                        }
                    string str = requestPathSegment.Substring(num6,num7);
                    if (string.IsNullOrEmpty(str))
                        {
                        return false;
                        }
                    //加入匹配值
                    matchedValues.Add(subsegment.ParameterName, str);
                    subsegment = null;
                    subsegment2 = null;
                    }
                length = num3;
                num2--;
                }
            if (length != 0)
                {
                return (routeSegment.Subsegments[0] is ParameterSubsegment);
                }
            return true;

            }
        private static bool RoutePartsEqual(object a, object b) {
            string str = a as string;
            string str2 = b as string;
            if ((str != null) && (str2 != null))
                {
                return string.Equals(str, str2, StringComparison.OrdinalIgnoreCase);
                }
            if ((a != null) && (b != null))
                {
                return a.Equals(b);
                }
            return (a == b);

            }
        private static string UrlEncode(string str)
            {
            return Regex.Replace(Uri.EscapeUriString(str), "([#;?:@&=+$,])", new MatchEvaluator(ParsedRoute.EscapeReservedCharacters));
            }

        // Properties
        private IList<PathSegment> PathSegments { get; set; }



        }
    }

以上是route的大概流程

(1)先通过url  tamplate 解析 url

(2) 解析请求的url 比较匹配赋值

(3) 再根据匹配到的值映射到相应的controller 和 Action 进行处理