Browse Source

1.优化权重随机筛选器
2.优化FromBodyOrDefaultModelBinder

懒得勤快 2 years ago
parent
commit
9c31798b58

+ 2 - 3
Masuit.Tools.Abstractions/Extensions/BaseType/IEnumerableExtensions.cs

@@ -10,7 +10,7 @@ using System.Threading.Tasks;
 namespace Masuit.Tools;
 
 /// <summary>
-/// 
+///
 /// </summary>
 public static class IEnumerableExtensions
 {
@@ -73,7 +73,6 @@ public static class IEnumerableExtensions
         }
     }
 
-
     /// <summary>
     /// 多个集合取交集元素
     /// </summary>
@@ -1138,4 +1137,4 @@ public static class IEnumerableExtensions
         list.Remove(item);
         list.Insert(index, item);
     }
-}
+}

+ 1 - 14
Masuit.Tools.Abstractions/Html/HtmlTools.cs

@@ -172,20 +172,7 @@ namespace Masuit.Tools.Html
         /// <returns></returns>
         public static string MatchRandomImgSrc(this string html)
         {
-            var srcs = MatchImgSrcs(html).ToList();
-            var rnd = new Random();
-            return srcs.Count > 0 ? srcs[rnd.Next(srcs.Count)] : default;
-        }
-
-        /// <summary>
-        /// 按顺序优先获取html代码中的img标签的src属性
-        /// </summary>
-        /// <param name="html"></param>
-        /// <returns></returns>
-        public static string MatchSeqRandomImgSrc(this string html)
-        {
-            var srcs = MatchImgSrcs(html).ToList();
-            return srcs.Count > 0 ? srcs.Select((s, i) => new WeightedItem<string>(s, srcs.Count - i)).WeightedItem() : default;
+            return MatchImgSrcs(html).OrderByRandom().FirstOrDefault();
         }
 
         /// <summary>

+ 2 - 2
Masuit.Tools.Abstractions/Masuit.Tools.Abstractions.csproj

@@ -3,7 +3,7 @@
         <TargetFrameworks>netstandard2.0;netstandard2.1;net461;net5;net6;net7</TargetFrameworks>
         <LangVersion>latest</LangVersion>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-        <Version>2.6.3.1</Version>
+        <Version>2.6.4</Version>
         <Authors>懒得勤快</Authors>
         <Description>新手友好的C#万能工具库,码数吐司库,Masuit.Tools基础公共库(适用于.NET4.6.1/.NET Standard2.0及以上项目),包含一些常用的操作类,大都是静态类,加密解密,反射操作,Excel简单导出,权重随机筛选算法,分布式短id,表达式树,linq扩展,文件压缩,多线程下载和FTP客户端,硬件信息,字符串扩展方法,日期时间扩展操作,中国农历,大文件拷贝,图像裁剪,验证码,断点续传,集合扩展等常用封装。
             官网教程:https://tools.masuit.org
@@ -48,7 +48,7 @@
     <ItemGroup>
         <PackageReference Include="Castle.Core" Version="5.1.1" />
         <PackageReference Include="DnsClient" Version="1.7.0" />
-        <PackageReference Include="HtmlSanitizer" Version="8.0.645" />
+        <PackageReference Include="HtmlSanitizer" Version="8.0.692" />
         <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
         <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
         <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

+ 62 - 27
Masuit.Tools.Abstractions/RandomSelector/Extensions.cs

@@ -1,34 +1,69 @@
 using Masuit.Tools.RandomSelector;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 
 namespace Masuit.Tools
 {
-    public static partial class Extensions
-    {
-        public static int TotalWeight<T>(this WeightedSelector<T> selector)
-        {
-            return selector.Items.Count == 0 ? 0 : selector.Items.Sum(t => t.Weight);
-        }
-
-        public static List<WeightedItem<T>> OrderByWeightDescending<T>(this WeightedSelector<T> selector)
-        {
-            return selector.Items.OrderByDescending(item => item.Weight).ToList();
-        }
-
-        public static List<WeightedItem<T>> OrderByWeightAscending<T>(this WeightedSelector<T> selector)
-        {
-            return selector.Items.OrderBy(item => item.Weight).ToList();
-        }
-
-        public static T WeightedItem<T>(this IEnumerable<WeightedItem<T>> list)
-        {
-            return new WeightedSelector<T>(list).Select();
-        }
-
-        public static List<T> WeightedItems<T>(this IEnumerable<WeightedItem<T>> list, int count)
-        {
-            return new WeightedSelector<T>(list).SelectMultiple(count);
-        }
-    }
+	public static partial class Extensions
+	{
+		public static int TotalWeight<T>(this WeightedSelector<T> selector)
+		{
+			return selector.Items.Count == 0 ? 0 : selector.Items.Sum(t => t.Weight);
+		}
+
+		public static List<WeightedItem<T>> OrderByWeightDescending<T>(this WeightedSelector<T> selector)
+		{
+			return selector.Items.OrderByDescending(item => item.Weight).ToList();
+		}
+
+		public static List<WeightedItem<T>> OrderByWeightAscending<T>(this WeightedSelector<T> selector)
+		{
+			return selector.Items.OrderBy(item => item.Weight).ToList();
+		}
+
+		public static T WeightedItem<T>(this IEnumerable<WeightedItem<T>> list)
+		{
+			return new WeightedSelector<T>(list).Select();
+		}
+
+		public static IEnumerable<T> WeightedItems<T>(this IEnumerable<WeightedItem<T>> list, int count)
+		{
+			return new WeightedSelector<T>(list).SelectMultiple(count);
+		}
+
+		/// <summary>
+		/// 执行权重筛选,取多个元素
+		/// </summary>
+		/// <typeparam name="T"></typeparam>
+		/// <param name="source">原始数据</param>
+		/// <param name="count">目标个数</param>
+		/// <param name="keySelector">按哪个属性进行权重筛选</param>
+		/// <param name="option">抽取选项</param>
+		/// <returns></returns>
+		public static IEnumerable<T> WeightedItems<T>(this IEnumerable<T> source, int count, Func<T, int> keySelector, SelectorOption option = null)
+		{
+			if (!source.Any())
+			{
+				return source;
+			}
+
+			var selector = new WeightedSelector<T>(source.Select(t => new WeightedItem<T>(t, keySelector(t))), option);
+			return selector.SelectMultiple(count);
+		}
+
+		/// <summary>
+		/// 执行权重筛选,取1个元素
+		/// </summary>
+		/// <typeparam name="T"></typeparam>
+		/// <param name="source">原始数据</param>
+		/// <param name="keySelector">按哪个属性进行权重筛选</param>
+		/// <param name="option">抽取选项</param>
+		/// <returns></returns>
+		public static T WeightedBy<T>(this IEnumerable<T> source, Func<T, int> keySelector, SelectorOption option = null)
+		{
+			var selector = new WeightedSelector<T>(source.Select(t => new WeightedItem<T>(t, keySelector(t))), option);
+			return selector.Select();
+		}
+	}
 }

