Повторное использование данных модели в действии публикации - PullRequest
5 голосов
/ 09 февраля 2012

В моей модели представления у меня есть список элементов, которые я извлекаю из базы данных и затем отправляю в представление. Я хотел бы знать, возможно ли избежать повторного заполнения свойства параметров всякий раз, когда я нажимаю на действие Post и мне нужно вернуть модель (для ошибок проверки, а что нет)?

В веб-формах это не нужно.

Редактировать : Мне было не ясно. Моя проблема с опциями SelectList, которые я использую для своих DropDownLists. Все публикуется, но если мне нужно вернуться к представлению (модель недействительна), я должен перезагрузить параметры из базы данных! Я хочу знать, можно ли этого избежать.

Моя модель:

public class TestModel
{
    public TestModel()
    {
        Departments = new List<SelectListItem>();
    }

    public string Name { get; set; }
    public int Department { get; set; }
    public IEnumerable<SelectListItem> Departments { get; set; }
}

Мой взгляд:

@model MvcApplication1.Models.TestModel    
@using (Html.BeginForm())
{
    @Html.TextBoxFor(m => m.Name)

    @Html.DropDownListFor(m => m.Department, Model.Departments)

    <input type=submit value=Submit />
}

Мой контроллер (обратите внимание на комментарий HttpPost ):

public ActionResult Index()
{
    TestModel model = new TestModel
    {
        Name = "Rafael",
        Department = 1,
        Departments = new List<SelectListItem>
        {
            new SelectListItem { Text = "Sales", Value = "1" },
            new SelectListItem { Text = "Marketing", Value = "2", Selected = true },
            new SelectListItem { Text = "Development", Value = "3" }
        }
    };

    // Departments gets filled from a database.

    return View(model);
}

[HttpPost]
public ActionResult Index(TestModel model)
{
if (!ModelState.IsValid)
{
    //Do I have to fill model.Departments again!?!?!?

    return View(model); 
}
else { ...  }
}

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

Редактировать: К вашему сведению, я решил использовать переменную Session.

Ответы [ 3 ]

1 голос
/ 09 февраля 2012

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

То есть представление

@model MyNamesspace.Models.MyModel
...
@using (Html.BeginForm())
{
    ....
}

И ваш метод управления, который размещен на.

[HttpPost]
public ActionResult MyAction(MyModel model)
{
    ...
}

РЕДАКТИРОВАТЬ: также убедитесь, что у вас есть поля формы для каждого свойства модели, которые вам нужно опубликовать в контроллере.Мой пример тоже использует Razor.

0 голосов
/ 09 февраля 2012

Я удивлен, что этот вопрос не возникает чаще, и я также удивлен, что очевидный (ИМХО) ответ в наши дни не является стандартной практикой: почти все POST должны основываться на Ajax. Это решает целый ряд проблем, включая

  1. Нет необходимости повторно заполнять данные формы, когда у вас есть, например, ошибка проверки или ошибка приложения (исключение). Это особенно желательно, когда у вас есть состояние на стороне клиента (по-настоящему богатым способом веб-приложения).
  2. Нет принуждения выполнять проверку на стороне клиента. Проверка может быть на 100% на стороне сервера (где она должна быть в любом случае), и пользовательский интерфейс почти такой же.

Конечно, есть некоторая начальная работа, которую вам нужно сделать для создания структуры для этого, например, у меня есть набор типов AjaxUpdate, AjaxNothing, AjaxRedirect, AjaxErrors ... ActionResult, которые отображают Json, который обрабатывается некоторый пользовательский Javascript. Но как только вы это сделаете, все будет гладко.

0 голосов
/ 09 февраля 2012

Я столкнулся с подобной проблемой при попытке создания мастера Order в MVC (где каждая страница мастера реализована в виде частичного представления, загружаемого AJAX).Я очень сомневаюсь, что это предложенный метод, но мой способ решения этой проблемы заключался в вызове пользовательского метода MergeChanges в каждом действии, вызываемом моим мастером:

public Order MergeChanges(Order newOrder)
{
    var sessionHistory = (List<string>)Session["sessionHistory"];

    if (sessionHistory == null || sessionHistory.Count == 0)
    return MergeChanges(newOrder, -1);

    return MergeChanges(newOrder, MasterViewController.GetStepNumberByName(sessionHistory.Last()));
}

public Order MergeChanges(Order newOrder, int step)
{
    PreMerge(newOrder);

    Order result = null;
    try
    {
        ApplyLookups(ref newOrder);
        Order oldOrder = (Order)Session["order"];

        if (oldOrder == null)
        {
             Session["order"] = newOrder;
             result = newOrder;
        }
        else
        {
            List<TypeHelper.DecoratedProperty<ModelPageAttribute>> props = null;
            newOrder.GetType().GetDecoratedProperty<ModelPageAttribute>(ref props);
            props = props.Where(p => (p.Attributes.Count() > 0 && p.Attributes.First().PageNumber.Contains(step))).ToList();
            foreach (var propPair in props)
            {
                object oldObj = oldOrder;
                object newObj = newOrder;
                if (!string.IsNullOrEmpty(propPair.PropertyPath))
                {
                    bool badProp = false;
                    foreach (string propStr in propPair.PropertyPath.Split('\\'))
                    {
                        var prop = oldObj.GetType().GetProperty(propStr);
                        if (prop == null)
                        {
                            badProp = true;
                            break;
                        }

                        oldObj = prop.GetValue(oldObj, BindingFlags.GetProperty, null, null, null);
                        newObj = prop.GetValue(newObj, BindingFlags.GetProperty, null, null, null);
                     }
                     if (badProp)
                          continue;
                 }

                 if (newObj == null)
                     continue;

                 var srcVal = propPair.Property.GetValue(newObj, BindingFlags.GetProperty, null, null, null);
                 var dstVal = propPair.Property.GetValue(oldObj, BindingFlags.GetProperty, null, null, null);

                  var mergeHelperAttr = propPair.Property.GetAttribute<MergeHelperAttribute>();
                   if (mergeHelperAttr == null)
                   {
                        if (newObj != null)
                            propPair.Property.SetValue(oldObj, srcVal, BindingFlags.SetProperty, null, null, null);
                   }
                   else
                   {
                       var mergeHelper = (IMergeHelper)Activator.CreateInstance(mergeHelperAttr.HelperType);
                       if (mergeHelper == null)
                           continue;

                       mergeHelper.Merge(context, HttpContext.Request, newObj, propPair.Property, srcVal, oldObj, propPair.Property, dstVal);
                    }
               }
               result = oldOrder;
          }
    }
    finally
    {
    PostMerge(result);
    }
    return result;
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...