Динамическое создание форм в asp.net c # - PullRequest
7 голосов
/ 12 августа 2011

Итак, мне нужен некоторый входной рефакторинг приложения asp.net (c #), которое в основном является структурой для создания динамических форм (любых форм).С точки зрения высокого уровня, есть таблица, которая имеет формы, а затем есть таблица, которая имеет все поля формы, где между двумя есть один ко многим.Существует таблица проверки, в которой каждое поле может иметь несколько типов проверки, и это одна ко многим из таблицы полей формы в таблицу проверки.

Таким образом, проблема заключается в том, что это приложение было продано какнастраиваемое решение для всех клиентов.Итак, идея в том, какую форму они хотят, мы можем построить ее, используя конфигурации БД.Дело в том, что это не всегда возможно, потому что есть сложные отношения между полями и сложные отношения между самими формами.Кроме того, существует только одна кодовая база, и это для нескольких клиентов, каждый из которых размещает ее самостоятельно.Для каждого из клиентов существует очень специфическая логика, и они ВСЕ в одной кодовой базе, без реального разделения.Иногда было слишком сложно сделать его универсальным, поэтому бывают случаи, когда он имеет жестко закодированную логику (например, если formID = XXX, то выполните _ ).Вы также можете иметь вложенные формы, как, например, один набор полей в каждой форме.

Так, обычно, когда один клиент запрашивает изменение, мы вносим изменение и разворачиваем его на этом клиенте - но затемдругой клиент запрашивает другое изменение, и мы вносим это изменение и разворачиваем его для ТО-клиента, но изменение от более раннего клиента нарушает его, и его головная боль пытается отладить, потому что ВСЕ динамично.Мы не можем откатить предыдущее изменение, потому что тогда другой клиент будет испорчен.

Это не сделано в реальной трехуровневой архитектуре - это веб-сайт со ссылками на класс БД ибиблиотека классов.Есть бизнес-логика на самом веб-сайте, в библиотеке классов и в хранимых процессах базы данных (проверка выполняется в хранимых процессах).

Я был назначен ответственным за реорганизацию всего этогои вот мои мысли / вопросы:

  1. Я думаю, что это вообще плохая модель, потому что одна из вещей, которую я слышал от одного из разработчиков, заключается в том, что каждый раз, когда любой клиент делаетизменения, мы должны развернуть на всех - но это нереально, если мы скажем, 20 клиентов - потребуется ВСЕ регрессионное тестирование, так как мы не знаем, влияние ...

  2. Всего около 100 форм, и в них есть некоторое сходство (не очень).Но я думаю, что идея о том, что динамический движок может решать ВСЕ запросы форм, также не была реалистичной.Клиенты приходят с самыми странными запросами.Например, у них есть этот движок, выполняющий обычную форму ввода данных И форму поиска.

  3. Существует много сохраняющих состояние между страницами, и все это делается с помощью переменных сеанса, которыевсе в порядке, за исключением того, что он на самом деле не отслеживается, и поэтому сеансы одного и того же пользователя продолжают перезаписываться, и я думаю, что от сеансов следует избавиться.

  4. Должен ли я действительно просто переписатьВсе это?Этому приложению около 3 лет, и было проведено множество тестов, и все сделано, и внедрена серьезная бизнес-логика, поэтому я не хочу избавляться от всего этого (совет Джоэла).Но это действительно беспорядок кода sphagetti, и все занимает вечность, и все постоянно ломается из-за незначительных изменений.

Я читал Мартина Фаулерса "Рефакторинг"и Майкл Фезерс «эффективно работают с унаследованным кодом» - и они хороши, но я чувствую, что они были написаны для приложения, которое было «немного» лучше спроектировано, где это все еще трехуровневая архитектура, и есть «некоторое» сходствологики ..

Мысли / вводить кого-нибудь?

Ох и "Помогите!"

Ответы [ 4 ]

4 голосов
/ 15 августа 2011

Мой текущий проект звучит так же, как и тот продукт, который вы описываете.К счастью, я усвоил большинство своих самых сложных уроков по предыдущему продукту, и поэтому я смог начать свой текущий проект с чистого листа.Вам, вероятно, следует прочитать мой ответ на этот вопрос , который описывает мой опыт и уроки, которые я выучил.

Главное, на чем стоит сосредоточиться, это идея, что вы создаете продукт .Если вы не можете найти способ реализовать определенную функцию с использованием текущего набора функций продукта, вам нужно потратить дополнительное время на размышления о том, как можно превратить эту настраиваемую одноразовую функцию в настраиваемую функцию, которая может принести пользу всем (иликак минимум много) ваших клиентов.

Итак:

  1. Если вы имеете в виду модель возможности создания полностью настраиваемой формы, которая делает код, специфичный для клиента, почти ненужным,эта модель совершенно верна, и у меня есть исправный рабочий продукт с реальными, платящими клиентами, которые могут это доказать.Регрессионное тестирование выполняется для определенных функций и комбинаций конфигурации, а не для конкретной клиентской реализации.Ключевыми элементами, которые делают это возможным, являются:
    1. Административный интерфейс, который эффективен при запрете проблемных комбинаций параметров конфигурации.
    2. Механизм правил, который позволяет определенным действиям в системе вызывать настраиваемые триггеры ивызвать другие действия.
    3. Интеграционная среда, которая позволяет извлекать данные из различных источников и отправлять их в различные источники настраиваемым способом.
    4. Возможность вставлять пользовательский кодв качестве плагина, когда это абсолютно необходимо.
  2. Да, клиенты приходят со странными запросами.Обычно стоит предложить альтернативные решения, которые все же решат проблему клиента, но при этом позволяют вашему продукту быть надежным и настраиваемым для других клиентов.Иногда вам просто нужно оттолкнуться.В других случаях вам придется делать то, что они говорят, но использовать мудрые архитектурные приемы, чтобы минимизировать влияние, которое это может оказать на другой клиентский код.
  3. Минимизировать использование сеанса для отслеживания состояния.На каждой странице должно быть достаточно информации для отслеживания текущего состояния страницы.Информация, которая должна сохраняться, даже если пользователь нажимает «Назад» и начинает делать что-то еще, должна храниться в базе данных.Тем не менее, я считаю полезным хранить в сеансе своего рода «крошку», отслеживать, как пользователи попадают в определенное место и куда их возвращать, когда они заканчивают работу.Но идентификатор узла, на котором они в данный момент находятся, необходимо сохранять постранично и посылать обратно с каждым запросом, поэтому странных вещей не происходит, когда пользователь просматривает разные страницы на разных вкладках.
  4. Использовать инкрементный рефакторинг.Вы можете закончить переписывать все дважды, когда закончите, или вы никогда не сможете «закончить» рефакторинг.Но в то же время все будет работать, и у вас будут появляться новые функции время от времени.Как правило, переписывание всего этого займет у вас в несколько раз больше времени, чем вы думаете, поэтому не пытайтесь взять все это за один укус.
4 голосов
/ 12 августа 2011

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

Существует множество вещей, которые вы могли / не могли сделать, и вы правильно подумаете, прежде чем выбросить 3 годатестирование / разработка.

Мой вклад, который вы должны рассмотреть, заключается в реализации архитектуры подключаемых модулей поверх того, что у вас есть.Любой пользовательский код для формы входит в плагин и имя этого плагина сохраняется вместе с формой.Когда вы генерируете форму, вызывается правильный плагин для расширения базовой функциональности.Таким образом, вы можете переместить весь пользовательский код из существующей библиотеки.Это также должно означать меньшее количество критических изменений, каждый плагин влияет только на форму, к которой он присоединен.

С этого момента будет легко провести рефакторинг ядра, поскольку он является общим функционалом для всех клиентов и форм.

0 голосов
/ 01 сентября 2011

Это распространенный, но (ИМО) несколько наивный подход к проектированию.«Вместо того, чтобы решать проблему клиента, давайте создадим инструмент, который позволит им решать свои собственные проблемы!».Но реальность такова, что, как правило, клиенты хотят, чтобы ВЫ решали их АКТУАЛЬНЫЕ проблемы.Поэтому создавайте вещи, которые решают их проблемы.Если вы можете сконструировать его так, чтобы вы могли повторно использовать некоторые детали для разных клиентов, хорошо.Но это, как правило, то, что фреймворки уже сделали для вас - разработайте общие функции, которые нужны приложениям, и сделайте их доступными в аккуратных пакетах.

0 голосов
/ 15 августа 2011

Поскольку ваше приложение, похоже, превратилось в большой шарик грязи, полное (или почти полное переписывание) может иметь смысл.

Вам также следует учитывать новые технологии, такие как ориентированные на документы базы данных (couchDB), MongoDB)

