ASP.Net MVC Html. Bị chặn với giá trị sai


132

Tôi đang sử dụng MVC 3 trong dự án của mình và tôi thấy một hành vi rất lạ.

Tôi đang cố gắng tạo một trường ẩn cho một giá trị cụ thể trên Mô hình của mình, vấn đề là vì một số lý do, giá trị được đặt trên trường không tương ứng với giá trị trong Mô hình.

ví dụ

Tôi có mã này, giống như một bài kiểm tra:

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

Tôi nghĩ rằng cả hai trường ẩn sẽ có cùng giá trị. Những gì tôi làm là, đặt giá trị thành 1 trong lần đầu tiên tôi hiển thị Chế độ xem và sau khi gửi, tôi tăng giá trị của trường Mô hình lên 1.

Vì vậy, lần đầu tiên tôi kết xuất trang, cả hai điều khiển đều có giá trị 1, nhưng lần thứ hai các giá trị được hiển thị là:

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

Như bạn có thể thấy, giá trị đầu tiên là chính xác, nhưng giá trị thứ hai dường như giống với lần đầu tiên tôi hiển thị Chế độ xem.

Tôi đang thiếu gì? Có phải * Đối với người trợ giúp Html lưu trữ các giá trị theo một cách nào đó? Nếu vậy, làm thế nào tôi có thể vô hiệu hóa bộ nhớ đệm này?.

Cảm ơn bạn đã giúp đỡ.


Tôi chỉ thử nghiệm một cái gì đó khác. Nếu tôi xóa cuộc gọi HiddenFor và chỉ để cuộc gọi Ẩn, nhưng sử dụng tên "Bước", nó cũng chỉ hiển thị giá trị đầu tiên (1).
willvv

1
cũng xảy ra trong get
Oren A

Câu trả lời:


191

Điều đó là bình thường và đó là cách người trợ giúp HTML hoạt động. Đầu tiên họ sử dụng giá trị của yêu cầu POST và sau đó là giá trị trong mô hình. Điều này có nghĩa là ngay cả khi bạn sửa đổi giá trị của mô hình trong hành động của bộ điều khiển nếu có cùng một biến trong yêu cầu POST, sửa đổi của bạn sẽ bị bỏ qua và giá trị POST sẽ được sử dụng.

Một cách giải quyết khác có thể là loại bỏ giá trị này khỏi trạng thái mô hình trong hành động của bộ điều khiển đang cố gắng sửa đổi giá trị:

// 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;

Một khả năng khác là viết một trình trợ giúp HTML tùy chỉnh sẽ luôn sử dụng giá trị của mô hình và bỏ qua các giá trị POST.

Và một khả năng khác:

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

5
Tôi thực sự đánh giá cao bài viết trên blog của Simon Ince về điều này. Kết luận tôi rút ra từ nó là để đảm bảo quy trình làm việc của bạn là chính xác. Vì vậy, nếu bạn đã chấp nhận một mô hình xem hợp lệ và thực hiện một cái gì đó với nó, sau đó chuyển hướng đến một hành động xác nhận, ngay cả khi điều này cũng chỉ đơn giản là truy xuất và hiển thị một mô hình tương đương. Điều này có nghĩa là bạn có một ModelState mới. blogs.msdn.com/b/simonince/archive/2010/05/05/... (liên kết từ một bài tôi đã viết ngày hôm nay này: oceanbites.blogspot.com/2011/02/mvc-renders-wrong-value.html )
Lisa

2
Tôi thực sự thích MVC3, nhưng bit này thực sự rất khó hiểu. Tôi hy vọng họ sửa nó trong MVC4.
KennyZ

5
Wow, cái này đã cho tôi đi khá lâu. Về cơ bản, tôi đã sử dụng đề xuất đầu tiên nhưng chỉ gọi là ModelState.Clear () trước khi quay lại. Điều này dường như làm việc tuyệt vời, có lý do gì để không sử dụng Clear?
Jason

