private string GetFieldDescription(string idName, OperationFilterContext context)
        {
            var name      = char.ToUpperInvariant(idName[0]) + idName.Substring(1);
            var classProp = context.MethodInfo.GetParameters().FirstOrDefault()?.ParameterType?.GetProperties().FirstOrDefault(x => x.Name == name);
            var typeAttr  = classProp != null
                ? (DescriptionAttribute)classProp.GetCustomAttribute <DescriptionAttribute>()
                : null;

            if (typeAttr != null)
            {
                return(typeAttr?.Description);
            }

            if (classProp != null)
            {
                foreach (var xmlNavigator in xmlNavigators)
                {
                    var propertyMemberName  = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(classProp);
                    var propertySummaryNode = xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{propertyMemberName}']/summary");
                    if (propertySummaryNode != null)
                    {
                        return(XmlCommentsTextHelper.Humanize(propertySummaryNode.InnerXml));
                    }
                }
            }

            return(null);
        }
        private void ApplyParameters(OpenApiOperation operation, MethodInfo methodInfo)
        {
            if (methodInfo != null)
            {
                var methodMemberName = XmlCommentsNodeNameHelper.GetMemberNameForMethod(methodInfo);
                foreach (var parameter in methodInfo.GetParameters())
                {
                    if (!String.IsNullOrEmpty(parameter.Name))
                    {
                        var paramNode = _xmlNavigator.SelectSingleNode(
                            $"/doc/members/member[@name='{methodMemberName}']/param[@name='{parameter.Name}']");

                        if (paramNode != null)
                        {
                            var humanizedDescription = XmlCommentsTextHelper.Humanize(paramNode.InnerXml);

                            var operationParameter = operation.Parameters
                                                     .FirstOrDefault(x => x.Name == parameter.Name);

                            if (operationParameter != null)
                            {
                                operationParameter.Description = humanizedDescription;
                            }
                        }
                    }
                }
            }
        }
        private void ApplyServiceTags(OpenApiOperation operation, Type controllerType)
        {
            var typeMemberName = XmlCommentsNodeNameHelper.GetMemberNameForType(controllerType);
            var responseNodes  = _xmlNavigator.Select($"/doc/members/member[@name='{typeMemberName}']/response");

            ApplyResponseTags(operation, responseNodes);
        }
        private void ApplyParamTags(OpenApiParameter parameter, ParameterInfo parameterInfo)
        {
            if (!(parameterInfo.Member is MethodInfo methodInfo))
            {
                return;
            }

            // If method is from a constructed generic type, look for comments from the generic type method
            var targetMethod = methodInfo.DeclaringType.IsConstructedGenericType
                ? methodInfo.GetUnderlyingGenericTypeMethod()
                : methodInfo;

            if (targetMethod == null)
            {
                return;
            }

            var methodMemberName = XmlCommentsNodeNameHelper.GetMemberNameForMethod(targetMethod);
            var paramNode        = _xmlNavigator.SelectSingleNode(
                $"/doc/members/member[@name='{methodMemberName}']/param[@name='{parameterInfo.Name}']");

            if (paramNode != null)
            {
                parameter.Description = XmlCommentsTextHelper.Humanize(paramNode.InnerXml);

                var example = paramNode.GetAttribute("example", "");
                if (!string.IsNullOrEmpty(example))
                {
                    parameter.Example = JsonMapper.CreateFromJson(example);
                }
            }
        }
        private bool TryAdd(OpenApiDocument swaggerDoc, KeyValuePair <string, ActionDescriptor> nameAndType, Type type)
        {
            var memberName = XmlCommentsNodeNameHelper.GetMemberNameForType(type);
            var typeNode   = _xmlNavigator.SelectSingleNode(string.Format(MemberXPath, memberName));

            if (typeNode != null)
            {
                var summaryNode = typeNode.SelectSingleNode(SummaryTag);
                if (summaryNode != null)
                {
                    if (swaggerDoc.Tags == null)
                    {
                        swaggerDoc.Tags = new List <OpenApiTag>();
                    }

                    swaggerDoc.Tags.Add(new OpenApiTag
                    {
                        Name        = nameAndType.Key,
                        Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml)
                    });
                }
                return(true);
            }

            return(false);
        }
