0

我有以下型号

public class MyModel
{
   public string Name {get;set;}
   public int? Age {get;set;}
   public string City {get;set;}
   public decimal? Salary {get;set;}
   public JObject ExtraFields {get;set;}
}

我正在尝试实现自定义模型绑定器。如果提交的表单key与模型的属性匹配,则设置模型的属性值,否则将键和值添加到ExtraFields. 注意ExtraFields是 JObject

public class MyModelBinder: IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }


        MyModel model = new MyModel()
        {
            ExtraFields = new JObject()
        };

        var form = bindingContext.HttpContext.Request.Form;

        var properties = typeof(MyModel).GetProperties();
        foreach (var key in form.Keys)
        {
            var p = properties.FirstOrDefault(x => x.Name == key);
            var val = form[key];
            if (p != null)
            {
                p.SetValue(model, val); // throws exception
            }
            else
            {
                var v = StringValues.IsNullOrEmpty(val) ? null : val.ToString();
                model.ExtraFields.Add(key, v);
            }
        }

        bindingContext.Model = model;
        bindingContext.Result = ModelBindingResult.Success(model);

        return Task.CompletedTask;
    }
}

问题
我在设置模型的值时遇到异常

Object of type 'Microsoft.Extensions.Primitives.StringValues' cannot be converted to type 'System.String

如果可能,我想避免检查模型目标属性的类型,然后将值转换为目标类型。这应该隐式发生。

基本上,对于所有匹配的键调用 ASP.NET 的默认绑定器,并为所有剩余的键添加值ExtraFields

4

1 回答 1

1

“Microsoft.Extensions.Primitives.StringValues”类型的对象无法转换为“System.String”类型

valMicrosoft.Extensions.Primitives.StringValues类型,不能直接将其值分配给模型字段。

首先,可以通过 直接获取对应值的字符串形式val.ToString()

由于每个字段的类型不同,可以创建自定义的 Convert.ChangeType 方法,通过传递和来动态转换类型。val.ToString()p.PropertyType

更多细节,参考这个demo:

  public class MyModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
 
            MyModel model = new MyModel()
            {
                ExtraFields = new JObject()
            };

            var form = bindingContext.HttpContext.Request.Form;

            var properties = typeof(MyModel).GetProperties();
            foreach (var key in form.Keys)
            {
                var p = properties.FirstOrDefault(x => x.Name == key);
                var val = form[key];
                if (p != null)
                {
                   // call custom method ChangeType and pass two parameters.
                    p.SetValue(model, ChangeType(val.ToString(),p.PropertyType)); 

                }
                else
                {
                    var v = StringValues.IsNullOrEmpty(val) ? null : val.ToString();
                    model.ExtraFields.Add(key, v);
                }
            }

            bindingContext.Model = model;
            bindingContext.Result = ModelBindingResult.Success(model);

            return Task.CompletedTask;
        }

        // custom method
        public static object ChangeType(object value, Type conversion)
        {
            var t = conversion;

            if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                if (value == null)
                {
                    return null;
                }

                t = Nullable.GetUnderlyingType(t);
            }

            return Convert.ChangeType(value, t);
        }
    }

更新

@LP13 提供了一个更简单的解决方案:</p>

TypeConverter typeConverter = TypeDescriptor.GetConverter(p.PropertyType); 
object propValue = typeConverter.ConvertFromString(val); p.PropertyType));  
p.SetValue(model, propValue); 

这是我的测试结果:

在此处输入图像描述

于 2020-07-15T06:42:36.753 回答