|
|
|
@ -0,0 +1,197 @@
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
|
|
|
|
using Microsoft.AspNetCore.Routing;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.ComponentModel.DataAnnotations;
|
|
|
|
|
using System.Dynamic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
namespace CSharpObjectJsonSchema.Controllers
|
|
|
|
|
{
|
|
|
|
|
public static class ControllerExtensions
|
|
|
|
|
{
|
|
|
|
|
public static object GetJsonSchema<T>(this ControllerBase controller)
|
|
|
|
|
{
|
|
|
|
|
if (controller is null)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentNullException(nameof(controller));
|
|
|
|
|
}
|
|
|
|
|
var metadata = controller.HttpContext.RequestServices.GetRequiredService<IModelMetadataProvider>().GetMetadataForType(typeof(T));
|
|
|
|
|
|
|
|
|
|
return CreateJson(controller, metadata as DefaultModelMetadata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static object CreateJson(this ControllerBase controller, DefaultModelMetadata metadata)
|
|
|
|
|
{
|
|
|
|
|
if (metadata is null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
dynamic json = new ExpandoObject();
|
|
|
|
|
var dictionary = (IDictionary<string, object>)json;
|
|
|
|
|
//type
|
|
|
|
|
if (metadata.IsComplexType && metadata.IsCollectionType)
|
|
|
|
|
{
|
|
|
|
|
json.type = "array";
|
|
|
|
|
json.items = new { type = metadata.ModelType.GenericTypeArguments[0].Name };
|
|
|
|
|
}
|
|
|
|
|
else if (metadata.IsEnum)
|
|
|
|
|
{
|
|
|
|
|
json.type = "string";
|
|
|
|
|
dictionary["enum"] = metadata.IsNullableValueType ? Enum.GetNames(metadata.ModelType.GenericTypeArguments[0]) : Enum.GetNames(metadata.ModelType);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var modelType = metadata.IsNullableValueType ? metadata.ModelType.GenericTypeArguments[0] : metadata.ModelType;
|
|
|
|
|
if (modelType == typeof(string))
|
|
|
|
|
{
|
|
|
|
|
json.type = "string";
|
|
|
|
|
}
|
|
|
|
|
else if (modelType == typeof(int) || modelType == typeof(long))
|
|
|
|
|
{
|
|
|
|
|
json.type = "integer";
|
|
|
|
|
}
|
|
|
|
|
else if (modelType == typeof(float) || modelType == typeof(double) || modelType == typeof(decimal))
|
|
|
|
|
{
|
|
|
|
|
json.type = "number";
|
|
|
|
|
}
|
|
|
|
|
else if (modelType == typeof(bool))
|
|
|
|
|
{
|
|
|
|
|
json.type = "boolean";
|
|
|
|
|
}
|
|
|
|
|
else if (modelType == typeof(DateTime))
|
|
|
|
|
{
|
|
|
|
|
json.type = "string";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
json.type = "object";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//title
|
|
|
|
|
if (metadata.DisplayName != null)
|
|
|
|
|
{
|
|
|
|
|
json.title = metadata.DisplayName;
|
|
|
|
|
}
|
|
|
|
|
foreach (var attribute in metadata.Attributes.Attributes)
|
|
|
|
|
{
|
|
|
|
|
if (attribute is DescriptionAttribute descriptionAttribute)
|
|
|
|
|
{//description
|
|
|
|
|
json.description = descriptionAttribute.Description;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is RegularExpressionAttribute regularExpressionAttribute)
|
|
|
|
|
{//pattern
|
|
|
|
|
json.pattern = regularExpressionAttribute.Pattern;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is DataTypeAttribute dataTypeAttribute)
|
|
|
|
|
{//format
|
|
|
|
|
if (dataTypeAttribute.DataType == DataType.DateTime)
|
|
|
|
|
{
|
|
|
|
|
json.format = "date-time";
|
|
|
|
|
}
|
|
|
|
|
else if (dataTypeAttribute.DataType == DataType.Time)
|
|
|
|
|
{
|
|
|
|
|
json.format = "time";
|
|
|
|
|
}
|
|
|
|
|
else if (dataTypeAttribute.DataType == DataType.EmailAddress)
|
|
|
|
|
{
|
|
|
|
|
json.format = "email";
|
|
|
|
|
}
|
|
|
|
|
else if (dataTypeAttribute.DataType == DataType.Url)
|
|
|
|
|
{
|
|
|
|
|
json.format = "uri";
|
|
|
|
|
}
|
|
|
|
|
else if (dataTypeAttribute.DataType == DataType.Custom)
|
|
|
|
|
{//自定义
|
|
|
|
|
json.format = dataTypeAttribute.GetDataTypeName().ToLower();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
json.format = dataTypeAttribute.DataType.ToString().ToLower();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is ReadOnlyAttribute readOnlyAttribute)
|
|
|
|
|
{//readOnly
|
|
|
|
|
json.readOnly = readOnlyAttribute.IsReadOnly;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is MinLengthAttribute minLengthAttribute)
|
|
|
|
|
{//minLength
|
|
|
|
|
json.minLength = minLengthAttribute.Length;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is MaxLengthAttribute maxLengthAttribute)
|
|
|
|
|
{//maxLength
|
|
|
|
|
json.maxLength = maxLengthAttribute.Length;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is StringLengthAttribute stringLengthAttribute)
|
|
|
|
|
{//minLength,maxLength
|
|
|
|
|
json.minLength = stringLengthAttribute.MinimumLength;
|
|
|
|
|
json.maxLength = stringLengthAttribute.MaximumLength;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is RangeAttribute rangeAttribute)
|
|
|
|
|
{//minimum,maximum
|
|
|
|
|
json.minimum = rangeAttribute.Minimum;
|
|
|
|
|
json.maximum = rangeAttribute.Maximum;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is ScaffoldColumnAttribute scaffoldColumnAttribute)
|
|
|
|
|
{//scaffold 自定义
|
|
|
|
|
json.scaffold = scaffoldColumnAttribute.Scaffold;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is HiddenInputAttribute hiddenInputAttribute)
|
|
|
|
|
{//hidden 自定义
|
|
|
|
|
json.hidden = hiddenInputAttribute.DisplayValue;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is UIHintAttribute uIHintAttribute)
|
|
|
|
|
{//ui 自定义
|
|
|
|
|
json.ui = uIHintAttribute.UIHint;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is CompareAttribute compareAttribute)
|
|
|
|
|
{//compare 自定义
|
|
|
|
|
json.compare = compareAttribute.OtherProperty;
|
|
|
|
|
}
|
|
|
|
|
else if (attribute is RemoteAttribute remoteAttribute)
|
|
|
|
|
{//remote 自定义
|
|
|
|
|
var routeData = attribute.GetType().GetProperty("RouteData", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(remoteAttribute) as RouteValueDictionary;
|
|
|
|
|
json.remote = new
|
|
|
|
|
{
|
|
|
|
|
url = controller.Url.Action(routeData["action"].ToString(), routeData["controller"].ToString(), new { Area = routeData["area"].ToString() }),
|
|
|
|
|
remoteAttribute.AdditionalFields,
|
|
|
|
|
//remoteAttribute.
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dynamic properties = new ExpandoObject();
|
|
|
|
|
var propertiesDictionary = (IDictionary<string, object>)properties;
|
|
|
|
|
var requiredList = new List<string>();
|
|
|
|
|
if (metadata.IsComplexType && !metadata.IsCollectionType && metadata.Properties.Any())
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in metadata.Properties)
|
|
|
|
|
{
|
|
|
|
|
var modelMetadataItem = item as DefaultModelMetadata;
|
|
|
|
|
propertiesDictionary[item.PropertyName] = CreateJson(controller, modelMetadataItem);
|
|
|
|
|
if (modelMetadataItem.IsRequired)
|
|
|
|
|
{
|
|
|
|
|
requiredList.Add(item.PropertyName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
json.properties = properties;
|
|
|
|
|
if (requiredList.Any())
|
|
|
|
|
{
|
|
|
|
|
json.required = requiredList;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return json;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|