Подтвердить что ты не робот

Динамические (созданные в Runtime) формы в ASP.NET MVC

Это общий вопрос дизайна: Как реализовать динамическую (сгенерированную во время выполнения) форму в ASP.NET MVC?

Здесь ситуация:

  • Администратор сайта может определять параметры формы (поля, тип полей, проверку) с графическим интерфейсом (представление MVC).
  • При необходимости среда выполнения формирует форму для конечного пользователя на основе конфигурации администратора. Я предполагаю, что вся эта логика будет находиться в контроллере - или, возможно, методы расширения, фильтры действий или что-то в этом роде.
  • Конечный пользователь заполняет форму, отправляет запросы, информация записывается в базу данных.

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

Спасибо за помощь.

4b9b3361

Ответ 1

У меня была такая же потребность в недавнем проекте. Для этого я создал библиотеку классов. Я только что выпустил новую версию библиотеки.

Может быть, это может вам помочь: Динамические формы ASP.NET MVC

Ответ 2

Вы можете сделать это очень легко, используя мою библиотеку FormFactory.

По умолчанию он отражает модель представления для создания массива PropertyVm[], но вы также можете создавать свойства программно, чтобы вы могли загружать настройки из базы данных, а затем создавать PropertyVm.

Это фрагмент из Linqpad script.

`` `

//import-package FormFactory
//import-package FormFactory.RazorGenerator


void Main()
{
    var properties = new[]{
        new PropertyVm(typeof(string), "username"){
            DisplayName = "Username",
            NotOptional = true,
        },
        new PropertyVm(typeof(string), "password"){
            DisplayName = "Password",
            NotOptional = true,
            GetCustomAttributes = () => new object[]{ new DataTypeAttribute(DataType.Password) }
        }
    };
    var html = FormFactory.RazorEngine.PropertyRenderExtension.Render(properties, new FormFactory.RazorEngine.RazorTemplateHtmlHelper());   

    Util.RawHtml(html.ToEncodedString()).Dump(); //Renders html for a username and password field.
}

`` `

Theres демонстрационный сайт с примерами различных функций, которые вы можете настроить (например, вложенные коллекции, автозаполнение, датапикеры и т.д.)

Ответ 3

Другой вариант - иметь очень слабо связанную схему базы данных.

//this will contain all the fields and types that the admin user sets
**ApplicationFields**
FieldName
FieldType
...

//these are all the values that have some mapping to a ParentObjectID
**FormValues**
ParentObjectID
FieldName
FieldValue

Когда вы отправляете свой Сгенерированный просмотр (из ApplicationFields), просто пропустите свой FormCollection и попробуйте установить его в ParentObject, который вам нужно обновить.

public ActionResult MyForm(FormCollection form)
{
    //this is the main object that contains all the fields
    var parentObject;

    foreach (string key in form)
    {
        parentObject.SetValue(key, form[key]);
    }
    ...

Тогда ваш объект parentObject может быть чем-то вроде этого...

public partial class ParentObject
{
    IList _FormValues;

    public void SetValue(string key, string value)
    {
        //try and find if this value already exists
        FormValue v = _FormValues.SingleOrDefault(k => k.Key == key);

        //if it does just set it
        if (v != null)
        {
            v.Value = value;
            return;
        }

        //else this might be a new form field added and therefore create a new value
        v = new FormValue
        {
            ParentObjectID = this.ID,
            Key = key,
            Value = value
        };

        _FormValues.Add(v);
    }
}

Ответ 4

Один из способов сделать это - создать свой собственный ModelBinder, который будет в основе ваших сгенерированных форм. Модельный блок отвечает за проверку ModelState и восстановление типизированного ViewDataModel (при условии ввода ваших просмотров).

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

В вашем случае ваше связующее устройство должно получить подтверждение для поля во время выполнения из файла/строки xml.

Если у вас есть маршрут, например:

routes.MapRoute(null, "Forms/{formName}/", new { action = "Index", controller = "Forms", formName = ""}),

Затем вы можете найти правильную форму xml в FormsController.Index(string formName) и передать ее в представление.

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

Вид для индекса формы может генерировать форму из этого xml через расширение HtmlHelper, которое принимает XmlDocument.

Затем, когда вы (или asp.net mvc) свяжете свою форму с вашим ViewData, вызывается ваше настраиваемое связующее устройство, оно может проверять текущие значения контроллера для поиска formName и искать соответствующий xml, который содержит всю проверку правила. Затем ModelBinder отвечает за заполнение ModelState любыми ошибками, определенными во время выполнения.

Это трудная задача, но когда она удалена успешно, стоит ее на мой взгляд:)

Обновить лучшая альтернатива данным модели будет очень свободной схемой базы данных, как предлагает Дэвид Лиддл. Я по-прежнему не в состоянии сохранить его как xml (или некоторый сериализованный формат) и использовать его для создания представления и для хранения правил проверки для пользовательского ModelBinder, чтобы у вас было больше контроля над макетом и валидацией каждого поля.

Ответ 6

Я не вижу огромных преимуществ генерации XForms или любой другой абстракции по сравнению с HTML по сравнению с прямым форматированием HTML с помощью списка управления "Web Forms 2.0" для модели типа List<Tuple<Meta, Value>>. Примечание: на стороне сервера вам в любом случае придется вручную анализировать результаты, чтобы они соответствовали вашим структурам.

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

Итак, просто введите код wirte, который генерирует элементы управления Web 2 в цикле @Foreach.