|
1 |
| -using System; |
| 1 | +using Microsoft.OpenApi.Any; |
| 2 | +using Microsoft.OpenApi.Models; |
| 3 | +using Swashbuckle.AspNetCore.SwaggerGen; |
| 4 | +using System; |
2 | 5 | using System.Collections.Generic;
|
| 6 | +using System.Globalization; |
3 | 7 | using System.Linq;
|
4 | 8 | using System.Reflection;
|
5 | 9 | using System.Xml.XPath;
|
6 | 10 |
|
7 |
| -using Microsoft.OpenApi.Any; |
8 |
| -using Microsoft.OpenApi.Models; |
9 |
| -using Swashbuckle.AspNetCore.SwaggerGen; |
10 |
| - |
11 | 11 | namespace Unchase.Swashbuckle.AspNetCore.Extensions.Extensions
|
12 | 12 | {
|
13 | 13 | internal static class XmlCommentsExtensions
|
@@ -114,15 +114,11 @@ private static MemberInfo[] GetTargets(MemberInfo memberInfo, string cref)
|
114 | 114 | }
|
115 | 115 |
|
116 | 116 | // Find all matching members in all interfaces and the base class.
|
117 |
| - var targets = type.GetInterfaces() |
118 |
| - .Append(type.BaseType) |
119 |
| - .SelectMany( |
120 |
| - x => x.FindMembers( |
121 |
| - memberInfo.MemberType, |
122 |
| - BindingFlags.Instance | BindingFlags.Public, |
123 |
| - (info, _) => info.Name == memberInfo.Name, |
124 |
| - null)) |
125 |
| - .ToList(); |
| 117 | + var targets = type.GetInterfaces().Append(type.BaseType).SelectMany(x => x.FindMembers( |
| 118 | + memberInfo.MemberType, |
| 119 | + BindingFlags.Instance | BindingFlags.Public, |
| 120 | + (info, _) => info.Name == memberInfo.Name, |
| 121 | + null)).ToList(); |
126 | 122 |
|
127 | 123 | // Try to find the target, if one is declared.
|
128 | 124 | if (!string.IsNullOrWhiteSpace(cref))
|
@@ -168,7 +164,7 @@ internal static void ApplyPropertyComments(
|
168 | 164 | XPathNavigator targetXmlNode;
|
169 | 165 | if (string.IsNullOrWhiteSpace(cref))
|
170 | 166 | {
|
171 |
| - var target = memberInfo.GetTargetRecursive(inheritedDocs, cref); |
| 167 | + var target = GetTargetRecursive(memberInfo, inheritedDocs, cref); |
172 | 168 | if (target == null)
|
173 | 169 | {
|
174 | 170 | return;
|
@@ -204,10 +200,95 @@ internal static void ApplyPropertyComments(
|
204 | 200 | var exampleNode = targetXmlNode.SelectSingleNode(ExampleTag);
|
205 | 201 | if (exampleNode != null)
|
206 | 202 | {
|
207 |
| - schema.Example = new OpenApiString(XmlCommentsTextHelper.Humanize(exampleNode.InnerXml)); |
| 203 | + schema.Example = GetExampleValue(memberInfo, exampleNode); |
208 | 204 | }
|
209 | 205 | }
|
210 | 206 |
|
| 207 | + private static IOpenApiAny GetExampleValue(MemberInfo memberInfo, XPathNavigator exampleNode) |
| 208 | + { |
| 209 | + var type = GetUnderlyingType(memberInfo); |
| 210 | + var exampleValue = exampleNode.InnerXml; |
| 211 | + |
| 212 | + if (string.IsNullOrEmpty(exampleValue)) |
| 213 | + { |
| 214 | + return new OpenApiNull(); |
| 215 | + } |
| 216 | + |
| 217 | + if (!type.IsNumber()) |
| 218 | + { |
| 219 | + return new OpenApiString(XmlCommentsTextHelper.Humanize(exampleValue)); |
| 220 | + } |
| 221 | + |
| 222 | + |
| 223 | + if ( |
| 224 | + type == typeof(byte) |
| 225 | + || type == typeof(sbyte) |
| 226 | + ) |
| 227 | + { |
| 228 | + return new OpenApiByte(byte.Parse(XmlCommentsTextHelper.Humanize(exampleValue))); |
| 229 | + } |
| 230 | + |
| 231 | + if ( |
| 232 | + type == typeof(short) |
| 233 | + || type == typeof(ushort) |
| 234 | + || type == typeof(int) |
| 235 | + || type == typeof(uint) |
| 236 | + ) |
| 237 | + { |
| 238 | + return new OpenApiInteger(int.Parse(XmlCommentsTextHelper.Humanize(exampleValue), CultureInfo.InvariantCulture)); |
| 239 | + } |
| 240 | + |
| 241 | + if ( |
| 242 | + type == typeof(long) |
| 243 | + || type == typeof(ulong) |
| 244 | + ) |
| 245 | + { |
| 246 | + return new OpenApiLong(long.Parse(XmlCommentsTextHelper.Humanize(exampleValue), CultureInfo.InvariantCulture)); |
| 247 | + } |
| 248 | + |
| 249 | + if ( |
| 250 | + type == typeof(float) |
| 251 | + || type == typeof(decimal) |
| 252 | + ) |
| 253 | + { |
| 254 | + return new OpenApiFloat(float.Parse(XmlCommentsTextHelper.Humanize(exampleValue), CultureInfo.InvariantCulture)); |
| 255 | + } |
| 256 | + |
| 257 | + if (type == typeof(double)) |
| 258 | + { |
| 259 | + return new OpenApiDouble(double.Parse(XmlCommentsTextHelper.Humanize(exampleValue), CultureInfo.InvariantCulture)); |
| 260 | + } |
| 261 | + |
| 262 | + return new OpenApiString(XmlCommentsTextHelper.Humanize(exampleValue)); |
| 263 | + } |
| 264 | + |
| 265 | + private static Type GetUnderlyingType(this MemberInfo member) |
| 266 | + { |
| 267 | + switch (member.MemberType) |
| 268 | + { |
| 269 | + case MemberTypes.Event: |
| 270 | + return ((EventInfo)member).EventHandlerType; |
| 271 | + case MemberTypes.Field: |
| 272 | + return ((FieldInfo)member).FieldType; |
| 273 | + case MemberTypes.Method: |
| 274 | + return ((MethodInfo)member).ReturnType; |
| 275 | + case MemberTypes.Property: |
| 276 | + var propType = ((PropertyInfo)member).PropertyType; |
| 277 | + |
| 278 | + if (!propType.Name.ToLower().Contains("nullable")) |
| 279 | + { |
| 280 | + return propType; |
| 281 | + } |
| 282 | + |
| 283 | + return propType.GenericTypeArguments?.Length > 0 ? propType.GenericTypeArguments[0] : propType; |
| 284 | + |
| 285 | + default: |
| 286 | + throw new ArgumentException |
| 287 | + ( |
| 288 | + "Input MemberInfo must be if type EventInfo, FieldInfo, MethodInfo, or PropertyInfo" |
| 289 | + ); |
| 290 | + } |
| 291 | + } |
211 | 292 | internal static XPathNavigator GetMemberXmlNode(string memberName, List<XPathDocument> documents)
|
212 | 293 | {
|
213 | 294 | string path = $"/doc/members/member[@name='{memberName}']";
|
|
0 commit comments