6

何年もの間、私は ASP.NET Web フォーム開発を行っていましたが、次のようなことができる独自のライブラリに甘やかされていました。

    UpdateToObject(ControlsCollection, obj)
    UpdateFromObject(ControlsCollection, obj)

概念的には、コードは MVC Model Binder が行うことと非常によく似た処理を行います。つまり、フォームのポストされた値を入力として指定すると、カスタム オブジェクトに入力されます。基本的に、開発者は次のようなモンキー コードを実行する必要がなくなりました。

employee.Name = txtName.Text;
employee.DOB = DateTime.Parse(txtDOB.Text);

等々..

現在、このプロプライエタリ ライブラリは、私が関与している新しいプロジェクトでは使用できません。これは Web フォーム プロジェクトです。System.Web.Mvc.DefaultModelBinderそこで、Web フォームのコンテキストで使用する方法があるかどうか疑問に思っています。目標は、理想的には検証アノテーションを考慮して、ドメイン オブジェクトとその逆のコントロールをシンプルかつ簡単に作成することです。それが不可能な場合は、誰かがこのニーズに対処するためのオープン ソース ソリューションを教えてくれませんか。私は本当にそのようなコードを書き直す気がしません。

前もって感謝します。

4

3 に答える 3

1

Sherlock さん、MVC から ModelBinder を使用しようとすると、ControllerContext に依存しているため、いくつかの問題に遭遇するでしょう。

私は以前に同様の質問に答えましたChangeType, Convert - Converting from one type to anotherが、それは本当にあなたが探しているものです。

私のブログChangeTypeのこのブログ投稿をチェックしてください – C# での変数の型の変更

ChangeType<T>基本的に、厳密に型指定された方法で探しているパラメーターの値を返すか、パラメーターが存在しない場合は既定値を返す単一のメソッドが呼び出されます。

カスタム クラス (主に DTO 型クラス) に関しては、リフレクションの使用を気にしない場合は、ほとんどのカスタム クラスも処理できるソリューションがあります。最後の方で述べた DtoBinder クラスはうまく機能します。

基本的に、最後の 3 つのコード リストには、典型的な Web アプリケーション シナリオでのほとんどすべてのニーズに対応するために必要なすべてのコードが含まれています。さらに、拡張可能であるため、独自のバインダーを実装する必要がある場合は、非常に簡単に実装でき、アプリのどこからでもバインダーを RequestBinder に登録できます。

したがって、頻繁に使用される特定の DTO オブジェクトに対してリフレクションを使用したくない場合は、その型のバインダーを実装して登録すると、その時点からカスタム バインダーが使用されます。多くの点で、概念は MVC ModelBinder に似ています。

編集済み -

以下は、必要なことを正確に行うために過去に使用した一連のクラスを含む .cs ファイルの 1 つです。最初の MsPropertyAssignerProvider は、ページ内から操作するものです。

コントロールを繰り返し処理し、コントロールの型名を渡して GetPropertyAssigner メソッドを呼び出します。このメソッドは、オブジェクト インスタンスとコントロール インスタンスを渡すことができる SetPropertyValue という 1 つのメソッドを持つ ObjectPropertyAssigner のインスタンスを返します。

  internal class MsPropertyAssignerProvider
  {
    private Hashtable propertyAssigners;

    internal MsPropertyAssignerProvider()
    {
      propertyAssigners = new Hashtable();
      RegisterPropertyAssigner(typeof(TextBox).ToString(), new TextBoxValueExtractor());
      RegisterPropertyAssigner(typeof(DropDownList).ToString(), new DropDownListValueExtractor());
      RegisterPropertyAssigner(typeof(Label).ToString(), new LabelValueExtractor());
      RegisterPropertyAssigner(typeof(CheckBox).ToString(), new CheckBoxValueExtractor());
    }

    internal void RegisterPropertyAssigner(string identifier, IMsObjectPropertyAssigner assigner)
    {
      if (propertyAssigners.ContainsKey(identifier))
        throw new DuplicatePropertyAssignerRegistrationException(identifier);
      propertyAssigners.Add(identifier, assigner);
    } 

    internal IMsObjectPropertyAssigner GetPropertyAssigner(string identifier)
    {
      return (propertyAssigners.ContainsKey(identifier)) ? (IMsObjectPropertyAssigner)propertyAssigners[identifier] : null;
    }
  }

付随するクラスは以下のとおりです。

  public interface IMsObjectPropertyAssigner
  {
    void SetPropertyValue(object obj, System.Web.UI.Control control); 
  }

  internal abstract class BaseValueExtractor : IMsObjectPropertyAssigner
  {
    protected MsReflectionHelper reflectionHelper = new MsReflectionHelper();
    protected string FixStringForNumber(string stringValue)
    {
      if (stringValue.Length == 0)
        return "0";
      else
        return stringValue;
    }
    public abstract void SetPropertyValue(object obj, System.Web.UI.Control control);
  }

  internal class TextBoxValueExtractor : BaseValueExtractor
  {
    public override void SetPropertyValue(object obj, System.Web.UI.Control control)
    {
      TextBox textBox = (TextBox)control;
      PropertyInfo propInfo = reflectionHelper.GetPropertyInfo(obj, control.ID);
      Type propType = propInfo.PropertyType;
      if (propType == typeof(System.String))
        reflectionHelper.SetPropertyValue(obj, control.ID, textBox.Text);
      else if (propType == typeof(System.Int16))
        reflectionHelper.SetPropertyValue(obj, control.ID, Int16.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency));
      else if (propType == typeof(System.Int32))
        reflectionHelper.SetPropertyValue(obj, control.ID, Int32.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency));
      else if (propType == typeof(System.Int64))
        reflectionHelper.SetPropertyValue(obj, control.ID, Int64.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency));
      else if (propType == typeof(System.Double))
        reflectionHelper.SetPropertyValue(obj, control.ID, Double.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency));
      else if (propType == typeof(System.Single))
        reflectionHelper.SetPropertyValue(obj, control.ID, Single.Parse(FixStringForNumber(textBox.Text), System.Globalization.NumberStyles.Currency));
      else
        reflectionHelper.SetPropertyValue(obj, control.ID, textBox.Text);
    }
  }

  internal class DropDownListValueExtractor : BaseValueExtractor
  {
    public override void SetPropertyValue(object obj, System.Web.UI.Control control)
    {
      DropDownList dropDownList = (DropDownList)control;
      reflectionHelper.SetPropertyValue(obj, control.ID, dropDownList.SelectedValue);
    }
  }

  internal class LabelValueExtractor : BaseValueExtractor
  {
    public override void SetPropertyValue(object obj, Control control)
    {
      Label label = (Label)control;
      reflectionHelper.SetPropertyValue(obj, control.ID, label.Text);
    }
  }

  internal class CheckBoxValueExtractor : BaseValueExtractor
  {
    public override void SetPropertyValue(object obj, Control control)
    {
      CheckBox checkbox = (CheckBox)control;
      reflectionHelper.SetPropertyValue(obj, control.ID, checkbox.Checked);
    }
  }

申し訳ありませんが、私が何をしても、エディターはコード リストを完全に台無しにします。しかし、これが役立つことを願っています。

于 2010-11-08T22:55:59.007 に答える
1

このようなことに AutoMapper を使用することはできませんか? マップをセットアップするだけで、新しいオブジェクトが作成され、値がコピーされます。

于 2011-09-06T08:28:39.130 に答える