示例#6
0
        private static MemberInfo GetTarget(MemberInfo memberInfo, string cref)
        {
            var type = memberInfo.DeclaringType ?? memberInfo.ReflectedType;

            if (type == null)
            {
                return(null);
            }

            // Find all matching members in all interfaces and the base class.
            var targets = type.GetInterfaces()
                          .Append(type.BaseType)
                          .SelectMany(
                x => x.FindMembers(
                    memberInfo.MemberType,
                    BindingFlags.Instance | BindingFlags.Public,
                    (info, criteria) => info.Name == memberInfo.Name,
                    null))
                          .ToList();

            // Try to find the target, if one is declared.
            if (!string.IsNullOrEmpty(cref))
            {
                var crefTarget = targets.SingleOrDefault(t => XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(t) == cref);

                if (crefTarget != null)
                {
                    return(crefTarget);
                }
            }

            // We use the last since that will be our base class or the "nearest" implemented interface.
            return(targets.LastOrDefault());
        }
        private bool TryApplyMethodTags(OpenApiOperation operation, MethodInfo methodInfo)
        {
            var methodMemberName = XmlCommentsNodeNameHelper.GetMemberNameForMethod(methodInfo);
            var methodNode       = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{methodMemberName}']");

            if (methodNode == null)
            {
                return(false);
            }

            var summaryNode = methodNode.SelectSingleNode("summary");

            if (summaryNode != null)
            {
                operation.Summary = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml);
            }

            var remarksNode = methodNode.SelectSingleNode("remarks");

            if (remarksNode != null)
            {
                operation.Description = XmlCommentsTextHelper.Humanize(remarksNode.InnerXml);
            }

            var responseNodes = methodNode.Select("response");

            ApplyResponseTags(operation, responseNodes);

            return(true);
        }
        private void ApplyTypeTags(OpenApiSchema schema, Type type)
        {
            var typeMemberName  = XmlCommentsNodeNameHelper.GetMemberNameForType(type);
            var typeSummaryNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{typeMemberName}']/summary");

            if (typeSummaryNode != null)
            {
                schema.Description = XmlCommentsTextHelper.Humanize(typeSummaryNode.InnerXml);
            }
        }
        public void GetMemberNameForType_ReturnsCorrectXmlCommentsMemberName_ForGivenType(
            Type type,
            string expectedMemberName
            )
        {
            var memberName = XmlCommentsNodeNameHelper.GetMemberNameForType(type);

            _output.WriteLine(expectedMemberName);
            _output.WriteLine(memberName);
            Assert.Equal(expectedMemberName, memberName);
        }
示例#10
0
        public string GetPropertyExample(PropertyInfo propertyInfo)
        {
            var propertyMemberName  = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(propertyInfo);
            var propertyExampleNode = this.xpathNavigator.SelectSingleNode($"/doc/members/member[@name='{propertyMemberName}']/example");

            if (propertyExampleNode == null)
            {
                return(string.Empty);
            }
            var example = XmlCommentsTextHelper.Humanize(propertyExampleNode.InnerXml);

            return(example);
        }
        public void GetMemberNameForMethod_ReturnsCorrectXmlCommentsMemberName_ForGivenMethodInfo(
            Type declaringType,
            string name,
            string expectedMemberName)
        {
            var methodInfo = declaringType.GetMethod(name);

            var memberName = XmlCommentsNodeNameHelper.GetMemberNameForMethod(methodInfo);

            _output.WriteLine(expectedMemberName);
            _output.WriteLine(memberName);
            Assert.Equal(expectedMemberName, memberName);
        }
示例#12
0
        public string GetSummaryForType(Type type)
        {
            var memberName = XmlCommentsNodeNameHelper.GetMemberNameForType(type);
            var typeNode   = this.xpathNavigator.SelectSingleNode(string.Format(XmlDocumentationService.MemberXPath, memberName));

            if (typeNode == null)
            {
                return(string.Empty);
            }
            var summaryNode = typeNode.SelectSingleNode(XmlDocumentationService.SummaryTag);

            return(XmlCommentsTextHelper.Humanize(summaryNode.InnerXml));
        }
        public void GetMemberNameForProperty_ReturnsCorrectXmlCommentMemberName_ForGivenMemberInfo(
            Type declaringType,
            string fieldOrPropertyName,
            string expectedMemberName
            )
        {
            var memberInfo = declaringType.GetMember(fieldOrPropertyName)[0];

            var memberName = XmlCommentsNodeNameHelper.GetNodeNameForMember(memberInfo);

            _output.WriteLine(expectedMemberName);
            _output.WriteLine(memberName);
            Assert.Equal(expectedMemberName, memberName);
        }