+ 43 - 43
Masuit.Tools.Abstractions/RandomSelector/MultipleSelector.cs

@@ -3,52 +3,52 @@ using System.Collections.Generic;
 
 namespace Masuit.Tools.RandomSelector
 {
-    /// <summary>
-    /// 多选器
-    /// </summary>
-    /// <typeparam name="T"></typeparam>
-    internal class MultipleSelector<T> : SelectorBase<T>
-    {
-        internal MultipleSelector(WeightedSelector<T> weightedSelector) : base(weightedSelector)
-        {
-        }
+	/// <summary>
+	/// 多选器
+	/// </summary>
+	/// <typeparam name="T"></typeparam>
+	internal class MultipleSelector<T> : SelectorBase<T>
+	{
+		internal MultipleSelector(WeightedSelector<T> weightedSelector) : base(weightedSelector)
+		{
+		}
 
-        internal List<T> Select(int count)
-        {
-            Validate(ref count);
-            var items = new List<WeightedItem<T>>(WeightedSelector.Items);
-            var resultList = new List<T>();
+		internal IEnumerable<T> Select(int count)
+		{
+			Validate(ref count);
+			var items = new List<WeightedItem<T>>(WeightedSelector.Items);
+			int result = 0;
+			do
+			{
+				var item = WeightedSelector.Option.AllowDuplicate ? BinarySelect(items) : LinearSelect(items);
+				yield return item.Value;
+				result++;
+				if (!WeightedSelector.Option.AllowDuplicate)
+				{
+					items.Remove(item);
+				}
+			} while (result < count);
+		}
 
-            do
-            {
-                var item = WeightedSelector.Option.AllowDuplicate ? BinarySelect(items) : LinearSelect(items);
-                resultList.Add(item.Value);
-                if (!WeightedSelector.Option.AllowDuplicate)
-                {
-                    items.Remove(item);
-                }
-            } while (resultList.Count < count);
-            return resultList;
-        }
+		private void Validate(ref int count)
+		{
+			if (count <= 0)
+			{
+				throw new InvalidOperationException("筛选个数必须大于0");
+			}
 
-        private void Validate(ref int count)
-        {
-            if (count <= 0)
-            {
-                throw new InvalidOperationException("筛选个数必须大于0");
-            }
+			var items = WeightedSelector.Items;
 
-            var items = WeightedSelector.Items;
+			if (items.Count == 0)
+			{
+				count = 0;
+				return;
+			}
 
-            if (items.Count == 0)
-            {
-                throw new InvalidOperationException("没有元素可以被筛选");
-            }
-
-            if (!WeightedSelector.Option.AllowDuplicate && items.Count < count)
-            {
-                count = items.Count;
-            }
-        }
-    }
+			if (!WeightedSelector.Option.AllowDuplicate && items.Count < count)
+			{
+				count = items.Count;
+			}
+		}
+	}
 }

+ 57 - 56
Masuit.Tools.Abstractions/RandomSelector/SelectorBase.cs

@@ -4,60 +4,61 @@ using System.Linq;
 
 namespace Masuit.Tools.RandomSelector
 {
-    internal abstract class SelectorBase<T>
-    {
-        protected readonly WeightedSelector<T> WeightedSelector;
-
-        internal SelectorBase(WeightedSelector<T> weightedSelector)
-        {
-            WeightedSelector = weightedSelector;
-        }
-
-        /// <summary>
-        /// 执行二进制筛选
-        /// </summary>
-        internal WeightedItem<T> BinarySelect(List<WeightedItem<T>> items)
-        {
-            if (items.Count == 0)
-            {
-                throw new InvalidOperationException("没有元素可以筛选");
-            }
-
-            int index = Array.BinarySearch(WeightedSelector.CumulativeWeights, new Random().Next(1, items.Sum(i => i.Weight) + 1));
-            //如果存在接近的匹配项,二进制搜索返回的负数会比搜索的第1个索引少1。
-            if (index < 0)
-            {
-                index = -index - 1;
-            }
-
-            return items[index];
-        }
-
-        /// <summary>
-        /// 线性筛选
-        /// </summary>
-        /// <param name="items"></param>
-        /// <returns></returns>
-        internal WeightedItem<T> LinearSelect(List<WeightedItem<T>> items)
-        {
-            // 只对具有允许重复项的多选功能有用,它会随着时间从列表中删除项目。 在这些条件下没有消耗更多性能让二进制搜索起作用。
-            if (!items.Any())
-            {
-                throw new InvalidOperationException("没有元素可以筛选");
-            }
-
-            var count = 0;
-            var seed = new Random().Next(1, items.Sum(i => i.Weight) + 1);
-            foreach (var item in items)
-            {
-                count += item.Weight;
-                if (seed <= count)
-                {
-                    return item;
-                }
-            }
-
-            return items.FirstOrDefault();
-        }
-    }
+	internal abstract class SelectorBase<T>
+	{
+		protected readonly WeightedSelector<T> WeightedSelector;
+
+		internal SelectorBase(WeightedSelector<T> weightedSelector)
+		{
+			WeightedSelector = weightedSelector;
+		}
+
+		/// <summary>
+		/// 执行二进制筛选
+		/// </summary>
+		internal WeightedItem<T> BinarySelect(List<WeightedItem<T>> items)
+		{
+			if (items.Count == 0)
+			{
+				throw new InvalidOperationException("没有元素可以筛选");
+			}
+
+			int index = Array.BinarySearch(WeightedSelector.CumulativeWeights, new Random().Next(1, items.Sum(i => i.Weight) + 1));
+
+			//如果存在接近的匹配项,二进制搜索返回的负数会比搜索的第1个索引少1。
+			if (index < 0)
+			{
+				index = -index - 1;
+			}
+
+			return items[index];
+		}
+
+		/// <summary>
+		/// 线性筛选
+		/// </summary>
+		/// <param name="items"></param>
+		/// <returns></returns>
+		internal WeightedItem<T> LinearSelect(List<WeightedItem<T>> items)
+		{
+			// 只对具有允许重复项的多选功能有用,它会随着时间从列表中删除项目。 在这些条件下没有消耗更多性能让二进制搜索起作用。
+			if (!items.Any())
+			{
+				return new WeightedItem<T>(default(T), 0);
+			}
+
+			var count = 0;
+			var seed = new Random().Next(1, items.Sum(i => i.Weight) + 1);
+			foreach (var item in items)
+			{
+				count += item.Weight;
+				if (seed <= count)
+				{
+					return item;
+				}
+			}
+
+			return items.FirstOrDefault();
+		}
+	}
 }

