ASP.NET Core Model Class Type Conversion, Swagger Mismatch

2023年9月19日 94点热度 0人点赞 0条评论
内容目录

Model Class:

	public class Test
	{
		[JsonConverter(typeof(string))]
		public int Value { get; set; }
	}

API Interface:

		[HttpPost("aaa")]
		public string AAA([FromBody] Test test)
		{
			return "11111111111";
		}

However, Swagger still displays the type as int and does not reflect the JSON configuration.

Therefore, we need to configure Swagger to properly display the converted type information.

Define a filter:

	/// <summary>
	/// Swagger Model Class Filter
	/// </summary>
	public class MaomiSwaggerSchemaFilter : ISchemaFilter
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="schema">Properties in Swagger</param>
		/// <param name="context">Model Class Context</param>
		public void Apply(OpenApiSchema schema, SchemaFilterContext context)
		{
			// Model class type
			var type = context.Type;

			// If the API parameter is not an object
			if (type.IsPrimitive || TypeInfo.GetTypeCode(type) != TypeCode.Object)
			{
				return;
			}

			// If the API parameter is an object type

			// Get all properties of the type
			PropertyInfo[] ps = context.Type.GetProperties();

			// Get all properties displayed in the Swagger file
			// Note that the documented properties have already been generated. Here we convert them late and replace them with the types to be displayed
			foreach (var property in schema.Properties)
			{
				var p = ps.FirstOrDefault(x => x.Name.ToLower() == property.Key.ToLower());
				if (p == null) continue;
				var t = property.Value.Type;
				var converter = p.GetCustomAttribute<JsonConverterAttribute>();
				if (converter == null || converter.ConverterType == null) continue;

				var targetType = TypeInfo.GetTypeCode(converter.ConverterType);

				// If it is a primitive type, Decimal, or DateTime
				if (targetType != TypeCode.Empty && 
					targetType != TypeCode.DBNull && 
					targetType != TypeCode.Object)
				{
					if (GetValueType(targetType, out var valueType))
					{
						property.Value.Type = valueType;
					}
				}
			}

			static bool GetValueType(TypeCode targetType, out string? valueType)
			{
				valueType = null;
				switch (targetType)
				{
					case TypeCode.Boolean: valueType = "boolean"; break;
					case TypeCode.Char: valueType = "string"; break;
					case TypeCode.SByte: valueType = "integer"; break;
					case TypeCode.Byte: valueType = "integer"; break;
					case TypeCode.Int16: valueType = "integer"; break;
					case TypeCode.UInt16: valueType = "integer"; break;
					case TypeCode.Int32: valueType = "integer"; break;
					case TypeCode.UInt32: valueType = "integer"; break;
					case TypeCode.Int64: valueType = "integer"; break;
					case TypeCode.UInt64: valueType = "integer"; break;
					case TypeCode.Single: valueType = "number"; break;
					case TypeCode.Double: valueType = "number"; break;
					case TypeCode.Decimal: valueType = "number"; break;
					case TypeCode.DateTime: valueType = "string"; break;
					case TypeCode.String: valueType = "string"; break;
					// Generally no need to handle objects
					// case TypeCode.Object: valueType = p.PropertyType.Name; break;
					default: return false;
				}
				return true;
			}
		}
	}

Generally, there's no need to handle objects, but if necessary, you can use:

case TypeCode.Object: property.Value.Type = p.PropertyType.Name; break;

Then configure the Swagger service.

			builder.Services.AddSwaggerGen(options =>
			{
				options.SchemaFilter<CustomSchemaFilter>();
			});

Corresponding primitive types displayed in Swagger:

	public class Test
	{
		public Boolean Value1 { get; set; }
		public char Value2 { get; set; }
		public sbyte Value3 { get; set; }
		public byte Value4 { get; set; }
		public Int16 Value5 { get; set; }
		public UInt16 Value6 { get; set; }
		public Int32 Value7 { get; set; }
		public UInt32 Value8 { get; set; }
		public Int64 Value9 { get; set; }
		public UInt64 Value { get; set; }
		public Single Value10 { get; set; }
		public Double Value11 { get; set; }
		public Decimal Value12 { get; set; }
		public DateTime Value13 { get; set; }
		public String Value14 { get; set; }
	}
{
value1	boolean
value2	string
value3	integer($int32)
value4	integer($int32)
value5	integer($int32)
value6	integer($int32)
value7	integer($int32)
value8	integer($int32)
value9	integer($int64)
value	integer($int64)
value10	number($float)
value11	number($double)
value12	number($double)
value13	string($date-time)
value14	string
}

痴者工良

高级程序员劝退师

文章评论