示例#14
0
        private void ApplyPropertyComments(OpenApiSchema propertySchema, MemberInfo memberInfo)
        {
            var memberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(memberInfo);

            if (!_inheritedDocs.ContainsKey(memberName))
            {
                return;
            }

            if (_excludedTypes.Any() && _excludedTypes.ToList()
                .Contains(((PropertyInfo)memberInfo).PropertyType))
            {
                return;
            }

            var cref   = _inheritedDocs[memberName];
            var target = GetTargetRecursive(memberInfo, cref);

            var targetXmlNode = GetMemberXmlNode(XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(target));

            if (targetXmlNode == null)
            {
                return;
            }

            var summaryNode = targetXmlNode.SelectSingleNode(SummaryTag);

            if (summaryNode != null)
            {
                propertySchema.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml);

                if (_includeRemarks)
                {
                    var remarksNode = targetXmlNode.SelectSingleNode(RemarksTag);
                    if (remarksNode != null && !string.IsNullOrWhiteSpace(remarksNode.InnerXml))
                    {
                        propertySchema.Description += $" ({XmlCommentsTextHelper.Humanize(remarksNode.InnerXml)})";
                    }
                }
            }

            var exampleNode = targetXmlNode.SelectSingleNode(ExampleTag);

            if (exampleNode != null)
            {
                propertySchema.Example = new OpenApiString(XmlCommentsTextHelper.Humanize(exampleNode.InnerXml));
            }
        }
示例#15
0
        /// <summary>
        /// Apply filter.
        /// </summary>
        /// <param name="schema"><see cref="OpenApiSchema"/>.</param>
        /// <param name="context"><see cref="SchemaFilterContext"/>.</param>
        public void Apply(OpenApiSchema schema, SchemaFilterContext context)
        {
            if (_excludedTypes.Any() && _excludedTypes.ToList().Contains(context.Type))
            {
                return;
            }

            // Try to apply a description for inherited types.
            var memberName = XmlCommentsNodeNameHelper.GetMemberNameForType(context.Type);

            if (string.IsNullOrEmpty(schema.Description) && _inheritedDocs.ContainsKey(memberName))
            {
                var cref   = _inheritedDocs[memberName];
                var target = GetTargetRecursive(context.Type, cref);

                var targetXmlNode = GetMemberXmlNode(XmlCommentsNodeNameHelper.GetMemberNameForType(target));
                var summaryNode   = targetXmlNode?.SelectSingleNode(SummaryTag);

                if (summaryNode != null)
                {
                    schema.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml);

                    if (_includeRemarks)
                    {
                        var remarksNode = targetXmlNode.SelectSingleNode(RemarksTag);
                        if (remarksNode != null && !string.IsNullOrWhiteSpace(remarksNode.InnerXml))
                        {
                            schema.Description += $" ({XmlCommentsTextHelper.Humanize(remarksNode.InnerXml)})";
                        }
                    }
                }
            }

            if (schema.Properties == null)
            {
                return;
            }

            // Add the summary and examples for the properties.
            foreach (var entry in schema.Properties)
            {
                var memberInfo = ((TypeInfo)context.Type).DeclaredMembers?.FirstOrDefault(p => p.Name.Equals(entry.Key, StringComparison.OrdinalIgnoreCase));
                if (memberInfo != null)
                {
                    ApplyPropertyComments(entry.Value, memberInfo);
                }
            }
        }
示例#16
0
        private Type GetTargetRecursive(Type type, string cref)
        {
            var target = GetTarget(type, cref);

            if (target == null)
            {
                return(null);
            }

            var targetMemberName = XmlCommentsNodeNameHelper.GetMemberNameForType(target);

            if (_inheritedDocs.ContainsKey(targetMemberName))
            {
                return(GetTarget(target, _inheritedDocs[targetMemberName]));
            }

            return(target);
        }
示例#17
0
        private MemberInfo GetTargetRecursive(MemberInfo memberInfo, string cref)
        {
            var target = GetTarget(memberInfo, cref);

            if (target == null)
            {
                return(null);
            }

            var targetMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(target);

            if (_inheritedDocs.ContainsKey(targetMemberName))
            {
                return(GetTarget(target, _inheritedDocs[targetMemberName]));
            }

            return(target);
        }
