Как изменить опубликованные данные формы в действии контроллера перед отправкой на просмотр?

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

    [AcceptVerbs("POST")]
    public ActionResult EditProduct(int id, [Bind(Include="UnitPrice, ProductName")]Product product) {
        NORTHWNDEntities entities = new NORTHWNDEntities();

        if (ModelState.IsValid) {
            var dbProduct = entities.ProductSet.First(p => p.ProductID == id);
            dbProduct.ProductName = product.ProductName;
            dbProduct.UnitPrice = product.UnitPrice;
            entities.SaveChanges();
        }

        /* Neither of these work */
        product.ProductName = "This has no effect";
        ViewData["ProductName"] = "This has no effect either";

        return View(product);
    }

Кто-нибудь знает, какой правильный метод для этого?

Ответы

Ответ 1

После изучения этого, у меня есть объяснение, почему следующий код не действует в Action:

product.ProductName = "This has no effect";
ViewData["ProductName"] = "This has no effect either";

В My View используются HTML-помощники:

<% Html.EditorFor(x => x.ProductName);

HTML-помощники используют следующий порядок приоритета при попытке поиска ключа:

  • Запись словаря ViewData.ModelState
  • Свойство Model (если строго типизированное представление. Это свойство является ярлыком для View.ViewData.Model)
  • Запись словаря ViewData​​li >

Для HTTP-сообщений, ModelState всегда заполняется, поэтому изменение модели (product.ProductName) или ViewData напрямую (ViewData [ "ProductName" ]) не имеет эффекта.

Если вам нужно изменить ModelState напрямую, синтаксис для этого:

ModelState.SetModelValue("ProductName", new ValueProviderResult("Your new value", "", CultureInfo.InvariantCulture));

Или, чтобы очистить значение ModelState:

ModelState.SetModelValue("ProductName", null);

Вы можете создать метод расширения для упрощения синтаксиса:

public static class ModelStateDictionaryExtensions {
    public static void SetModelValue(this ModelStateDictionary modelState, string key, object rawValue) {
        modelState.SetModelValue(key, new ValueProviderResult(rawValue, String.Empty, CultureInfo.InvariantCulture));
    }
}

Тогда вы можете просто написать:

ModelState.SetModelValue("ProductName", "Your new value");

Подробнее см. Потребление данных в представлениях MVC2.

Ответ 2

Значения хранятся в ModelState.

Это должно делать то, что вы хотите:

ModelState.SetModelValue("ProductName", "The new value");

Я бы не предложил сделать это, хотя... правильным методом было бы следовать шаблон PRG (Post/Redirect/Get).

HTHS,
Чарльз

EDIT: обновлено, чтобы лучше отразить значение ModelState, найденное с помощью @Gary

Ответ 3

Это приведет к переоценке модели при простых условиях:

ModelState.Clear();
model.Property = "new value";
TryValidateModel(model);

Ответ 4

Выполните ModelState.Clear() перед изменением модели.

...
ModelState.Clear()
dbProduct.ProductName = product.ProductName;
dbProduct.UnitPrice = product.UnitPrice;
...