asp.net - ASP.NET 网络表单中的模型绑定(bind)器

标签 asp.net webforms modelbinders defaultmodelbinder

多年来,我从事 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 表单的上下文中。目标是实现从域对象和返回的简单和容易的控件填充,理想情况下考虑到验证注释。
如果这是不可能的,有人可以向我指出一个开源解决方案来解决这个需求。我真的不想重写这样的代码。

提前致谢。

最佳答案

Sherlock,您在尝试使用 MVC 中的 ModelBinder 时会遇到一些问题,因为它们依赖于 ControllerContext。

我之前回答了一个类似的问题 ChangeType, Convert - Converting from one type to another但这确实是您要寻找的。

在我的博客上查看这篇博文
ChangeType – Changing the type of a variable in C#

本质上,您会得到一个名为 ChangeType<T> 的方法。它以强类型方式返回您要查找的参数的值,如果参数不存在,则返回默认值。

现在关于自定义类(主要是 DTO 类型类),如果您不介意使用反射,那么我有一个解决方案也可以处理大多数自定义类。在遗嘱末尾提到的 DtoBinder 类很好地工作。

本质上,最后 3 个代码 list 包含您需要的所有代码,以便处理典型 Web 应用程序场景中的几乎所有需求。此外,它是可扩展的,因此如果您需要实现自己的活页夹,您可以非常简单地做到这一点,并从应用程序的任何位置向 RequestBinder 注册活页夹。

因此,如果您不想对某些经常使用的 DTO 对象使用反射,您可以为该类型实现一个活页夹并注册它,然后它将使用您的自定义活页夹。在许多方面,它在概念上类似于 MVC ModelBinder。

已编辑 -

下面是一个 .cs 文件,其中包含我过去用来完全满足您需要的一堆类。第一个 MsPropertyAssignerProvider 是您将在页面中使用的那个。

您将遍历您的控件并调用 GetPropertyAssigner 方法,将控件的类型名称传递给它。此方法返回 ObjectPropertyAssigner 的一个实例,该实例具有一个名为 SetPropertyValue 的方法,您可以将对象实例和控件实例传递给该方法。

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

下面列出了随附的类(class)
  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);
    }
  }

抱歉,无论我做什么,编辑器都会完全弄乱代码列表。但我希望这会有所帮助。

关于asp.net - ASP.NET 网络表单中的模型绑定(bind)器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3680435/

相关文章:

回发或初始请求期间的 ASP.NET 事件顺序

.net - 如何本地化 ASP.NET MVC 应用程序中的 Controller 名称和操作?

ASP.NET 4 WebForms 路由 - 获取处理请求的物理页面

c# - 我可以调试带有源断点的 nuget 包而不是单步执行吗?

asp.net-mvc - 如何使用 Moq 对自定义 ModelBinder 进行单元测试?

c# - 在开发 facebook 图网站时如何使用本地主机?

c# - 为什么我会收到此 404 错误?

asp.net - 如何在 Global.asax 中正确捕获 Web 应用程序错误

ASP.NET MVC 模型绑定(bind)器无法使用字典

asp.net - 在没有 Html 帮助程序的情况下从表单传递数据