示例#18
0
        private static string TryGetMemberComments(MemberInfo memberInfo, IEnumerable <XPathNavigator> xmlNavigators)
        {
            if (xmlNavigators == null)
            {
                return(string.Empty);
            }

            foreach (var xmlNavigator in xmlNavigators)
            {
                var nodeNameForMember = XmlCommentsNodeNameHelper.GetNodeNameForMember(memberInfo);
                var xpathNavigator1   = xmlNavigator.SelectSingleNode(
                    $"/doc/members/member[@name='{nodeNameForMember}']");
                var xpathNavigator2 = xpathNavigator1?.SelectSingleNode("summary");
                return(xpathNavigator2 != null?XmlCommentsTextHelper.Humanize(xpathNavigator2.InnerXml) : string.Empty);
            }

            return(string.Empty);
        }
示例#19
0
        private void ApplyTypeTags(OpenApiSchema schema, Type type)
        {
            if (_excludedTypes.Any() && _excludedTypes.ToList().Contains(type))
            {
                return;
            }

            var typeMemberName  = XmlCommentsNodeNameHelper.GetMemberNameForType(type);
            var typeSummaryNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{typeMemberName}']/{SummaryTag}");

            if (typeSummaryNode != null)
            {
                var typeRemarksNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{typeMemberName}']/{RemarksTag}");
                if (typeRemarksNode != null && !string.IsNullOrWhiteSpace(typeRemarksNode.InnerXml))
                {
                    schema.Description +=
                        $" ({XmlCommentsTextHelper.Humanize(typeRemarksNode.InnerXml)})";
                }
            }
        }
示例#20
0
        private static void Populate_MethodParams(XPathNavigator rawRoot, XPathNavigator newPathMembers, MergeArgType type)
        {
            /*
             * <member name="M:DataContract.IService2Async.Call3Async(DataContract.CallObj,System.String)">
             *  <summary>
             *  Call3Async des
             *  </summary>
             *  <param name="obj">obj des</param>
             *  <param name="s1">s1 des</param>
             *  <returns></returns>
             * </member>
             *
             * ->
             *
             * <member name="T:DataContract.CallObjXXX.obj">   //ref obj will ignore the summary
             *  <summary>
             *  obj des
             *  </summary>
             * </member>
             * <member name="T:DataContract.CallObjXXX.s1">
             *  <summary>
             *  s1 des
             *  </summary>
             * </member>
             */

            var methodStr = XmlCommentsNodeNameHelper.GetMemberNameForMethod(type.MethodInfo);

            foreach (var p in type.MethodInfo.GetParameters())
            {
                var pPath = rawRoot.SelectSingleNode($"/doc/members/member[@name='{methodStr}']/param[@name='{p.Name}']");
                var prop  = type.TypeWithoutPathQueryStream !.GetProperties().FirstOrDefault(i => i.Name == p.Name);
                if (pPath != null && prop != null)
                {
                    var str = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(prop);
                    newPathMembers.AppendChild(GetXml(str, pPath.Value));
                }
            }
        }
示例#21
0
        private void ApplyPropertyTags(OpenApiRequestBody requestBody, PropertyInfo propertyInfo)
        {
            if (propertyInfo.DeclaringType != null && _excludedTypes.Any() && _excludedTypes.ToList().Contains(propertyInfo.DeclaringType))
            {
                return;
            }

            var propertyMemberName  = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(propertyInfo);
            var propertySummaryNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{propertyMemberName}']/{SummaryTag}");

            if (propertySummaryNode != null)
            {
                var propertyRemarksNode = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{propertyMemberName}']/{RemarksTag}");
                if (propertyRemarksNode != null &&
                    !string.IsNullOrWhiteSpace(propertyRemarksNode.InnerXml) &&
                    !requestBody.Description.Contains(XmlCommentsTextHelper.Humanize(propertyRemarksNode.InnerXml)))
                {
                    requestBody.Description +=
                        $" ({XmlCommentsTextHelper.Humanize(propertyRemarksNode.InnerXml)})";
                }
            }
        }
