4

複雑なモデルにバインドするときに、すべてのパブリックプロパティが処理され、それぞれに対して一致バインドが試行されたという印象を受けました。

変数の命名の問題を解決して、モデルを作成しようとしています

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

次のようなクエリ文字列でうまく機能します

?foo=foo&foo_bar=foo_bar

カスタムモデルバインダーを使用するよりも良い方法はありますか?いずれにせよ、私のものは機能しません。FooBarは単にスキップされます。

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

    }

に登録

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

1 に答える 1

15

複雑なモデルにバインドするときに、すべてのパブリックプロパティが処理され、それぞれに対して一致バインドが試行されたという印象を受けました。

いいえ、それは間違った印象です。デフォルトのモデルバインダーは、リクエストに対応する値があるプロパティのみをバインドしようとします。あなたの場合、FooBarプロパティに対応する値がないため、バインドされません。

実際、次のように書くことができれば素晴らしいと思います。

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

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

それでは、これを実装しましょう。まず、基本属性を記述します。

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

およびカスタムモデルバインダー:

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

ご覧のとおり、このカスタムモデルはモデルのメタデータを分析し、プロパティがPropertyBinderAttributeのインスタンスで装飾されている場合は、それを使用します。

次に、デフォルトのモデルバインダーをカスタムバインダーに置き換えますApplication_Start

ModelBinders.Binders.DefaultBinder = new CustomModelBinder();

あとは、モデルプロパティを次のように装飾するために使用したParameterNameAttributeバインダーを実装するだけです。

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;
    }
}
于 2013-01-14T13:48:53.277 に答える