强调弦模型粘结剂 [英] Underscore string model binder
问题描述
我是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屋!