public JimuServiceDesc Parse(MethodInfo methodInfo)
        {
            JimuServiceDesc desc = new JimuServiceDesc();
            var             descriptorAttributes = methodInfo.GetCustomAttributes <JimuServiceDescAttribute>();

            foreach (var attr in descriptorAttributes)
            {
                attr.Apply(desc);
            }

            if (string.IsNullOrEmpty(desc.Comment))
            {
                var xml = GetXmlComment(methodInfo.DeclaringType);
                var key = XmlCommentsMemberNameHelper.GetMemberNameForMethod(methodInfo);
                if (xml != null && xml.TryGetValue(key, out var node))
                {
                    var summaryNode = node.SelectSingleNode("summary");
                    if (summaryNode != null)
                    {
                        desc.Comment = summaryNode.Value.Trim();
                    }
                }
            }

            desc.ReturnDesc = GetReturnDesc(methodInfo);

            if (string.IsNullOrEmpty(desc.HttpMethod))
            {
                desc.HttpMethod = GetHttpMethod(methodInfo);
            }

            desc.Parameters = JimuHelper.Serialize <string>(GetParameters(methodInfo));

            if (string.IsNullOrEmpty(desc.Id))
            {
                desc.Id = JimuHelper.GenerateServiceId(methodInfo);
            }

            var type          = methodInfo.DeclaringType;
            var routeTemplate = type.GetCustomAttribute <JimuAttribute>();

            if (routeTemplate != null)
            {
                if (string.IsNullOrEmpty(desc.RoutePath))
                {
                    var setPath = string.IsNullOrEmpty(desc.Rest) ? methodInfo.Name : desc.Rest;
                    desc.ServiceClassPath = JimuServiceRoute.ParseClassPath(routeTemplate.GetTemplate(type), type.Name, type.IsInterface);
                    desc.RoutePath        = JimuServiceRoute.ParseRoutePath(desc.HttpMethod, desc.ServiceClassPath, setPath, methodInfo.GetParameters().Select(x => x.Name).ToArray(), type.IsInterface);
                }
            }

            desc.Service        = methodInfo.DeclaringType.FullName;
            desc.ServiceComment = GetServiceComment(methodInfo);
            return(desc);
        }
        private string GetReturnDesc(MethodInfo methodInfo)
        {
            JimuServiceReturnDesc desc = new JimuServiceReturnDesc();
            var jimuReturnComment      = methodInfo.GetCustomAttribute <JimuReturnCommentAttribute>();

            if (jimuReturnComment != null)
            {
                desc.Comment      = jimuReturnComment.Comment;
                desc.ReturnFormat = jimuReturnComment.Default;
            }
            if (string.IsNullOrEmpty(desc.Comment))
            {
                var xml = GetXmlComment(methodInfo.DeclaringType);
                var key = XmlCommentsMemberNameHelper.GetMemberNameForMethod(methodInfo);
                if (xml != null && xml.TryGetValue(key, out var node))
                {
                    var returnNode = node.SelectSingleNode("returns");
                    desc.Comment = returnNode?.Value.Trim();
                }
            }

            Type returnType = methodInfo.ReturnType;

            if (methodInfo.ReturnType.ToString().IndexOf("System.Threading.Tasks.Task", StringComparison.Ordinal) == 0)
            {
                if (methodInfo.ReturnType.GenericTypeArguments.Any())
                {
                    returnType = methodInfo.ReturnType.GenericTypeArguments[0];
                }
                else
                {
                    returnType = typeof(void);
                }
            }
            desc.ReturnType = returnType.ToString();
            if (returnType.IsGenericType && returnType.ToString().StartsWith("System."))
            {
                returnType = returnType.GenericTypeArguments[0];
            }
            else if (returnType.IsArray)
            {
                var arrayBaseType = returnType.Assembly.ExportedTypes.FirstOrDefault(x => x.FullName == returnType.FullName.TrimEnd('[', ']'));
                returnType = arrayBaseType;
            }

            if (returnType != null)
            {
                desc.Properties = GetProperties(returnType);
            }
            return(JimuHelper.Serialize <string>(desc));
        }
        private List <JimuServiceParameterDesc> GetParameters(MethodInfo method)
        {
            //StringBuilder sb = new StringBuilder();
            var            paras        = new List <JimuServiceParameterDesc>();
            var            paraComments = method.GetCustomAttributes <JimuFieldCommentAttribute>();
            var            xml          = GetXmlComment(method.DeclaringType);
            var            key          = XmlCommentsMemberNameHelper.GetMemberNameForMethod(method);
            var            hasNode      = false;
            XPathNavigator node         = null;

            if (xml != null)
            {
                hasNode = xml.TryGetValue(key, out node);
            }

            foreach (var para in method.GetParameters())
            {
                var paraComment = paraComments.FirstOrDefault(x => x.FieldName == para.Name);
                var paraDesc    = new JimuServiceParameterDesc
                {
                    Name    = para.Name,
                    Type    = para.ParameterType.ToString(),
                    Comment = paraComment?.Comment,
                    Default = paraComment?.Default
                };
                if (string.IsNullOrEmpty(paraDesc.Comment) && hasNode)
                {
                    var paraNode = node.SelectSingleNode($"param[@name='{para.Name}']");
                    if (paraNode != null)
                    {
                        paraDesc.Comment = paraNode.Value.Trim();
                    }
                }
                if (para.ParameterType.IsClass &&
                    !para.ParameterType.FullName.StartsWith("System."))
                {
                    paraDesc.Properties = GetProperties(para.ParameterType);
                }
                paras.Add(paraDesc);
            }
            return(paras);
        }