Большинство определений форм, вероятно, вполне может вписаться в ориентированные на документы базы данных.Например:

Чтобы определить форму клиента, вы можете использовать документ, который выглядит следующим образом:

{Type:"FormDefinition",
 EntityType: "Customer",
 Fields: [
   {FieldName:"CustomerName", 
    FieldType:"String", 
    Validations:[
      {ValidationType:"Required"},
      {ValidationType:"StringLength", Minimum:15, Maximum:50},
    ]},
    ...
   {FieldName:"CustomerType", 
    FieldType:"Dropdown", 
    PossibleValues: ["Standard", "Valued", "Gold"],
    DefaultValue: ["Standard"]
    Validations:[
      {ValidationType:"Required"},
      {
        ValidationType:"Custom", 
        ValidationClass:"MySystem.CustomerName.CustomValidations.CustomerStatus"
      }
    ]},
    ...
 ]
};

С этим типом документа для определения ваших форм вы можете легко добавлять формы и проверкикоторые являются специфическими для клиента.

Вы можете легко добавить подчиненные формы, используя тип поля SubForm или любой другой.

Вы можете определить FieldTypes для всех распространенных типов полей, таких как электронная почта, номера телефонов, адрес и т. Д.

namespace System.CustomerName.CustomValidations {
  class CustomerStatus: IValidator {

    private FormContext form;
    private List<ValidationErrors> validationErrors;

    CustomerStatus(FormContext fc) {
      this.validationErrors = new List<ValidationErrors>();
      this.form = fc;
    }

    public List<ValidationErrors> Validate() {
      if (this.formContext.Fields["CustomerType"] == "Gold" && Int.Parse(this.form.Fields["OrderCount"]) < 10) { 
        this.validationErrors.Add(new ValidationError("A gold customer must have at least 10 orders"))
      }

      if (this.formContext.Fields["CustomerType"] == "Valued" && Int.Parse(this.form.Fields["OrderCount"]) < 5) { 
        this.validationErrors.Add(new ValidationError("A valued customer must have at least 5 orders"))
      }
      return this.validationErrors;          
    }
  }
}

Запись документа с таким определением может выглядеть следующим образом:

{Type:"Record",
 EntityType: "Customer",
 Fields: [
   {FieldName:"CustomerName", Value:"ABC Corp.", 
   {FieldName:"CustomerType", Value:"Gold",
   ...
 ]
};

Конечно, это решение - большая работа, но если / когда оно будет реализовано, то будет очень легко создавать / обновлять / настраивать формы.

...