Связыватель модели в веб-формах ASP.NET - PullRequest
6 голосов
/ 10 сентября 2010

В течение нескольких лет, когда я занимался разработкой веб-форм ASP.NET, я был избалован проприетарной библиотекой, которая позволяла мне делать что-то вроде:

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

Концептуально код делал нечто очень похожее на то, что MVC ModelBinder делает, т. Е. Публикуемые значения данной формы в качестве входных данных заполняют пользовательский объект.По сути, это освободило разработчика от выполнения кода обезьяны, такого как

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

и т. Д.

Теперь эта проприетарная библиотека недоступна в новом проекте, с которым я связан, и онапроект веб-форм.Поэтому мне интересно, есть ли способ использования System.Web.Mvc.DefaultModelBinder в контексте веб-форм.Цель состоит в том, чтобы добиться простого и легкого заполнения элементов управления из объектов домена и обратно, в идеале с учетом аннотаций проверки.Если это невозможно, может кто-нибудь указать мне на решение с открытым исходным кодом, чтобы удовлетворить эту потребность.Мне действительно не хочется переписывать такой код.

Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 06 сентября 2011

Не могли бы вы использовать AutoMapper для чего-то вроде этого?Просто настройте свои карты, и он создаст новые объекты и скопирует в них значения.

1 голос
/ 09 ноября 2010

Шерлок, вы столкнетесь с некоторыми проблемами, пытаясь использовать ModelBinder от MVC, поскольку они используют ControllerContext.

Я ответил на аналогичный вопрос ранее ChangeType, Convert - Преобразование из одного типа в другой , но это действительно то, что вы ищете.

Посмотри этот пост в моем блоге. ChangeType - изменение типа переменной в C #

По сути, вы получаете единственный метод с именем ChangeType<T>, который возвращает значение параметра, который вы ищете, строго типизированным способом, или значение по умолчанию, если параметр не существует.

Теперь, что касается пользовательских классов (в основном классов типов DTO), если вы не возражаете против использования отражения, у меня есть решение, которое также будет обрабатывать большинство пользовательских классов. Класс DtoBinder, упомянутый в конце завещания, будет хорошо работать.

По сути, последние 3 листинга кода содержат весь код, который вам понадобится для удовлетворения почти всех ваших потребностей в типичном сценарии веб-приложения. Кроме того, он расширяемый, поэтому, если вам нужно реализовать свой собственный механизм связывания, вы можете сделать это очень просто и зарегистрировать свой механизм связывания в 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;
    }
  }

Сопутствующий класс указан ниже

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

Извините, независимо от того, что я делаю, редактор полностью испортил листинг кода. Но я надеюсь, что это поможет.

0 голосов
/ 29 мая 2013

Это довольно старый вопрос, но я столкнулся с ним, пытаясь выяснить, как на самом деле работает механизм связывания моделей по умолчанию.

У меня есть проект на CodeProject, который на самом деле делает то, что вы хотите (ed), посмотрите .

Ура!

...