1
".Remove" không hoạt động với tôi. Nhưng ModelState.Clear () đã làm đúng trước khi trả về Bộ điều khiển. Tùy chỉnh viết Hidden của bạn cũng sẽ hoạt động tốt. Tất cả điều này xảy ra bởi vì các nhà phát triển không muốn mất "giá trị biểu mẫu" của họ nếu họ nhấn "gửi" và DB không lưu chính xác. Giải pháp tốt nhất: không đặt tên các trường khác nhau trên cùng một trang cùng tên / id.
Dexter

1
FYI hành vi gây phiền nhiễu này đã được chuyển sang ASP.NET Core trong trường hợp bất cứ ai lo lắng mọi thứ sẽ trở nên tốt hơn
John Hargrove

19

Tôi gặp phải cùng một vấn đề khi viết một Wizard hiển thị các phần khác nhau của một mô hình lớn hơn ở mỗi bước.
Dữ liệu và / hoặc Lỗi từ "Bước 1" sẽ bị lẫn lộn với "Bước 2", v.v., cho đến khi cuối cùng tôi nhận ra rằng ModelState là 'đổ lỗi'.

Đây là giải pháp đơn giản của tôi:

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

return View(model[newPageIndex]);

10
ModelState.Clear()đã giải quyết vấn đề của tôi với các yêu cầu POST liên tiếp trong tình huống tương tự.
Evan Mulawski

Cảm ơn về mẹo ModelState.Clear () Evan. Đây là một sự bất thường mà tôi chưa bao giờ gặp phải trước đây. Tôi đã có một số bài đăng ajax.beginform tuần tự và một trong số đó là giữ lại các giá trị từ bài đăng trước. Gỡ lỗi lỗ đen. Bất cứ ai cũng biết tại sao điều này được lưu trữ?
Rob

1

Mã này sẽ không hoạt động

// 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;

... bởi vì HiddenFor luôn luôn (!) đọc từ ModelState chứ không phải chính mô hình. Và nếu không tìm thấy phím "Bước", nó sẽ tạo mặc định cho loại biến đó là 0 trong trường hợp này

Đây là giải pháp. Tôi đã viết nó cho chính mình nhưng không ngại chia sẻ nó vì tôi thấy nhiều người đang vật lộn với người trợ giúp HiddenFor nghịch ngợm này.

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)
            };
        }
    }
}

Sau đó, bạn chỉ cần sử dụng nó như bình thường từ bên trong bạn xem:

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

Nó đáng để đề cập đến nó hoạt động với các bộ sưu tập quá.


Giải pháp này không hoạt động đầy đủ. Sau khi đăng lại tài sản trở lại là null trong Hành động
user576510

Vâng, đây là mã từ sản xuất, nơi nó hoạt động tốt. Tôi không thể biết lý do tại sao nó không hoạt động với bạn nhưng nếu bạn thấy trường ẩn có giá trị chính xác được hiển thị trên trang thì tôi không thấy lý do rõ ràng tại sao nó không được khôi phục vào thuộc tính của mô hình. Nếu bạn thấy giá trị trường ẩn sai trên trang mặc dù - đó là một câu chuyện khác, tôi sẽ rất muốn biết trong trường hợp nào điều này xảy ra trước khi điều tương tự xảy ra trong sản phẩm của tôi :-) Cảm ơn bạn.
Ruslan Georgievskiy

0

Tôi quá vật lộn với tình huống tương tự tôi nghĩ, nơi tôi sử dụng trạng thái mô hình giống nhau giữa các cuộc gọi và khi tôi thay đổi một thuộc tính mô hình trên phụ trợ. Mặc dù vậy, nó không thành vấn đề đối với tôi, nếu tôi sử dụng textboxfor hoặc hiddenfor.

Tôi chỉ bỏ qua tình huống bằng cách sử dụng các tập lệnh trang để lưu trữ giá trị mô hình dưới dạng biến js, vì tôi cần trường ẩn cho mục đích đó ngay từ đầu.

Không chắc chắn nếu điều này giúp nhưng chỉ cần xem xét ..

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.