+ 18 - 18
Masuit.Tools.Abstractions/RandomSelector/SingleSelector.cs

@@ -2,24 +2,24 @@
 
 namespace Masuit.Tools.RandomSelector
 {
-    /// <summary>
-    /// 单选器
-    /// </summary>
-    /// <typeparam name="T"></typeparam>
-    internal class SingleSelector<T> : SelectorBase<T>
-    {
-        internal SingleSelector(WeightedSelector<T> weightedSelector) : base(weightedSelector)
-        {
-        }
+	/// <summary>
+	/// 单选器
+	/// </summary>
+	/// <typeparam name="T"></typeparam>
+	internal class SingleSelector<T> : SelectorBase<T>
+	{
+		internal SingleSelector(WeightedSelector<T> weightedSelector) : base(weightedSelector)
+		{
+		}
 
-        internal T Select()
-        {
-            if (WeightedSelector.Items.Count == 0)
-            {
-                throw new InvalidOperationException("没有元素可以筛选");
-            }
+		internal T Select()
+		{
+			if (WeightedSelector.Items.Count == 0)
+			{
+				return default(T);
+			}
 
-            return BinarySelect(WeightedSelector.Items).Value;
-        }
-    }
+			return BinarySelect(WeightedSelector.Items).Value;
+		}
+	}
 }

+ 2 - 1
Masuit.Tools.Abstractions/RandomSelector/WeightedSelector.cs

@@ -103,7 +103,7 @@ namespace Masuit.Tools.RandomSelector
         /// <summary>
         /// 执行权重筛选,取多个元素
         /// </summary>
-        public List<T> SelectMultiple(int count)
+        public IEnumerable<T> SelectMultiple(int count)
         {
             CalculateCumulativeWeights();
             var selector = new MultipleSelector<T>(this);
@@ -145,6 +145,7 @@ namespace Masuit.Tools.RandomSelector
 
             return results;
         }
+
         public IEnumerator<T> GetEnumerator()
         {
             return Items.GetEnumerator() as IEnumerator<T>;

+ 1 - 1
Masuit.Tools.Abstractions/Systems/DeserializeOnlyJsonPropertyAttribute.cs

@@ -11,7 +11,7 @@ public class DeserializeOnlyJsonPropertyAttribute : Attribute
 }
 
 /// <summary>
-/// 只允许序列化
+/// 只允许序列化
 /// </summary>
 [AttributeUsage(AttributeTargets.Property)]
 public class SerializeOnlyJsonPropertyAttribute : Attribute

+ 1 - 1
Masuit.Tools.AspNetCore/Masuit.Tools.AspNetCore.csproj

@@ -18,7 +18,7 @@
         <Product>Masuit.Tools.AspNetCore</Product>
         <PackageId>Masuit.Tools.AspNetCore</PackageId>
         <LangVersion>latest</LangVersion>
-        <Version>1.2.3.1</Version>
+        <Version>1.2.4</Version>
         <RepositoryType></RepositoryType>
         <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
         <FileVersion>1.1.9</FileVersion>

+ 0 - 17
Masuit.Tools.AspNetCore/ModelBinder/BodyOrDefaultBindingSource.cs

@@ -1,17 +0,0 @@
-using Microsoft.AspNetCore.Mvc.ModelBinding;
-
-namespace Masuit.Tools.AspNetCore.ModelBinder;
-
-public class BodyOrDefaultBindingSource : BindingSource
-{
-    public static readonly BindingSource BodyOrDefault = new BodyOrDefaultBindingSource("BodyOrDefault", "BodyOrDefault", true, true);
-
-    public BodyOrDefaultBindingSource(string id, string displayName, bool isGreedy, bool isFromRequest) : base(id, displayName, isGreedy, isFromRequest)
-    {
-    }
-
-    public override bool CanAcceptDataFrom(BindingSource bindingSource)
-    {
-        return bindingSource == Body || bindingSource == this;
-    }
-}

+ 283 - 87
Masuit.Tools.AspNetCore/ModelBinder/BodyOrDefaultModelBinder.cs

@@ -1,93 +1,289 @@
-using Microsoft.AspNetCore.Mvc.ModelBinding;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System.Text;
+using System.Collections;
+using System.Net.Mime;
+using System.Reflection;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.Extensions.Primitives;
 
 namespace Masuit.Tools.AspNetCore.ModelBinder;
 
 public class BodyOrDefaultModelBinder : IModelBinder
 {
-    private readonly IModelBinder _bodyBinder;
-    private readonly IModelBinder _complexBinder;
-
-    public BodyOrDefaultModelBinder(IModelBinder bodyBinder, IModelBinder complexBinder)
-    {
-        _bodyBinder = bodyBinder;
-        _complexBinder = complexBinder;
-    }
-
-    public async Task BindModelAsync(ModelBindingContext bindingContext)
-    {
-        var request = bindingContext.HttpContext.Request;
-        request.EnableBuffering();
-        var buffer = new byte[Convert.ToInt32(request.ContentLength)];
-        _ = await request.Body.ReadAsync(buffer, 0, buffer.Length);
-        var text = Encoding.UTF8.GetString(buffer);
-        request.Body.Position = 0;
-
-        if (bindingContext.ModelType.IsPrimitive || bindingContext.ModelType == typeof(string) || bindingContext.ModelType.IsEnum || bindingContext.ModelType == typeof(DateTime) || bindingContext.ModelType == typeof(Guid) || (bindingContext.ModelType.IsGenericType && bindingContext.ModelType.GetGenericTypeDefinition() == typeof(Nullable<>)))
-        {
-            var parameter = bindingContext.ModelMetadata.ParameterName;
-            var value = "";
-            if (request.Query.ContainsKey(parameter))
-            {
-                value = request.Query[parameter] + "";
-            }
-            else if (request.ContentType is not null && request.ContentType.StartsWith("application/json"))
-            {
-                try
-                {
-                    value = JObject.Parse(text)[parameter] + "";
-                }
-                catch
-                {
-                    value = text.Trim('"');
-                }
-            }
-            else if (request.HasFormContentType)
-            {
-                value = request.Form[bindingContext.ModelMetadata.ParameterName] + "";
-            }
-
-            if (value.TryConvertTo(bindingContext.ModelType, out var result))
-            {
-                bindingContext.Result = ModelBindingResult.Success(result);
-            }
-            return;
-        }
-
-        if (request.HasFormContentType)
-        {
-            if (bindingContext.ModelType.IsClass)
-            {
-                await DefaultBindModel(bindingContext);
-            }
-            else
-            {
-                bindingContext.Result = ModelBindingResult.Success(request.Form[bindingContext.ModelMetadata.ParameterName].ToString().ConvertTo(bindingContext.ModelType));
-            }
-            return;
-        }
-
-        try
-        {
-            bindingContext.Result = ModelBindingResult.Success(JsonConvert.DeserializeObject(text, bindingContext.ModelType) ?? request.Query[bindingContext.ModelMetadata.ParameterName!].ToString().ConvertTo(bindingContext.ModelType));
-        }
-        catch
-        {
-            await DefaultBindModel(bindingContext);
-        }
-    }
-
-    private async Task DefaultBindModel(ModelBindingContext bindingContext)
-    {
-        await _bodyBinder.BindModelAsync(bindingContext);
-        if (bindingContext.Result.IsModelSet)
-        {
-            return;
-        }
-
-        bindingContext.ModelState.Clear();
-        await _complexBinder.BindModelAsync(bindingContext);
-    }
+	private static readonly List<BindType> AutoTypes;
+
+	static BodyOrDefaultModelBinder()
+	{
+		AutoTypes = Enum.GetNames(typeof(BindType)).Select(t => Enum.Parse<BindType>(t)).Where(t => t != BindType.None && t != BindType.Services).ToList();
+	}
+
+	private readonly ILogger<BodyOrDefaultModelBinder> _logger;
+
+	public BodyOrDefaultModelBinder(ILogger<BodyOrDefaultModelBinder> logger)
+	{
+		_logger = logger;
+	}
+
+	public Task BindModelAsync(ModelBindingContext bindingContext)
+	{
+		var context = bindingContext.HttpContext;
+		var attr = bindingContext.GetAttribute<FromBodyOrDefaultAttribute>();
+		var fieldName = attr?.FieldName ?? bindingContext.FieldName;
+		var modelType = bindingContext.ModelType;
+		object targetValue = null;
+		if (attr != null)
+		{
+			if (modelType.IsSimpleType() || modelType.IsSimpleArrayType() || modelType.IsSimpleListType())
+			{
+				if (attr.Type == BindType.None)
+				{
+					foreach (var type in AutoTypes)
+					{
+						targetValue = GetBindingValue(bindingContext, type, fieldName, modelType);
+						if (targetValue != null)
+						{
+							break;
+						}
+					}
+				}
+				else
+				{
+					targetValue = GetBindingValue(bindingContext, attr.Type, fieldName, modelType);
+				}
+			}
+			else
+			{
+				if (BodyOrDefaultModelBinderMiddleware.JsonObject != null)
+				{
+					if (modelType.IsArray || modelType.IsGenericType && modelType.GenericTypeArguments.Length == 1)
+					{
+						if (BodyOrDefaultModelBinderMiddleware.JsonObject.TryGetValue(fieldName, StringComparison.OrdinalIgnoreCase, out var jtoken))
+						{
+							targetValue = jtoken.ToObject(modelType);
+						}
+						else
+						{
+							_logger.LogWarning($"TraceIdentifier:{context.TraceIdentifier},AutoBinderMiddleware从{BodyOrDefaultModelBinderMiddleware.JsonObject}中获取{fieldName}失败!");
+						}
+					}
+					else
+					{
+						// 可能是 字典或者实体 类型,尝试将modeltype 当初整个请求参数对象
+						try
+						{
+							targetValue = BodyOrDefaultModelBinderMiddleware.JsonObject.ToObject(modelType);
+						}
+						catch (Exception e)
+						{
+							_logger.LogError(e, e.Message, BodyOrDefaultModelBinderMiddleware.JsonObject.ToString());
+						}
+					}
+				}
+
+				if (targetValue == null)
+				{
+					var (requestData, keys) = GetRequestData(bindingContext, modelType);
+					if (keys.Any())
+					{
+						var setObj = Activator.CreateInstance(modelType);
+						switch (requestData)
+						{
+							case IEnumerable<KeyValuePair<string, StringValues>> stringValues:
+								{
+									foreach (var item in stringValues)
+									{
+										var prop = modelType.GetProperty(item.Key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
+										if (prop != null)
+										{
+											prop.SetValue(setObj, item.Value.ConvertObject(prop.PropertyType));
+										}
+									}
+
+									break;
+								}
+							case IEnumerable<KeyValuePair<string, string>> strs:
+								{
+									//处理Cookie
+									foreach (var item in strs)
+									{
+										var prop = modelType.GetProperty(item.Key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
+										if (prop != null)
+										{
+											prop.SetValue(setObj, item.Value.ConvertObject(prop.PropertyType));
+										}
+									}
+
+									break;
+								}
+							case IEnumerable<KeyValuePair<string, object>> objects:
+								{
+									//处理路由
+									foreach (var item in objects)
+									{
+										var prop = modelType.GetProperty(item.Key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
+										if (prop != null)
+										{
+											prop.SetValue(setObj, item.Value.ConvertObject(prop.PropertyType));
+										}
+									}
+
+									break;
+								}
+						}
+
+						targetValue = setObj;
+					}
+				}
+			}
+
+			if (targetValue == null && attr.DefaultValue != null)
+			{
+				targetValue = attr.DefaultValue.ChangeType(modelType);
+			}
+		}
+
+		if (targetValue != null)
+		{
+			bindingContext.Result = ModelBindingResult.Success(targetValue);
+		}
+
+		return Task.CompletedTask;
+	}
+
+	private static (IEnumerable data, List<string> keys) GetRequestData(ModelBindingContext bindingContext, Type type)
+	{
+		var request = bindingContext.HttpContext.Request;
+		var props = type.GetProperties().Select(t => t.Name).ToList();
+		var query = props.Except(request.Query.Keys, StringComparer.OrdinalIgnoreCase).ToList();
+		var headers = props.Except(request.Headers.Keys, StringComparer.OrdinalIgnoreCase).ToList();
+		var cookies = props.Except(request.Cookies.Keys, StringComparer.OrdinalIgnoreCase).ToList();
+		var routes = props.Except(bindingContext.ActionContext.RouteData.Values.Keys, StringComparer.OrdinalIgnoreCase).ToList();
+		var list = new List<KeyValuePair<List<string>, IEnumerable>>()
+		{
+			new(query, request.Query),
+			new(headers, request.Headers),
+			new(cookies, request.Cookies),
+			new(routes, bindingContext.ActionContext.RouteData.Values),
+		};
+
+		if (request.HasFormContentType && request.Form.Count > 0)
+		{
+			var forms = props.Except(request.Form.Keys, StringComparer.OrdinalIgnoreCase).ToList();
+			list.Add(new KeyValuePair<List<string>, IEnumerable>(forms, request.Form));
+		}
+
+		var kv = list.OrderBy(t => t.Key.Count).FirstOrDefault();
+		return (kv.Value, props.Except(kv.Key).ToList());
+	}
+
+	/// <summary>
+	/// 获取要绑定的值
+	/// </summary>
+	/// <param name="bindingContext"></param>
+	/// <param name="bindType"></param>
+	/// <param name="fieldName"></param>
+	/// <param name="modelType"></param>
+	/// <returns></returns>
+	private object GetBindingValue(ModelBindingContext bindingContext, BindType bindType, string fieldName, Type modelType)
+	{
+		var context = bindingContext.HttpContext;
+		var mediaType = string.Empty;
+		if (!string.IsNullOrWhiteSpace(context.Request.ContentType))
+		{
+			try
+			{
+				var cttType = new ContentType(context.Request.ContentType);
+				mediaType = cttType.MediaType.ToLower();
+			}
+			catch (Exception ex)
+			{
+				_logger.LogError(ex, ex.Message, context.Request.ContentType);
+			}
+		}
+
+		object targetValue = null;
+		switch (bindType)
+		{
+			case BindType.Body:
+				switch (mediaType)
+				{
+					case "application/json":
+						{
+							var jsonObj = BodyOrDefaultModelBinderMiddleware.JsonObject;
+							if (jsonObj != null && jsonObj.TryGetValue(fieldName, StringComparison.OrdinalIgnoreCase, out var values))
+							{
+								targetValue = values.ConvertObject(modelType);
+							}
+						}
+
+						break;
+
+					case "application/xml":
+
+						//var xmlObj = AutoBinderMiddleware.XmlObject;
+
+						//if (xmlObj != null)
+						//{
+						//    var xmlElt = xmlObj.Element(fieldName);
+
+						//    if (xmlElt != null)
+						//    {
+						//    }
+						//}
+						break;
+				}
+
+				break;
+
+			case BindType.Query:
+				{
+					if (context.Request.Query != null && context.Request.Query.Count > 0 && context.Request.Query.TryGetValue(fieldName, out var values))
+					{
+						targetValue = values.ConvertObject(modelType);
+					}
+				}
+
+				break;
+
+			case BindType.Form:
+				{
+					if (context.Request.HasFormContentType && context.Request.Form.Count > 0 && context.Request.Form.TryGetValue(fieldName, out StringValues values))
+					{
+						targetValue = values.ConvertObject(modelType);
+					}
+				}
+
+				break;
+
+			case BindType.Header:
+				{
+					if (context.Request.Headers != null && context.Request.Headers.Count > 0 && context.Request.Headers.TryGetValue(fieldName, out var values))
+					{
+						targetValue = values.ConvertObject(modelType);
+					}
+				}
+
+				break;
+
+			case BindType.Cookie:
+				{
+					if (context.Request.Cookies != null && context.Request.Cookies.Count > 0 && context.Request.Cookies.TryGetValue(fieldName, out var values))
+					{
+						targetValue = values.ConvertObject(modelType);
+					}
+				}
+
+				break;
+
+			case BindType.Route:
+				{
+					if (bindingContext.ActionContext.RouteData.Values != null && bindingContext.ActionContext.RouteData.Values.Count > 0 && bindingContext.ActionContext.RouteData.Values.TryGetValue(fieldName, out var values))
+					{
+						targetValue = values.ConvertObject(modelType);
+					}
+				}
+
+				break;
+		}
+
+		return targetValue;
+	}
 }

+ 112 - 0
Masuit.Tools.AspNetCore/ModelBinder/BodyOrDefaultModelBinderMiddleware.cs

@@ -0,0 +1,112 @@
+using System.Net.Mime;
+using System.Text;
+using System.Xml.Linq;
+using Newtonsoft.Json.Linq;
+
+namespace Masuit.Tools.AspNetCore.ModelBinder;
+
+public sealed class BodyOrDefaultModelBinderMiddleware
+{
+	private readonly RequestDelegate _next;
+	private readonly ILogger<BodyOrDefaultModelBinderMiddleware> _logger;
+
+	public BodyOrDefaultModelBinderMiddleware(RequestDelegate next, ILogger<BodyOrDefaultModelBinderMiddleware> logger)
+	{
+		_next = next;
+		_logger = logger;
+	}
+
+	public static JObject JsonObject { get; private set; }
+
+	public static XDocument XmlObject { get; private set; }
+
+	public Task Invoke(HttpContext context)
+	{
+		JsonObject = null;
+		XmlObject = null;
+
+		var contentType = context.Request.ContentType;
+		string mediaType;
+		var charSet = "utf-8";
+
+		if (string.IsNullOrWhiteSpace(contentType))
+		{
+			//表单提交
+			mediaType = "application/x-www-form-urlencoded";
+		}
+		else
+		{
+			var cttType = new ContentType(contentType);
+			if (!string.IsNullOrWhiteSpace(cttType.CharSet))
+			{
+				charSet = cttType.CharSet;
+			}
+			mediaType = cttType.MediaType.ToLower();
+		}
+
+		Encoding encoding = Encoding.GetEncoding(charSet);
+
+		if (mediaType == "application/x-www-form-urlencoded")
+		{
+			//普通表单提交
+		}
+		else if (mediaType == "multipart/form-data")
+		{
+			//带有文件的表单提交
+		}
+		else if (mediaType == "application/json")
+		{
+			#region json数据提交
+
+			var body = context.GetBodyString(encoding)?.Trim();
+
+			if (string.IsNullOrWhiteSpace(body))
+			{
+				return _next(context);
+			}
+
+			if (!(body.StartsWith("{") && body.EndsWith("}")))
+			{
+				return _next(context);
+			}
+
+			try
+			{
+				JsonObject = JObject.Parse(body);
+				return _next(context);
+			}
+			catch (Exception ex)
+			{
+				_logger.LogError(ex, "Parsing json failed:" + body);
+				return _next(context);
+			}
+
+			#endregion json数据提交
+		}
+		else if (mediaType == "application/xml")
+		{
+			#region xml数据提交
+
+			var body = context.GetBodyString(encoding)?.Trim();
+
+			if (string.IsNullOrWhiteSpace(body))
+			{
+				return _next(context);
+			}
+
+			try
+			{
+				XmlObject = XDocument.Parse(body);
+				return _next(context);
+			}
+			catch (Exception ex)
+			{
+				_logger.LogError(ex, "Parsing xml failed:" + body);
+				return _next(context);
+			}
+
+			#endregion xml数据提交
+		}
+		return _next(context);
+	}
+}

+ 14 - 0
Masuit.Tools.AspNetCore/ModelBinder/BodyOrDefaultModelBinderMiddlewareExtensions.cs

@@ -0,0 +1,14 @@
+namespace Masuit.Tools.AspNetCore.ModelBinder;
+
+public static class BodyOrDefaultModelBinderMiddlewareExtensions
+{
+	/// <summary>
+	/// 使用自动参数绑定中间件
+	/// </summary>
+	/// <param name="appBuilder"></param>
+	/// <returns></returns>
+	public static IApplicationBuilder UseBodyOrDefaultModelBinder(this IApplicationBuilder appBuilder)
+	{
+		return appBuilder.UseMiddleware<BodyOrDefaultModelBinderMiddleware>();
+	}
+}

+ 0 - 37
Masuit.Tools.AspNetCore/ModelBinder/BodyOrDefaultModelBinderProvider.cs

@@ -1,37 +0,0 @@
-using Microsoft.AspNetCore.Mvc.ModelBinding;
-using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
-
-#if NET5_0_OR_GREATER
-
-using ComplexDataModelBinderProvider = Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinderProvider;
-
-#else
-
-using ComplexDataModelBinderProvider = Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinderProvider;
-
-#endif
-
-namespace Masuit.Tools.AspNetCore.ModelBinder;
-
-public class BodyOrDefaultModelBinderProvider : IModelBinderProvider
-{
-    private readonly BodyModelBinderProvider _bodyModelBinderProvider;
-    private readonly ComplexDataModelBinderProvider _complexDataModelBinderProvider;
-
-    public BodyOrDefaultModelBinderProvider(BodyModelBinderProvider bodyModelBinderProvider, ComplexDataModelBinderProvider complexDataModelBinderProvider)
-    {
-        _bodyModelBinderProvider = bodyModelBinderProvider;
-        _complexDataModelBinderProvider = complexDataModelBinderProvider;
-    }
-
-    public IModelBinder GetBinder(ModelBinderProviderContext context)
-    {
-        if (context.BindingInfo.BindingSource != null && (context.BindingInfo.BindingSource.CanAcceptDataFrom(BindingSource.Body) || context.BindingInfo.BindingSource.CanAcceptDataFrom(BodyOrDefaultBindingSource.BodyOrDefault)))
-        {
-            var bodyBinder = _bodyModelBinderProvider.GetBinder(context);
-            var complexBinder = _complexDataModelBinderProvider.GetBinder(context);
-            return new BodyOrDefaultModelBinder(bodyBinder, complexBinder);
-        }
-        return null;
-    }
-}

+ 235 - 16
Masuit.Tools.AspNetCore/ModelBinder/BodyOrDefaultModelBinderProviderSetup.cs

@@ -1,24 +1,243 @@
-using Microsoft.AspNetCore.Mvc.ModelBinding;
-using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
+using System.Net.Mime;
+using System.Text;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.Extensions.Primitives;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
 
-#if NET5_0_OR_GREATER
+namespace Masuit.Tools.AspNetCore.ModelBinder;
 
-using ComplexDataModelBinderProvider = Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinderProvider;
+internal static class BodyOrDefaultModelBinderProviderSetup
+{
+	/// <summary>
+	/// 获取绑定参数对应的 Attribute
+	/// </summary>
+	/// <typeparam name="T">Attribute对象</typeparam>
+	/// <param name="bindingContext">绑定参数上下文</param>
+	/// <param name="parameterName">参数名称</param>
+	/// <returns></returns>
+	public static T GetAttribute<T>(this ModelBindingContext bindingContext, string parameterName = null) where T : Attribute
+	{
+		var fieldName = parameterName ?? bindingContext.FieldName;
+		var ctrlActionDesc = bindingContext.ActionContext.ActionDescriptor as ControllerActionDescriptor;
+		var fieldParameter = ctrlActionDesc!.MethodInfo.GetParameters().Single(p => p.Name == fieldName);
+		return fieldParameter.GetCustomAttributes(typeof(T), false).Single() as T;
+	}
 
-#else
+	/// <summary>
+	/// 判断该次请求体Body是否是Json内容类型
+	/// </summary>
+	/// <param name="httpContext"></param>
+	/// <param name="charSet"></param>
+	/// <returns></returns>
+	public static bool ContentTypeIsJson(this HttpContext httpContext, out string charSet)
+	{
+		string strContentType = httpContext.Request.ContentType;
+		if (string.IsNullOrEmpty(strContentType))
+		{
+			charSet = null;
+			return false;
+		}
 
-using ComplexDataModelBinderProvider = Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinderProvider;
+		var contentType = new ContentType(strContentType);
+		charSet = contentType.CharSet;
+		return contentType.MediaType.ToLower() == "application/json";
+	}
 
-#endif
+	/// <summary>
+	/// 获取请求体Body字符串内容
+	/// </summary>
+	/// <param name="context"></param>
+	/// <param name="encoding"></param>
+	/// <returns></returns>
+	public static string GetBodyString(this HttpContext context, Encoding encoding)
+	{
+		context.Request.EnableBuffering(); //Ensure the HttpRequest.Body can be read multipletimes
+		int contentLen = 255;
+		if (context.Request.ContentLength != null)
+		{
+			contentLen = (int)context.Request.ContentLength;
+		}
 
-namespace Masuit.Tools.AspNetCore.ModelBinder;
+		var body = context.Request.Body;
+		string bodyText;
+		if (contentLen <= 0)
+		{
+			bodyText = "";
+		}
+		else
+		{
+			using var reader = new StreamReader(body, encoding, true, contentLen, true);
+			bodyText = reader.ReadToEndAsync().Result;
+		}
 
-public static class BodyOrDefaultModelBinderProviderSetup
-{
-    public static void InsertBodyOrDefaultBinding(this IList<IModelBinderProvider> providers)
-    {
-        var bodyProvider = providers.OfType<BodyModelBinderProvider>().Single();
-        var complexDataProvider = providers.OfType<ComplexDataModelBinderProvider>().Single();
-        providers.Insert(0, new BodyOrDefaultModelBinderProvider(bodyProvider, complexDataProvider));
-    }
+		body.Position = 0;
+		return bodyText;
+	}
+
+	/// <summary>
+	/// 判断类型是否是常见的简单类型
+	/// </summary>
+	/// <param name="type"></param>
+	/// <returns></returns>
+	public static bool IsSimpleType(this Type type)
+	{
+		//IsPrimitive 判断是否为基础类型。
+		//基元类型为 Boolean、 Byte、 SByte、 Int16、 UInt16、 Int32、 UInt32、 Int64、 UInt64、 IntPtr、 UIntPtr、 Char、 Double 和 Single。
+		var t = Nullable.GetUnderlyingType(type) ?? type;
+		return t.IsPrimitive || t.IsEnum || t == typeof(decimal) || t == typeof(string) || t == typeof(Guid) || t == typeof(TimeSpan) || t == typeof(Uri);
+	}
+
+	/// <summary>
+	/// 是否是常见类型的 数组形式 类型
+	/// </summary>
+	/// <param name="type"></param>
+	/// <returns></returns>
+	public static bool IsSimpleArrayType(this Type type)
+	{
+		return type.IsArray && Type.GetType(type.FullName!.Trim('[', ']')).IsSimpleType();
+	}
+
+	/// <summary>
+	/// 是否是常见类型的 泛型形式 类型
+	/// </summary>
+	/// <param name="type"></param>
+	/// <returns></returns>
+	public static bool IsSimpleListType(this Type type)
+	{
+		type = Nullable.GetUnderlyingType(type) ?? type;
+		return type.IsGenericType && type.GetGenericArguments().Length == 1 && type.GetGenericArguments().FirstOrDefault().IsSimpleType();
+	}
+
+	/// <summary>
+	/// 转换为对应类型
+	/// </summary>
+	/// <param name="this"></param>
+	/// <param name="toType"></param>
+	/// <returns></returns>
+	public static object ConvertObject(this object @this, Type toType)
+	{
+		object targetValue;
+		if (@this is string strValue)
+		{
+			strValue = strValue.Trim();
+			if ((strValue.StartsWith("[") && strValue.EndsWith("]")) || strValue.StartsWith("{") && strValue.EndsWith("}"))
+			{
+				targetValue = JsonConvert.DeserializeObject(strValue, toType);
+			}
+			else if ((strValue.StartsWith("\"[") && strValue.EndsWith("]\"")) || strValue.StartsWith("\"{") && strValue.EndsWith("}\""))
+			{
+				// json字符串 又被 json序列化 的情况
+				var objects = JsonConvert.DeserializeObject(strValue);
+				targetValue = JsonConvert.SerializeObject(objects).ConvertObject(toType);
+			}
+			else
+			{
+				var text = JsonConvert.SerializeObject(@this);
+				targetValue = JsonConvert.DeserializeObject(text, toType);
+			}
+		}
+		else if (@this is StringValues values)
+		{
+			var text = values.ToString();
+			if (toType.IsSimpleArrayType() || toType.IsSimpleListType())
+			{
+				text = JsonConvert.SerializeObject(values);
+				targetValue = JsonConvert.DeserializeObject(text, toType);
+			}
+			else
+			{
+				text = JsonConvert.SerializeObject(text);
+				targetValue = JsonConvert.DeserializeObject(text, toType);
+			}
+		}
+		else if (@this is JToken)
+		{
+			var text = JsonConvert.SerializeObject(@this);
+			targetValue = JsonConvert.DeserializeObject(text, toType);
+		}
+		else
+		{
+			var text = JsonConvert.SerializeObject(@this);
+			targetValue = JsonConvert.DeserializeObject(text, toType);
+		}
+
+		return targetValue;
+	}
+
+	/// <summary>
+	/// 尝试设置默认值
+	/// </summary>
+	/// <param name="bindingContext"></param>
+	public static bool TrySetDefaultValue(this ModelBindingContext bindingContext)
+	{
+		var attr = bindingContext.GetAttribute<FromBodyOrDefaultAttribute>();
+
+		if (attr.DefaultValue != null)
+		{
+			var targetValue = attr.DefaultValue.ChangeType(bindingContext.ModelType);
+			bindingContext.Result = ModelBindingResult.Success(targetValue);
+			return true;
+		}
+
+		return false;
+	}
+
+	/// <summary>
+	/// 对象类型转换
+	/// </summary>
+	/// <param name="this">当前值</param>
+	/// <param name="toType">指定类型的类型</param>
+	/// <returns>转换后的对象</returns>
+	public static object ChangeType(this object @this, Type toType)
+	{
+		var currType = Nullable.GetUnderlyingType(@this.GetType()) ?? @this.GetType();
+		toType = Nullable.GetUnderlyingType(toType) ?? toType;
+		if (@this == DBNull.Value)
+		{
+			if (!toType.IsValueType)
+			{
+				return null;
+			}
+
+			throw new Exception("不能将null值转换为" + toType.Name + "类型!");
+		}
+
+		if (currType == toType)
+		{
+			return @this;
+		}
+
+		if (toType.IsAssignableFrom(typeof(string)))
+		{
+			return @this.ToString();
+		}
+
+		if (toType.IsEnum)
+		{
+			return Enum.Parse(toType, @this.ToString(), true);
+		}
+
+		if (toType.IsAssignableFrom(typeof(Guid)))
+		{
+			return Guid.Parse(@this.ToString());
+		}
+
+		if (!toType.IsArray || !currType.IsArray)
+		{
+			return Convert.ChangeType(@this, toType);
+		}
+
+		var length = ((Array)@this).Length;
+		var targetType = Type.GetType(toType.FullName.Trim('[', ']'));
+		var targetArr = Array.CreateInstance(targetType, length);
+		for (int j = 0; j < length; j++)
+		{
+			var tmp = ((Array)@this).GetValue(j);
+			targetArr.SetValue(ChangeType(tmp, targetType), j);
+		}
+
+		return targetArr;
+	}
 }

+ 108 - 6
Masuit.Tools.AspNetCore/ModelBinder/FromBodyOrDefaultAttribute.cs

@@ -1,9 +1,111 @@
-using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.AspNetCore.Mvc;
 
-namespace Masuit.Tools.AspNetCore.ModelBinder;
-
-[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
-public class FromBodyOrDefaultAttribute : Attribute, IBindingSourceMetadata
+namespace Masuit.Tools.AspNetCore.ModelBinder
 {
-    public BindingSource BindingSource => BodyOrDefaultBindingSource.BodyOrDefault;
+	/// <summary>
+	/// 自动装配声明参数值
+	/// <list type="bullet">
+	/// <item>
+	/// 布尔
+	/// <description>bool</description>
+	/// </item>
+	/// <item>
+	/// 字符/字符串
+	/// <description>char/string</description>
+	/// </item>
+	/// <item>
+	/// 浮点型
+	/// <description>float/double/decimal</description>
+	/// </item>
+	/// <item>
+	/// 整型
+	/// <description>byte/sbyte/short/ushort/int/uint/long/ulong</description>
+	/// </item>
+	/// <item>
+	/// 枚举
+	/// <description>Enum</description>
+	/// </item>
+	/// <item>
+	/// 其他类型
+	/// <description>JObject/XDocument/Uri/Guid/TimeSpan</description>
+	/// </item>
+	/// </list>
+	/// </summary>
+	[AttributeUsage(AttributeTargets.Parameter)]
+	public class FromBodyOrDefaultAttribute : ModelBinderAttribute
+	{
+		public FromBodyOrDefaultAttribute() : this(BindType.None, null, null)
+		{
+		}
+
+		public FromBodyOrDefaultAttribute(IConvertible defaultValue) : this(BindType.None, null, defaultValue)
+		{
+		}
+
+		public FromBodyOrDefaultAttribute(BindType type, string fieldname) : this(type, fieldname, null)
+		{
+		}
+
+		public FromBodyOrDefaultAttribute(BindType type, string fieldname, IConvertible defaultValue) : base(typeof(BodyOrDefaultModelBinder))
+		{
+			Type = type;
+			FieldName = fieldname;
+			DefaultValue = defaultValue;
+		}
+
+		public string FieldName { get; set; }
+
+		public IConvertible DefaultValue { get; set; }
+
+		/// <summary>
+		/// 取值方式
+		/// </summary>
+		public BindType Type { get; set; }
+	}
+
+	/// <summary>
+	/// 枚举取值方式
+	/// </summary>
+	public enum BindType
+	{
+		/// <summary>
+		/// 无设定,自动取值(1.取请求数据中的某个值,2.请求数据当成一个对象取值)
+		/// </summary>
+		None,
+
+		/// <summary>
+		/// 从请求正文中获取值
+		/// </summary>
+		Body,
+
+		/// <summary>
+		/// 从查询字符串获取值
+		/// </summary>
+		Query,
+
+		/// <summary>
+		/// 从已发布的表单字段中获取值
+		/// </summary>
+		Form,
+
+		/// <summary>
+		/// 从 HTTP 标头中获取值
+		/// </summary>
+		Header,
+
+		/// <summary>
+		/// 从 Cookie 中取值
+		/// </summary>
+		Cookie,
+
+		/// <summary>
+		/// 从路由数据中获取值
+		/// </summary>
+		Route,
+
+		/// <summary>
+		/// 从依赖关系注入容器中获取类型的实例
+		/// </summary>
+		Services
+	}
 }

+ 1 - 1
Masuit.Tools.Core/Masuit.Tools.Core.csproj

@@ -6,7 +6,7 @@
 官网教程:https://tools.masuit.org
 github:https://github.com/ldqk/Masuit.Tools
         </Description>
-        <Version>2.6.3.1</Version>
+        <Version>2.6.4</Version>
         <Copyright>Copyright © 懒得勤快</Copyright>
         <PackageProjectUrl>https://github.com/ldqk/Masuit.Tools</PackageProjectUrl>
         <PackageTags>Masuit.Tools,工具库,Utility,Crypt,Extensions</PackageTags>

+ 10 - 9
NetCoreTest/Controllers/HomeController.cs

@@ -7,16 +7,17 @@ namespace NetCoreTest.Controllers;
 [ApiController]
 public class HomeController : Controller
 {
-    [HttpPost("test")]
-    [ProducesResponseType(typeof(MyClass), (int)HttpStatusCode.OK)]
-    public async Task<ActionResult> Test([FromBodyOrDefault] MyClass mc)
-    {
-        return Ok(mc);
-    }
+	[HttpPost("test")]
+	[ProducesResponseType(typeof(MyClass), (int)HttpStatusCode.OK)]
+	public async Task<ActionResult> Test(MyClass mc)
+	{
+		return Ok(mc);
+	}
 }
 
 public class MyClass
 {
-    public string MyProperty { get; set; }
-    public List<string> List { get; set; }
-}
+	public string MyProperty { get; set; }
+
+	public List<string> List { get; set; }
+}

+ 4 - 5
NetCoreTest/Program.cs

@@ -1,7 +1,7 @@
 using Masuit.Tools.AspNetCore.ModelBinder;
 
 var builder = WebApplication.CreateBuilder(args);
-builder.Services.AddControllers(options => options.ModelBinderProviders.InsertBodyOrDefaultBinding());
+builder.Services.AddControllers();
 builder.Services.AddEndpointsApiExplorer();
 builder.Services.AddSwaggerGen();
 
@@ -9,11 +9,10 @@ var app = builder.Build();
 
 if (app.Environment.IsDevelopment())
 {
-    app.UseSwagger();
-    app.UseSwaggerUI();
+	app.UseSwagger();
+	app.UseSwaggerUI();
 }
-
-app.UseAuthorization();
+app.UseBodyOrDefaultModelBinder();
 
 app.MapControllers();
 

+ 2 - 5
README.md

@@ -1082,13 +1082,10 @@ PM> Install-Package Masuit.Tools.AspNetCore
 Startup配置:
 
 ```csharp
-    services.AddMvc(options =>
-        {
-             options.ModelBinderProviders.InsertBodyOrDefaultBinding();
-        })
+app.UseBodyOrDefaultModelBinder();
 ```
 
-在action的参数模型前打上标记:`[FromBodyOrDefault]`即可,当然也可以省略,示例代码如下:
+在action的参数模型前打上标记:`[FromBodyOrDefault]`即可,示例代码如下:
 
 ```csharp
         [HttpGet("query"),HttpPost("query")]