示例#22
0
        private void ApplyFieldOrPropertyTags(OpenApiSchema schema, MemberInfo fieldOrPropertyInfo)
        {
            if (fieldOrPropertyInfo.DeclaringType != null && _excludedTypes.Any() && _excludedTypes.ToList().Contains(fieldOrPropertyInfo.DeclaringType))
            {
                return;
            }

            var fieldOrPropertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(fieldOrPropertyInfo);
            var fieldOrPropertyNode       = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{fieldOrPropertyMemberName}']");
            var summaryNode = fieldOrPropertyNode?.SelectSingleNode(SummaryTag);

            if (summaryNode != null)
            {
                var remarksNode = fieldOrPropertyNode.SelectSingleNode(RemarksTag);
                if (remarksNode != null &&
                    !string.IsNullOrWhiteSpace(remarksNode.InnerXml) &&
                    !schema.Description.Contains(XmlCommentsTextHelper.Humanize(remarksNode.InnerXml)))
                {
                    schema.Description +=
                        $" ({XmlCommentsTextHelper.Humanize(remarksNode.InnerXml)})";
                }
            }
        }
示例#23
0
        private static Type GetTarget(Type type, string cref)
        {
            var targets = type.GetInterfaces();

            if (type.BaseType != typeof(object))
            {
                targets = targets.Append(type.BaseType).ToArray();
            }

            // Try to find the target, if one is declared.
            if (!string.IsNullOrEmpty(cref))
            {
                var crefTarget = targets.SingleOrDefault(t => XmlCommentsNodeNameHelper.GetMemberNameForType(t) == cref);

                if (crefTarget != null)
                {
                    return(crefTarget);
                }
            }

            // We use the last since that will be our base class or the "nearest" implemented interface.
            return(targets.LastOrDefault());
        }
        /// <summary>
        /// Apply filter.
        /// </summary>
        /// <param name="swaggerDoc"><see cref="OpenApiDocument"/>.</param>
        /// <param name="context"><see cref="DocumentFilterContext"/>.</param>
        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            // Collect (unique) controller names and types in a dictionary
            var controllerNamesAndTypes = context.ApiDescriptions
                                          .Select(apiDesc => apiDesc.ActionDescriptor as ControllerActionDescriptor)
                                          .SkipWhile(actionDesc => actionDesc == null)
                                          .GroupBy(actionDesc => actionDesc.ControllerName)
                                          .Select(group => new KeyValuePair <string, Type>(group.Key, group.First().ControllerTypeInfo.AsType()));

            foreach (var nameAndType in controllerNamesAndTypes)
            {
                if (_excludedTypes.Any() && _excludedTypes.ToList().Contains(nameAndType.Value))
                {
                    continue;
                }

                var memberName = XmlCommentsNodeNameHelper.GetMemberNameForType(nameAndType.Value);
                var typeNode   = _xmlNavigator.SelectSingleNode(string.Format(MemberXPath, memberName));

                var summaryNode = typeNode?.SelectSingleNode(SummaryTag);
                if (summaryNode != null)
                {
                    var remarksNode = typeNode.SelectSingleNode(RemarksTag);
                    if (remarksNode != null && !string.IsNullOrWhiteSpace(remarksNode.InnerXml))
                    {
                        var tag = swaggerDoc.Tags.FirstOrDefault(t => t.Name.Equals(nameAndType.Key));
                        if (tag != null &&
                            !tag.Description.Contains(XmlCommentsTextHelper.Humanize(remarksNode.InnerXml)))
                        {
                            swaggerDoc.Tags.First(t => t.Name.Equals(nameAndType.Key)).Description +=
                                $" ({XmlCommentsTextHelper.Humanize(remarksNode.InnerXml)})";
                        }
                    }
                }
            }
        }
        private void ApplyFieldOrPropertyTags(OpenApiSchema schema, MemberInfo fieldOrPropertyInfo)
        {
            var fieldOrPropertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(fieldOrPropertyInfo);
            var fieldOrPropertyNode       = _xmlNavigator.SelectSingleNode($"/doc/members/member[@name='{fieldOrPropertyMemberName}']");

            if (fieldOrPropertyNode == null)
            {
                return;
            }

            var summaryNode = fieldOrPropertyNode.SelectSingleNode("summary");

            if (summaryNode != null)
            {
                schema.Description = XmlCommentsTextHelper.Humanize(summaryNode.InnerXml);
            }

            var exampleNode = fieldOrPropertyNode.SelectSingleNode("example");

            if (exampleNode != null)
            {
                schema.Example = JsonMapper.CreateFromJson(exampleNode.InnerXml);
            }
        }