Проверка на ASP.net модель MVC3 с динамическими свойствами - PullRequest
2 голосов
/ 23 февраля 2012

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

Я хочу иметь возможность сделать это в своем действии Edit:

[HttpPost]
public ActionResult Edit(Movie movie) 
{
    if (ModelState.IsValid) 
    {
        db.Entry(movie).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Обычный вид:

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Movie</legend>

        @Html.HiddenFor(model => model.ID)

        <div class="editor-label">
            @Html.LabelFor(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>
    </fieldset>
}

Что мне нужно сделать:

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Movie</legend>

        @Html.HiddenFor(model => model.ID)

        for(i = 1 to n) {
            <div class="editor-label">
                @Html.LabelFor(model => model.Fields[i].Name)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Fields[i].Value)
                @Html.ValidationMessageFor(model => model.Fields[i].Value)
            </div>
        }
        </fieldset>
}

Модель:

public class Movie
{
    public Movie()
    {
        this.Fields = new List<Field>();
    }
    public List<Movie> Movies { get; set; }
}

Класс поля:

public class Field
{
    public string Name { get; set; }
    public Type Type { get; set; }
    public object Value { get; set; }
} 

1 Ответ

2 голосов
/ 23 февраля 2012

Я полагаю, что-то вроде этого должно работать:

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Movie</legend>

        @Html.HiddenFor(model => model.ID)
        @{int i = 0;}
        @foreach(var field in model.Fields) {
            var htmlFieldName = string.Format("Fields[{0}]", i);

            <div class="editor-label">
                <label for="@htmlFieldName">@field.Title</label>
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => field, null, htmlFieldName)
                @Html.ValidationMessage(htmlFieldName)
            </div>
        }
        </fieldset>
}

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

POST должен заканчиваться следующими значениями:

ID=123
Fields[0]=Jaws
Fields[1]=VeggieTales
...

... и это должно автоматически связываться с вашей моделью фильма, если модель имеет, например, List<string> по имени Поля.Если ваша модель выглядит не так, это должно как минимум привести вас на правильный путь.

Обновление

В своем комментарии вы объясняете, что пытаетесь создать редактор для объект .Здесь есть две основные трудности:

  1. MVC использует статический тип, возвращаемый в лямбда-выражении, которое вы передаете EditorFor, чтобы определить, какой тип редактора он должен создавать.Чтобы переопределить это, вам нужно будет указать конкретное имя шаблона, в котором мое первоначальное предложение показывает, что вы предоставляете null:

    @Html.EditorFor(model => field.Value, field.Type.Name, htmlFieldName + ".Value")
    

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

  2. При повторной публикации сервер не может узнать, что Field[0] является int, и т. Д. Вы можете:

    1. Укажите скрытые значения для указания каждого типа, а затем используйте пользовательский механизм связывания модели, который может использовать эту информацию для построения каждого поля на основе комбинированных типа и значения.
    2. Создайте заново структуру объекта Movie нана стороне сервера на основе идентификатора фильма, а затем пройдитесь по каждому из его полей, вызывая:

      TryUpdateModel((dynamic)field, string.Format("Field[{0}]", i));
      

Возможно, есть и другие варианты, но это всевремя, которое я готов потратить на это сегодня.

...