ASP.Net MVC Html.HiddenFor yanlış değere sahip


132

Projemde MVC 3 kullanıyorum ve çok garip bir davranış görüyorum.

Modelimdeki belirli bir değer için gizli bir alan oluşturmaya çalışıyorum, sorun şu ki, alan üzerinde ayarlanan değer, Modeldeki değere karşılık gelmiyor.

Örneğin

Bu koda sahibim, tıpkı bir test olarak:

<%:Html.Hidden("Step2", Model.Step) %>
<%:Html.HiddenFor(m => m.Step) %>

Her iki gizli alanın da aynı değere sahip olacağını düşünürdüm. Yaptığım şey, Görünümü ilk kez görüntülediğimde değeri 1 olarak ayarlamak ve ardından gönderimin ardından Model alanının değerini 1 artırmak.

Dolayısıyla, sayfayı ilk kez oluşturduğumda her iki kontrol de 1 değerine sahip, ancak ikinci kez işlenen değerler şunlar:

<input id="Step2" name="Step2" type="hidden" value="2" />
<input id="Step" name="Step" type="hidden" value="1" />

Gördüğünüz gibi, ilk değer doğru, ancak ikinci değer, Görünümü ilk kez görüntülediğimde aynı görünüyor.

Neyi kaçırıyorum? * For Html yardımcıları değerleri bir şekilde önbelleğe alıyor mu? Öyleyse, bu önbelleğe almayı nasıl devre dışı bırakabilirim?

Yardımınız için teşekkürler.


Az önce başka bir şeyi test ettim. HiddenFor çağrısını kaldırır ve yalnızca Gizli çağrısına izin verirsem, ancak "Adım" adını kullanırsam, aynı zamanda yalnızca ilk değeri (1) oluşturur.
willvv

1
de olur
Oren A

Yanıtlar:


191

Bu normaldir ve HTML yardımcıları böyle çalışır. Önce POST isteğinin değerini ve ardından modeldeki değeri kullanırlar. Bu, kontrolör eyleminizdeki modelin değerini değiştirseniz bile, POST isteğinde aynı değişken varsa, değişikliğiniz yok sayılacak ve POSTed değer kullanılacaktır.

Olası bir geçici çözüm, bu değeri, değeri değiştirmeye çalışan denetleyici eylemindeki model durumundan kaldırmaktır:

// remove the Step variable from the model state 
// if you want the changes in the model to be
// taken into account
ModelState.Remove("Step");
model.Step = 2;

Diğer bir olasılık, her zaman modelin değerini kullanan ve POST değerlerini yok sayan özel bir HTML yardımcısı yazmaktır.

Ve yine başka bir olasılık:

<input type="hidden" name="Step" value="<%: Model.Step %>" />

5
Simon İnce'nin bu konudaki blog yazısını gerçekten takdir ettim. Bundan çıkardığım sonuç, iş akışınızın doğru olmasını sağlamaktır. Dolayısıyla, geçerli bir görünüm modelini kabul ettiyseniz ve onunla bir şey yaptıysanız, bu aynı zamanda geri çekilip eşdeğer bir modeli gösterse bile, bir onay eylemine yönlendirin. Bu, yeni bir ModelState'iniz olduğu anlamına gelir. blogs.msdn.com/b/simonince/archive/2010/05/05/… (bugün bu konuda yazdığım bir gönderiden bağlantılı: oceanbites.blogspot.com/2011/02/mvc-renders-wrong-value.html )
Lisa

2
MVC3'ü gerçekten seviyorum ama bu kısım gerçekten hantal. Umarım MVC4'te düzeltirler.
KennyZ

5
Vay canına, bu beni epey bir süre idare etti. Temelde ilk öneriyi kullandım ama geri dönmeden önce sadece ModelState.Clear () çağırdım. Bu harika çalışıyor gibi görünüyor, Clear'ı kullanmamak için herhangi bir sebep var mı?
Jason

1
".Remove" benim için işe yaramadı. Ancak ModelState.Clear (), Controller'a dönmeden hemen önce yaptı. Gizli'nizi özel olarak yazmak da işe yarar. Tüm bunlar, geliştiricilerin "gönder" e bastığında "form değerlerini" kaybetmek istememeleri ve DB'nin doğru şekilde kaydetmemesi nedeniyle olur. En iyi çözüm: Aynı sayfadaki farklı alanlara aynı ad / id ile isim vermeyin.
Dexter

1
Bilginize, bu sinir bozucu davranış, herhangi birinin işlerin daha iyi olacağından endişelenmesi durumunda nazikçe ASP.NET Core'a taşındı
John Hargrove

19

Her adımda daha büyük bir modelin farklı parçalarını gösteren bir Sihirbaz yazarken aynı sorunla karşılaştım.
"Adım 1" deki veriler ve / veya Hatalar, ModelState'in "suçlu" olduğunu sonunda anlayana kadar "Adım 2", vb. İle karıştırılırdı.

Bu benim basit çözümümdü:

if (oldPageIndex != newPageIndex)
{
    ModelState.Clear(); // <-- solution
}

return View(model[newPageIndex]);

10
ModelState.Clear()benzer bir durumda sıralı POST istekleriyle ilgili sorunumu çözdüm.
Evan Mulawski

ModelState.Clear () bahşiş Evan için teşekkürler. Bu daha önce hiç karşılaşmadığım bir anormallikti. Birkaç sıralı ajax.beginform postam vardı ve bunlardan biri önceki bir gönderiden değerleri koruyordu. Kara delik hata ayıklama. Bunun neden önbelleğe alındığını bilen var mı?
Rob

1

Bu kod çalışmayacak

// remove the Step variable from the model state
// if you want the changes in the model to be
// taken into account
ModelState.Remove("Step");
model.Step = 2;

... çünkü HiddenFor her zaman (!) ModelState'ten okur, modelin kendisini değil. Ve "Adım" anahtarını bulamazsa, bu değişken türü için bu durumda 0 olacak varsayılanı üretecektir.

İşte çözüm. Kendim için yazdım ama paylaşmaktan çekinme çünkü birçok insanın bu yaramaz HiddenFor yardımcısıyla mücadele ettiğini görüyorum.

public static class CustomExtensions
{
    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression);
    }

    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression, htmlAttributes);
    }

    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression, htmlAttributes);
    }

    private static void ReplacePropertyState<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        string text = ExpressionHelper.GetExpressionText(expression);
        string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text);
        ModelStateDictionary modelState = htmlHelper.ViewContext.ViewData.ModelState;
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        if (modelState.ContainsKey(fullName))
        {                
            ValueProviderResult currentValue = modelState[fullName].Value;
            modelState[fullName].Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), currentValue.Culture);
        }
        else
        {
            modelState[fullName] = new ModelState
            {
                Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), CultureInfo.CurrentUICulture)
            };
        }
    }
}

Sonra onu her zamanki gibi kendi görünümünüzden kullanırsınız:

@Html.HiddenFor2(m => m.Id)

Koleksiyonlarla da çalıştığını belirtmekte fayda var.


bu çözüm tam olarak işe yaramadı. Sonraki
gönderiden

Bu, iyi çalıştığı üretimden gelen kod. Sizin için neden işe yaramadığını söyleyemem, ancak sayfada doğru değere sahip gizli alanı görürseniz, modelin özelliğine geri yüklenmemesi için açık bir neden göremiyorum. Sayfada yanlış gizli alan değeri görürseniz - bu başka bir hikaye, aynısı benim prodüksiyonumda gerçekleşmeden önce bunun hangi koşullar altında olduğunu bilmek isterim :-) Teşekkür ederim.
Ruslan Georgievskiy

0

Çağrılar arasında aynı model durumunu kullandığım ve arka uçta bir model özelliğini değiştirdiğimde, düşündüğüm aynı durumla çok mücadele ediyorum. Yine de textboxfor veya hiddenfor kullanmam benim için önemli değil.

Model değerini bir js değişkeni olarak saklamak için sayfa betikleri kullanarak durumu atladım, çünkü başlangıçta bu amaç için gizli alana ihtiyacım var.

Bunun yardımcı olup olmadığından emin değilim ama bir düşünün ..

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.