zoukankan      html  css  js  c++  java
  • mvc5 解析route源码实现自己的route系统

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

     

    url route


    路由系统的责任找到匹配路由创建路由数据请求分配一个处理程序
    选择动作 MVC 的处理程序实现细节使用路由数据传入请求其他信息选择执行操作

    实例


     源码: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 进行处理

     
    分类: MVC
  • 相关阅读:
    RAM调优之日志分析
    HDU Always Cook Mushroom (极角排序+树状数组)
    并非全部的程序猿都适合做技术管理
    HTTP Header具体解释
    Linux 通配符
    寻找正在连接中的网络连接
    hdu 1052 田忌赛马
    linux上电自启动应用程序具体解释
    C++ 中的 const 类型变量
    FileUtil
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4752856.html
Copyright © 2011-2022 走看看