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); }
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); }
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); }
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); }
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)); } }
/// <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); } } }
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); }
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); }
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); }
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)})"; } } }
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)); } } }
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)})"; } } }
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)})"; } } }
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); } }