修改 可空类型传参处理,添加预处理模型绑定逻辑
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
cf2b3f5954
commit
59ba1a6193
|
|
@ -96,6 +96,9 @@ builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resourc
|
|||
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
||||
builder.Services.AddControllers(options =>
|
||||
{
|
||||
// 插到最前,抢在默认绑定器之前
|
||||
options.ModelBinderProviders.Insert(0, new NullableStructModelBinderProvider());
|
||||
|
||||
options.Filters.Add<ModelActionFilter>();
|
||||
options.Filters.Add<ProjectExceptionFilter>();
|
||||
options.Filters.Add<UnitOfWorkFilter>();
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ using Newtonsoft.Json;
|
|||
using Newtonsoft.Json.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace IRaCIS.Core.API
|
||||
{
|
||||
|
|
@ -51,34 +53,69 @@ namespace IRaCIS.Core.API
|
|||
}
|
||||
public class NullToEmptyStringValueProvider : IValueProvider
|
||||
{
|
||||
PropertyInfo _MemberInfo;
|
||||
PropertyInfo _memberInfo;
|
||||
private readonly bool _isNullable;
|
||||
public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
|
||||
{
|
||||
_MemberInfo = memberInfo;
|
||||
_memberInfo = memberInfo;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// DTO → JSON 返回前端的时候 处理null 变为"" 方便前端判断
|
||||
public object GetValue(object target)
|
||||
{
|
||||
object result = _MemberInfo.GetValue(target);
|
||||
if (_MemberInfo.PropertyType == typeof(string) && result == null) result = "";
|
||||
else if (_MemberInfo.PropertyType == typeof(String[]) && result == null) result = new string[] { };
|
||||
//else if (_MemberInfo.PropertyType == typeof(Nullable<Int32>) && result == null) result = 0;
|
||||
//else if (_MemberInfo.PropertyType == typeof(Nullable<Decimal>) && result == null) result = 0.00M;
|
||||
var result = _memberInfo.GetValue(target);
|
||||
// 检查类型是否为string或string?
|
||||
if (_memberInfo.PropertyType == typeof(string) && result == null)
|
||||
{
|
||||
|
||||
#region 返回的时候处理 string string? null 为"" 不区分处理
|
||||
|
||||
|
||||
//// 如果是string?类型,返回null 可以做到,但是得反射,因为 string string? 是编译层区分的
|
||||
|
||||
//var isNullable1 = _memberInfo.CustomAttributes
|
||||
// .Any(a => a.AttributeType.Name == "NullableAttribute");
|
||||
|
||||
////var isNullable2 = _memberInfo.CustomAttributes
|
||||
//// .Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
|
||||
|
||||
//if (isNullable1)
|
||||
//{
|
||||
// return result;
|
||||
//}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
// 如果是string类型,返回空字符串
|
||||
return string.Empty;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//影响 模型绑定时接收前端的值,同时影响 正常 JSON 序列化
|
||||
public void SetValue(object target, object value)
|
||||
{
|
||||
|
||||
if (_MemberInfo.PropertyType == typeof(string))
|
||||
{
|
||||
//去掉前后空格
|
||||
_MemberInfo.SetValue(target, value == null ? string.Empty : value.ToString() == string.Empty ? value : value/*.ToString().Trim()*/);
|
||||
_memberInfo.SetValue(target, value);
|
||||
|
||||
|
||||
//// 会影响 string? 传递null 变为""
|
||||
|
||||
//if (_memberInfo.PropertyType == typeof(string))
|
||||
//{
|
||||
// //去掉前后空格
|
||||
// _memberInfo.SetValue(target, value == null ? string.Empty : value.ToString() == string.Empty ? value : value/*.ToString().Trim()*/);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// _memberInfo.SetValue(target, value);
|
||||
//}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_MemberInfo.SetValue(target, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
|
@ -28,3 +29,66 @@ public class ModelActionFilter(IStringLocalizer _localizer) : ActionFilterAttrib
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class NullableStructModelBinderProvider : IModelBinderProvider
|
||||
{
|
||||
public IModelBinder? GetBinder(ModelBinderProviderContext context)
|
||||
{
|
||||
// 获取要绑定的模型类型,比如 Guid?, int?, DateTime? 等
|
||||
var type = context.Metadata.ModelType;
|
||||
|
||||
// 检查是否是 Nullable<T> 类型
|
||||
// 1. 必须是泛型类型
|
||||
// 2. 泛型定义必须是 Nullable<>
|
||||
if (!type.IsGenericType ||
|
||||
type.GetGenericTypeDefinition() != typeof(Nullable<>))
|
||||
return null; // 返回 null 表示"我不处理这个类型"
|
||||
|
||||
|
||||
// 获取可空类型内部的实际类型,如 Guid?, int? 中的 Guid, int
|
||||
var innerType = Nullable.GetUnderlyingType(type)!;
|
||||
|
||||
// 创建默认的模型绑定器(系统的原逻辑)
|
||||
var fallback = context.CreateBinder(context.Metadata);
|
||||
|
||||
// 创建泛型绑定器类型:NullableEmptyStringToNullBinder<T>
|
||||
// 比如对于 Guid?,会创建 NullableEmptyStringToNullBinder<Guid>
|
||||
var binderType = typeof(NullableEmptyStringToNullBinder<>).MakeGenericType(innerType);
|
||||
|
||||
// 实例化绑定器,传入默认绑定器作为备用
|
||||
return (IModelBinder)Activator.CreateInstance(binderType, fallback)!;
|
||||
}
|
||||
}
|
||||
|
||||
// 泛型约束:T 必须是值类型(struct),这确保了只处理可空值类型
|
||||
public class NullableEmptyStringToNullBinder<T> : IModelBinder where T : struct
|
||||
{
|
||||
private readonly IModelBinder _fallbackBinder;
|
||||
|
||||
// 构造函数接收一个备用的绑定器(系统的默认绑定器)
|
||||
public NullableEmptyStringToNullBinder(IModelBinder fallbackBinder)
|
||||
{
|
||||
_fallbackBinder = fallbackBinder;
|
||||
}
|
||||
|
||||
public async Task BindModelAsync(ModelBindingContext context)
|
||||
{
|
||||
// 获取前端传递的值
|
||||
var value = context.ValueProvider.GetValue(context.ModelName).FirstValue;
|
||||
|
||||
// 关键逻辑:如果值是空字符串或空白,直接返回 null
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
// 设置绑定结果为 null(表示空值)
|
||||
context.Result = ModelBindingResult.Success(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// 非空 → 完全走系统原逻辑
|
||||
|
||||
// 如果不是空字符串,则使用系统的默认绑定逻辑
|
||||
// 比如将 "123" 转换为 int? 123,或将 GUID 字符串转换为 Guid?
|
||||
await _fallbackBinder.BindModelAsync(context);
|
||||
}
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ using SixLabors.ImageSharp;
|
|||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
|
@ -77,6 +78,41 @@ namespace IRaCIS.Core.Application.Service
|
|||
public static int IntValue = 100;
|
||||
|
||||
|
||||
public class ModelVerifyCommand
|
||||
{
|
||||
public int? IntNUllValue { get; set; }
|
||||
public int IntValue { get; set; }
|
||||
|
||||
public string StringValue { get; set; }
|
||||
|
||||
public string? StringNUllValue { get; set; }
|
||||
|
||||
public Guid GuidValue { get; set; } = NewId.NextSequentialGuid();
|
||||
|
||||
public Guid? GuidNUllValue { get; set; }
|
||||
|
||||
[NotDefault]
|
||||
public Guid GuidValueNotDefault { get; set; }
|
||||
|
||||
|
||||
public bool BoolValue { get; set; }
|
||||
|
||||
public bool? BoolNUllValue { get; set; }
|
||||
|
||||
public DateTime DateTimeValue { get; set; }
|
||||
|
||||
public DateTime? DateTimeNUllValue { get; set; }
|
||||
}
|
||||
|
||||
//创建一个模型验证的方法
|
||||
[AllowAnonymous]
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> PostModelVerify(ModelVerifyCommand modelVerify)
|
||||
{
|
||||
return ResponseOutput.Ok(modelVerify);
|
||||
}
|
||||
|
||||
|
||||
[AllowAnonymous]
|
||||
|
||||
public async Task<IResponseOutput> CreatNewDBStruct()
|
||||
|
|
@ -99,10 +135,10 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
public async Task<IResponseOutput> DeleteCacheDIR()
|
||||
{
|
||||
var list= _dicomStudyRepository.Where(t => t.StudyDIRPath!="").Select(t => t.StudyDIRPath).ToList();
|
||||
var list = _dicomStudyRepository.Where(t => t.StudyDIRPath != "").Select(t => t.StudyDIRPath).ToList();
|
||||
|
||||
|
||||
await _IOSSService.DeleteObjects(list.Select(t => t.TrimStart('/')).ToList(),true);
|
||||
await _IOSSService.DeleteObjects(list.Select(t => t.TrimStart('/')).ToList(), true);
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue