强调弦模型粘结剂 [英] Underscore string model binder

查看:154
本文介绍了强调弦模型粘结剂的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是IM pression根据该绑定到一个复杂的模型时,所有的公共属性进行了处理,并尝试结合每个匹配。

我试图解决变量的命名问题,让一个模型

 类模型{
      公共字符串美孚{获取;设置;}
      公共字符串FooBar的{获取;设置;}
}

与查询字符串的作品很好像

 富=富&放大器; foo_bar这样的名称= foo_bar这样的名称

难道还有比一个自定义模型绑定一个更好的办法?在任何情况下,矿井不起作用。 FooBar的只是跳过。

 公共类StringModelBinder:DefaultModelBinder
    {
        公众覆盖对象BindModel(ControllerContext controllerContext,ModelBindingContext的BindingContext)
        {
            VAR模型= base.BindModel(controllerContext,BindingContext中);            如果(型号!= NULL)
                回归模型;            VAR MODELNAME = Regex.Replace(bindingContext.ModelName([A-Z])([A-Z]),$ 1_ $ 2)ToLowerInvariant()。            VAR值= bindingContext.ValueProvider.GetValue(MODELNAME);            返回值;
        }    }

与注册

  ModelBinders.Binders.Add(typeof运算(字符串),新StringModelBinder());


解决方案

  

我是IM pression是绑定到一个复杂的模型下的时候,所有的
  公共属性进行了处理,并尝试结合为比赛
  每个


没有,这是一个错误的IM pression。默认的模型绑定将尝试只能绑定您拥有的请求对应值的属性。在你的情况你不必为FooBar的属性,因此它不会被绑定相应的值。

其实这将是很好,如果我们可以这样写:

 公共类模型
{
    公共字符串美孚{搞定;组; }    [参数名称(foo_bar这样的名称)]
    公共字符串FooBar的{搞定;组; }
}

因此​​,让我们实现这一点。我们开始写一个基础属性:

  [AttributeUsageAttribute(AttributeTargets.Property)
公共抽象类PropertyBinderAttribute:属性,IModelBinder
{
    公共抽象对象BindModel(ControllerContext controllerContext,ModelBindingContext的BindingContext);
}

和一个自定义的模型绑定:

 公共类CustomModelBinder:DefaultModelBinder
{
    保护覆盖无效BindProperty(ControllerContext controllerContext,ModelBindingContext的BindingContext,的PropertyDescriptor PropertyDescriptor的)
    {
        VAR propertyBinderAttribute =的PropertyDescriptor
            .Attributes
            .OfType< PropertyBinderAttribute>()
            .FirstOrDefault();        如果(propertyBinderAttribute!= NULL)
        {
            VAR值= propertyBinderAttribute.BindModel(controllerContext,BindingContext中);
            propertyDescriptor.SetValue(bindingContext.Model,值);
        }
        其他
        {
            base.BindProperty(controllerContext,BindingContext中,PropertyDescriptor的);
        }
    }
}

正如你可以看到这个自定义模型分析模型的元数据,如果一个属性是装饰着PropertyBinderAttribute的一个实例,它会使用它。

我们会再更换与我们自定义的默认模型绑定在的Application_Start

  ModelBinders.Binders.DefaultBinder =新CustomModelBinder();

和所有剩下的,现在是落实我们用来装饰我们与模型属性ParameterNameAttribute粘结剂:

 公共类ParameterNameAttribute:PropertyBinderAttribute
{
    私人只读字符串参数名称;
    公共ParameterNameAttribute(字符串参数名称)
    {
        this.parameterName =参数名称;
    }    公众覆盖对象BindModel(ControllerContext controllerContext,ModelBindingContext的BindingContext)
    {
        VAR值= bindingContext.ValueProvider.GetValue(this.parameterName);
        如果(值!= NULL)
        {
            返回value.AttemptedValue;
        }
        返回null;
    }
}

I was under the impression that when binding to a complex model, all public properties were processed and a match binding attempted for each.

I'm trying to resolve a variable naming problem so that a model

class Model {
      public string Foo {get;set;}
      public string FooBar {get;set;}
}

works nicely with a query string like

?foo=foo&foo_bar=foo_bar

Is there a better way than with a custom model binder? In any case, mine doesn't work. FooBar is simply skipped.

public class StringModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var model = base.BindModel(controllerContext, bindingContext);

            if (model != null)
                return model;

            var modelName = Regex.Replace(bindingContext.ModelName, "([a-z])([A-Z])", "$1_$2").ToLowerInvariant();

            var value = bindingContext.ValueProvider.GetValue(modelName);

            return value;
        }

    }

Registered with

ModelBinders.Binders.Add(typeof(string), new StringModelBinder());

解决方案

I was under the impression that when binding to a complex model, all public properties were processed and a match binding attempted for each.

No, that's a wrong impression. The default model binder will attempt to bind only the properties for which you have a corresponding value in the Request. In your case you do not have a corresponding value for the FooBar property so it won't be bound.

Actually it would be nice if we could write:

public class Model
{
    public string Foo { get; set; }

    [ParameterName("foo_bar")]
    public string FooBar { get; set; }
}

So let's implement this. We start by writing a base attribute:

[AttributeUsageAttribute(AttributeTargets.Property)]
public abstract class PropertyBinderAttribute : Attribute, IModelBinder
{
    public abstract object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
}

and a custom model binder:

public class CustomModelBinder : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
    {
        var propertyBinderAttribute = propertyDescriptor
            .Attributes
            .OfType<PropertyBinderAttribute>()
            .FirstOrDefault();

        if (propertyBinderAttribute != null)
        {
            var value = propertyBinderAttribute.BindModel(controllerContext, bindingContext);
            propertyDescriptor.SetValue(bindingContext.Model, value);
        }
        else
        {
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
    }
}

As you can see this custom model analyzes the metadata of the model and if a property is decorated with an instance of the PropertyBinderAttribute it will use it.

We will then replace the default model binder with our custom one in Application_Start:

ModelBinders.Binders.DefaultBinder = new CustomModelBinder();

and all that's left now is to implement the ParameterNameAttribute binder that we used to decorate our model property with:

public class ParameterNameAttribute : PropertyBinderAttribute
{
    private readonly string parameterName;
    public ParameterNameAttribute(string parameterName)
    {
        this.parameterName = parameterName;
    }

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(this.parameterName);
        if (value != null)
        {
            return value.AttemptedValue;
        }
        return null;
    }
}

这篇关于强调弦模型粘结剂的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