You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
15 KiB
332 lines
15 KiB
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
using Microsoft.AspNetCore.Routing;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Localization;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Dynamic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
namespace Infrastructure.Extensions
|
|
{
|
|
public static class ControllerExtensions
|
|
{
|
|
public static ModelMetadata GetModelMetadata<T>(this ControllerBase controller)
|
|
{
|
|
if (controller is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(controller));
|
|
}
|
|
return controller.HttpContext.RequestServices.GetRequiredService<IModelMetadataProvider>().GetMetadataForType(typeof(T));
|
|
}
|
|
|
|
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 GetJsonSchema(this ControllerBase controller, Type type)
|
|
{
|
|
if (controller is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(controller));
|
|
}
|
|
var metadata = controller.HttpContext.RequestServices.GetRequiredService<IModelMetadataProvider>().GetMetadataForType(type);
|
|
|
|
return CreateJson(controller, metadata as DefaultModelMetadata);
|
|
}
|
|
|
|
public static SelectList GetSelectList<T>(this Controller controller, object selectedValue)
|
|
{
|
|
var values = from Enum e in Enum.GetValues(typeof(T))
|
|
select new { Id = e.GetValue(), Name = e.GetDisplayName() };
|
|
return new SelectList(values, "Id", "Name", selectedValue);
|
|
}
|
|
|
|
public static object CreateJson(this ControllerBase controller, DefaultModelMetadata metadata, DefaultModelMetadata parent = null)
|
|
{
|
|
if (metadata is null)
|
|
{
|
|
return null;
|
|
}
|
|
try
|
|
{
|
|
var factory = controller.HttpContext.RequestServices.GetService<IStringLocalizerFactory>();
|
|
var localizer = factory.Create("Resources.Resource", Assembly.GetEntryAssembly().GetName().Name);
|
|
dynamic json = new ExpandoObject();
|
|
var dictionary = (IDictionary<string, object>)json;
|
|
//type
|
|
if (metadata.IsNullableValueType)
|
|
{
|
|
json.nullable = true;
|
|
}
|
|
if (metadata.IsComplexType && metadata.IsCollectionType)
|
|
{
|
|
json.type = "array";
|
|
json.items = controller.GetJsonSchema(metadata.ModelType.GenericTypeArguments[0]);
|
|
}
|
|
else if (metadata.IsEnum)
|
|
{
|
|
json.type = "string";
|
|
var type = metadata.IsNullableValueType ? metadata.ModelType.GenericTypeArguments[0] : metadata.ModelType;
|
|
dictionary["enum"] = from Enum e in Enum.GetValues(type) select new { value = e.GetValue(), text = e.ToString(), title = e.GetDisplayName() };
|
|
}
|
|
else
|
|
{
|
|
var modelType = metadata.ModelType;
|
|
var underlyingType = Nullable.GetUnderlyingType(modelType);
|
|
if (underlyingType != null)
|
|
{
|
|
modelType = underlyingType;
|
|
}
|
|
if (modelType == typeof(string))
|
|
{
|
|
json.type = "string";
|
|
}
|
|
else if (modelType == typeof(int) || modelType == typeof(long))
|
|
{
|
|
json.type = "integer";
|
|
json.ui = "string";
|
|
json.digits = new
|
|
{
|
|
message = "整数格式错误"
|
|
};
|
|
}
|
|
else if (modelType == typeof(float) || modelType == typeof(double) || modelType == typeof(decimal))
|
|
{
|
|
json.type = "number";
|
|
json.ui = "string";
|
|
json.number = new
|
|
{
|
|
message = "数值格式错误"
|
|
};
|
|
}
|
|
else if (modelType == typeof(bool))
|
|
{
|
|
json.type = "boolean";
|
|
}
|
|
else if (modelType == typeof(Guid))
|
|
{
|
|
json.type = "guid";
|
|
}
|
|
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 RequiredAttribute requiredAttribute)
|
|
{
|
|
json.required = new
|
|
{
|
|
message = requiredAttribute.GetErrorMessage(localizer, metadata.DisplayName)
|
|
};
|
|
}
|
|
else if (attribute is RegularExpressionAttribute regularExpressionAttribute)
|
|
{//pattern
|
|
json.pattern = new
|
|
{
|
|
regex = regularExpressionAttribute.Pattern,
|
|
message = regularExpressionAttribute.GetErrorMessage(localizer, metadata.DisplayName, regularExpressionAttribute.Pattern)
|
|
};
|
|
}
|
|
else if (attribute is DataTypeAttribute dataTypeAttribute)
|
|
{//format
|
|
if (dataTypeAttribute.DataType == DataType.EmailAddress)
|
|
{
|
|
json.format = "email";
|
|
json.ui = "string";
|
|
json.email = new
|
|
{
|
|
message = "email格式错误"
|
|
};
|
|
}
|
|
else if (dataTypeAttribute.DataType == DataType.Url)
|
|
{
|
|
json.format = "url";
|
|
json.ui = "string";
|
|
json.url = new
|
|
{
|
|
message = "url格式错误"
|
|
};
|
|
}
|
|
else if (dataTypeAttribute.DataType == DataType.DateTime)
|
|
{
|
|
json.format = "date";
|
|
json.ui = "string";
|
|
json.date = new
|
|
{
|
|
message = "日期格式错误"
|
|
};
|
|
}
|
|
else if (dataTypeAttribute.DataType == DataType.CreditCard)
|
|
{
|
|
json.format = "creditcard";
|
|
json.ui = "string";
|
|
json.url = new
|
|
{
|
|
message = "信用卡格式错误"
|
|
};
|
|
}
|
|
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 = new
|
|
{
|
|
min = minLengthAttribute.Length,
|
|
message = minLengthAttribute.GetErrorMessage(localizer, metadata.DisplayName, minLengthAttribute.Length.ToString())
|
|
};
|
|
}
|
|
else if (attribute is MaxLengthAttribute maxLengthAttribute)
|
|
{//maxLength
|
|
json.maxLength = new
|
|
{
|
|
max = maxLengthAttribute.Length,
|
|
message = maxLengthAttribute.GetErrorMessage(localizer, metadata.DisplayName, maxLengthAttribute.Length.ToString())
|
|
};
|
|
}
|
|
else if (attribute is StringLengthAttribute stringLengthAttribute)
|
|
{//minLength,maxLength
|
|
json.rangeLength = new
|
|
{
|
|
min = stringLengthAttribute.MinimumLength,
|
|
max = stringLengthAttribute.MaximumLength,
|
|
message = stringLengthAttribute.GetErrorMessage(localizer, metadata.DisplayName,
|
|
stringLengthAttribute.MinimumLength.ToString(),
|
|
stringLengthAttribute.MaximumLength.ToString())
|
|
};
|
|
}
|
|
else if (attribute is RangeAttribute rangeAttribute)
|
|
{//minimum,maximum
|
|
json.range = new
|
|
{
|
|
min = rangeAttribute.Minimum,
|
|
max = rangeAttribute.Maximum,
|
|
message = rangeAttribute.GetErrorMessage(localizer, metadata.DisplayName,
|
|
rangeAttribute.Minimum.ToString(),
|
|
rangeAttribute.Maximum.ToString())
|
|
};
|
|
}
|
|
else if (attribute is CompareAttribute compareAttribute)
|
|
{//compare 自定义
|
|
var compareName = parent.Properties.FirstOrDefault(o => o.PropertyName == compareAttribute.OtherProperty)?.DisplayName;
|
|
json.equalTo = new
|
|
{
|
|
other = compareAttribute.OtherProperty,
|
|
message = compareAttribute.GetErrorMessage(localizer, metadata.DisplayName, compareName)
|
|
};
|
|
}
|
|
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,
|
|
message = remoteAttribute.GetErrorMessage(localizer, metadata.DisplayName)
|
|
};
|
|
}
|
|
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.ToLower();
|
|
}
|
|
}
|
|
dynamic properties = new ExpandoObject();
|
|
var propertiesDictionary = (IDictionary<string, object>)properties;
|
|
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, metadata);
|
|
}
|
|
json.properties = properties;
|
|
}
|
|
return json;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static bool IsJsonRequest(this ControllerBase controller)
|
|
{
|
|
return controller.Request.Headers["accept"].ToString().Contains("json", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
public static string GetErrorMessage(this ValidationAttribute attribute, IStringLocalizer localizer, params string[] args)
|
|
{
|
|
var localizedString = localizer.GetString(attribute.GetType().Name);
|
|
//return localizedString.ResourceNotFound ? attribute.FormatErrorMessage(args[0]) : string.Format(localizedString.Value, args);
|
|
var format = attribute.ErrorMessage;
|
|
if (localizedString.ResourceNotFound)
|
|
{
|
|
if (string.IsNullOrEmpty(format))
|
|
{
|
|
format = attribute.GetType().GetProperty("ErrorMessageString", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(attribute) as string;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
format = localizedString.Value;
|
|
}
|
|
try
|
|
{
|
|
return string.Format(format, args);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.PrintStack();
|
|
}
|
|
return format;
|
|
}
|
|
}
|
|
} |