.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));
            })

 

记录成长中的点点滴滴。。

 

posted @ 2019-08-09 17:49  Fate、狐狸  阅读(1601)  评论(0编辑  收藏  举报