.NET Core 使用ModelBinder去掉所有參數的空格


一.前言

  通過各種姿勢搜索都沒搜到這方面的,唯一找到一個比較符合的,但是只適合簡單類型,而且代碼還沒貼全,心累。。

然后查看官網和源碼之后,發現繼承並實現 IModelBinder和IModelBinderProvider 即可。

我這里是WebApi,所以要區分綁定屬性[FromBody]、[FromForm]等。不同的綁定方法要實現不同的IModelBinder。

二:正文

  api主要設計到的就是[FromBody]和[FromQuery],我這里也只實現了這兩種,其余的方式沒測試過。

 

public class StringTrimModelBinderProvider : IModelBinderProvider
    {
        private readonly IList<IInputFormatter> _formatters;

        public StringTrimModelBinderProvider(IList<IInputFormatter> formatters)
        {
            _formatters = formatters;
        }

        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
                throw new ArgumentNullException(nameof(context));

            if (!context.Metadata.IsComplexType && context.Metadata.ModelType == typeof(string))
            {
                //簡單類型
                var loggerFactory = (ILoggerFactory)context.Services.GetService(typeof(ILoggerFactory));
                return new SimpleStringTrimModelBinder(context.Metadata.ModelType);
            }
            else if (context.BindingInfo.BindingSource != null &&
                context.BindingInfo.BindingSource.CanAcceptDataFrom(BindingSource.Body))
            {
                //通過[FromBody]綁定的
                return new BodyStringTrimModelBinder(_formatters, context.Services.GetRequiredService<IHttpRequestStreamReaderFactory>());
            }
            //else
            //if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
            //{
            //    //復雜類型
            //    var propertyBinders = context.Metadata.Properties
            //        .ToDictionary(modelProperty => modelProperty, modelProperty => context.CreateBinder(modelProperty));
            //    var loggerFactory = (ILoggerFactory)context.Services.GetService(typeof(ILoggerFactory));
            //    return new AComplexTypeModelBinder(propertyBinders);
            //}

            return null;
        }
    }

 

 

下面的是實現IModelBinder

 

public class SimpleStringTrimModelBinder : IModelBinder
    {
        private readonly Type _type;

        public SimpleStringTrimModelBinder(Type type)
        {
            _type = type;
        }

        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
            var valueProvider = bindingContext.ValueProvider;
            var modelName = bindingContext.ModelName;
            var valueProviderResult = valueProvider.GetValue(modelName);

            if (valueProviderResult == ValueProviderResult.None)
            {
                return Task.CompletedTask;
            }
            string value = valueProviderResult.FirstValue.Trim();
            //bindingContext.ModelState.SetModelValue(modelName, new ValueProviderResult(value));
            //替換原有ValueProvider
            bindingContext.ValueProvider = new CompositeValueProvider
                {
                    new ElementalValueProvider(modelName, value, valueProviderResult.Culture),
                    bindingContext.ValueProvider
                };
            //調用默認系統綁定
            SimpleTypeModelBinder simpleTypeModelBinder = new SimpleTypeModelBinder(_type, (ILoggerFactory)bindingContext.HttpContext.RequestServices.GetService(typeof(ILoggerFactory)));
            simpleTypeModelBinder.BindModelAsync(bindingContext);
            //bindingContext.Result = ModelBindingResult.Success(value);
            return Task.CompletedTask;
        }
    }

 

public class BodyStringTrimModelBinder : IModelBinder
    {
        private readonly BodyModelBinder bodyModelBinder;

        public BodyStringTrimModelBinder(IList<IInputFormatter> formatters, IHttpRequestStreamReaderFactory readerFactory)
        {
            bodyModelBinder = new BodyModelBinder(formatters,readerFactory);
        }

        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
            //調用原始body綁定數據
            bodyModelBinder.BindModelAsync(bindingContext);
            //判斷是否設置了值
            if (!bindingContext.Result.IsModelSet)
            {
                return Task.CompletedTask;
            }
            //獲取綁定對象
            var model = bindingContext.Result.Model;

            /*通過反射修改值,
            也可以實現 IInputFormatter接口里面的ReadAsync方法,自己從Request.Body里面獲取數據進行處理,但是那樣考慮的比較多也比較復雜,原諒我能力有限。。*/
            var stringPropertyInfo = model.GetType().GetProperties().Where(c=>c.PropertyType == typeof(string));
            foreach (PropertyInfo property in stringPropertyInfo)
            {
                string value = property.GetValue(model)?.ToString()?.Trim();
                property.SetValue(model, value);
            }
            //bindingContext.Result = ModelBindingResult.Success(value);
            return Task.CompletedTask;
        }
    }

最后,需要將我們自定義的在Startup注冊進去,

services.AddMvc(options =>
            {
                //需要插入到第一條,內置默認是匹配到合適的Provider就不會在向下繼續綁定;如果添加到末尾,即不會調用到我們實現的
                options.ModelBinderProviders.Insert(0,new StringTrimModelBinderProvider(options.InputFormatters));
            })

 

記錄成長中的點點滴滴。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM