3

ユーザーに表示される値を修正する ASP.NET MVC のモデルバインダーを作成したいと考えています。たぶん、値の最初の文字を大文字にしたり、文字列をトリムしたりします。

この動作をモデルバインダー内にカプセル化したいと思います。

たとえば、これはTrimModelBinder文字列をトリミングするための a です。(ここから取得)

public class TrimModelBinder : DefaultModelBinder
  {
    protected override void SetProperty(ControllerContext controllerContext, 
      ModelBindingContext bindingContext, 
      System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
    {
      if (propertyDescriptor.PropertyType == typeof(string))
      {
        var stringValue = (string)value;
        if (!string.IsNullOrEmpty(stringValue))
          stringValue = stringValue.Trim();

        value = stringValue;
      }

      base.SetProperty(controllerContext, bindingContext, 
                          propertyDescriptor, value);
    }
  }

これにより値がモデルに設定されますが、ページが再表示されると元の値が保持されます (ModelState にあるため)。

トリミングされた値をユーザーに再表示したいだけです。

などOnPropertyValidated、オーバーライドするメソッドはたくさんあります。OnPropertyValidating

おそらく機能させることができますが、間違ったメソッドをオーバーライドした場合に意図しない副作用が発生することは望ましくありません。

ビューを生成しているときに、Trim() などのロジックを実行したくありません。このロジックをモデルバインダー内に完全にカプセル化したいと考えています。

4

2 に答える 2

2

このクラスを置き換えます。

  public class TrimModelBinder : DefaultModelBinder
  {
    protected override void SetProperty(ControllerContext controllerContext,
      ModelBindingContext bindingContext,
      System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
    {
      if (propertyDescriptor.PropertyType == typeof(string))
      {
        var stringValue = (string)value;
        if (!string.IsNullOrEmpty(stringValue))
          stringValue = stringValue.Trim();

        value = stringValue;
        bindingContext.ModelState[propertyDescriptor.Name].Value = 
          new ValueProviderResult(stringValue,
            stringValue,
            bindingContext.ModelState[propertyDescriptor.Name].Value.Culture);
      }

      base.SetProperty(controllerContext, bindingContext,
                propertyDescriptor, value);
    }
  }

編集:サイモンによって変更

(オリジナルには null 参照例外があり、階層モデルをサポートするための変更が追加されました)

protected override void SetProperty(ControllerContext controllerContext,
    ModelBindingContext bindingContext,
    System.ComponentModel.PropertyDescriptor propertyDescriptor,
    object value)
    {
        string modelStateName = string.IsNullOrEmpty(bindingContext.ModelName) ? propertyDescriptor.Name : 
            bindingContext.ModelName + "." + propertyDescriptor.Name;

        // only process strings
        if (propertyDescriptor.PropertyType == typeof(string))
        {
            if (bindingContext.ModelState[modelStateName] != null)
            {
                // modelstate already exists so overwrite it with our trimmed value
                var stringValue = (string)value;
                if (!string.IsNullOrEmpty(stringValue))
                    stringValue = stringValue.Trim();

                value = stringValue;
                bindingContext.ModelState[modelStateName].Value =
                  new ValueProviderResult(stringValue,
                    stringValue,
                    bindingContext.ModelState[modelStateName].Value.Culture);
            }
            else
            {
                // trim and pass to default model binder
                base.SetProperty(controllerContext, bindingContext, propertyDescriptor, (value == null) ? null : (value as string).Trim());
            }
        }
        else
        {
            base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
        }
    }
于 2010-01-24T11:43:03.910 に答える
0

モデルバインダー内から、にアクセスできますModelBindingContext。その上でアクセスModelStateでき、そのディクショナリの値をトリミングされた値に変更できるはずです。

多分次のようなものです:

string trimmedValue = GetTheTrimmedValueSomehow();
modelBindingContext.ModelState[modelBindingContext.ModelName] = trimmedValue;
于 2010-01-18T03:16:48.500 に答える