잘못된 값을 가진 ASP.Net MVC Html.HiddenFor


132

내 프로젝트에서 MVC 3을 사용하고 있으며 매우 이상한 동작을보고 있습니다.

내 모델의 특정 값에 대해 숨겨진 필드를 만들려고하는데 문제는 어떤 이유로 필드에 설정된 값이 모델의 값과 일치하지 않는다는 것입니다.

예 :

테스트와 마찬가지로이 코드가 있습니다.

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

숨겨진 필드 모두 동일한 값을 가질 것이라고 생각합니다. 내가하는 일은보기를 처음 표시 할 때 값을 1로 설정 한 다음 제출 후 모델 필드의 값을 1 씩 늘리는 것입니다.

따라서 페이지를 처음 렌더링 할 때 두 컨트롤의 값은 1이지만 두 번째 렌더링 값은 다음과 같습니다.

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

보시다시피 첫 번째 값은 정확하지만 두 번째 값은 처음보기를 표시 할 때와 같은 것 같습니다.

내가 무엇을 놓치고 있습니까? * For Html 헬퍼가 어떤 방식으로 값을 캐싱합니까? 그렇다면이 캐싱을 어떻게 비활성화 할 수 있습니까?

당신의 도움을 주셔서 감사합니다.


방금 다른 것을 테스트했습니다. HiddenFor 호출을 제거하고 숨겨진 호출 만 허용하고 "단계"이름을 사용하면 첫 번째 값 (1) 만 렌더링됩니다.
willvv

1
뿐만 아니라 취득으로 발생
오렌

답변:


191

그것은 정상이며 HTML 도우미가 작동하는 방식입니다. 먼저 POST 요청의 값을 사용하고 그 후에 모델의 값을 사용합니다. 이는 POST 요청에 동일한 변수가있는 경우 컨트롤러 조치에서 모델 값을 수정하더라도 수정이 무시되고 POST 값이 사용됨을 의미합니다.

가능한 해결 방법 중 하나는 값을 수정하려고하는 컨트롤러 조치의 모델 상태에서이 값을 제거하는 것입니다.

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

또 다른 가능성은 항상 모델 값을 사용하고 POST 값을 무시하는 사용자 정의 HTML 헬퍼를 작성하는 것입니다.

그리고 또 다른 가능성 :

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

5
Simon Ince의 블로그 게시물에 정말 감사했습니다. 내가 얻은 결론은 워크 플로우가 올바른지 확인하는 것입니다. 따라서 유효한 뷰 모델을 수락하고 해당 모델로 무언가를 수행 한 경우 단순히 동일한 모델을 검색하여 표시하더라도 확인 작업으로 리디렉션합니다. 이것은 새로운 ModelState를 가지고 있음을 의미합니다. blogs.msdn.com/b/simonince/archive/2010/05/05/... (I이 오늘 쓴 글에서 링크 : oceanbites.blogspot.com/2011/02/mvc-renders-wrong-value.html )
Lisa

2
나는 MVC3를 정말로 좋아하지만이 비트는 정말 어수선합니다. MVC4에서 수정하기를 바랍니다.
KennyZ

5
와우, 이건 꽤 오랫동안 갔었 어. 기본적으로 첫 번째 제안을 사용했지만 반환하기 전에 ModelState.Clear ()를 호출했습니다. 이것은 잘 작동하는 것 같습니다. Clear를 사용하지 않는 이유가 있습니까?
Jason

1
".Remove"가 작동하지 않았습니다. 그러나 ModelState.Clear ()는 Controller로 돌아 오기 직전에 수행되었습니다. 숨겨진 사용자 정의도 잘 작동합니다. 개발자가 "제출"을 누르고 DB가 올바르게 저장되지 않으면 "양식 값"을 잃고 싶지 않기 때문에이 모든 것이 발생합니다. 가장 좋은 해결책 : 같은 페이지에서 다른 이름을 같은 이름 / ID로 지정하지 마십시오.
Dexter

1
참고로,이 성가신 행동은 누군가가 상황이 나아 질까 걱정되는 경우 ASP.NET Core로 은혜롭게 옮겨졌습니다.
John Hargrove

19

모든 단계에서 더 큰 모델의 다른 부분을 보여주는 마법사를 작성할 때도 같은 문제가 발생했습니다.
ModelState가 '비난'되었다는 것을 마침내 깨달을 때까지 "단계 1"의 데이터 및 / 또는 오류가 "단계 2"등과 혼합됩니다.

이것은 나의 간단한 해결책이었습니다.

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

return View(model[newPageIndex]);

10
ModelState.Clear()비슷한 상황에서 순차적 POST 요청과 관련된 문제를 해결했습니다.
Evan Mulawski

ModelState.Clear () 팁 Evan에 감사드립니다. 이것은 내가 전에는 본 적이없는 변칙이었다. 여러 개의 순차적 ajax.beginform 게시물이 있었고 그 중 하나는 이전 게시물의 값을 유지했습니다. 블랙홀 디버깅. 왜 이것이 캐시되는지 아는 사람이 있습니까?
Rob

1

이 코드는 작동하지 않습니다

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

... 숨겨져 있기 때문에 항상 (!)는 모델 자체가 아닌 ModelState에서 읽습니다. "Step"키를 찾지 못하면 해당 변수 유형에 대한 기본값 인 0이됩니다.

해결책은 다음과 같습니다. 나는 그것을 위해 직접 작성했지만 그것을 공유하는 것을 신경 쓰지 않습니다. 많은 사람들 이이 장난 꾸러기 HiddenFor 도우미로 고심하고 있습니다.

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

그런 다음보기 내에서 평소와 같이 사용하십시오.

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

컬렉션에서도 작동한다는 것은 언급 할 가치가 있습니다.


이 솔루션은 완전히 작동하지 않았습니다. 다음 게시물에 다시 등록 후 널 (null)은 액션에
user576510

글쎄, 이것은 잘 작동하는 프로덕션 코드입니다. 왜 그것이 작동하지 않는지 알 수는 없지만 페이지에 올바른 값으로 렌더링 된 숨겨진 필드가 표시되면 모델 속성으로 복원되지 않는 분명한 이유가 없습니다. 페이지에 숨겨진 필드 값이 잘못 표시되면 다른 이야기입니다. 제작에서 동일한 상황이 발생하기 전에 어떤 상황에서 이런 일이 발생하는지 알고 싶습니다. :-) 감사합니다.
Ruslan Georgievskiy

0

전화와 동일한 모델 상태를 사용하고 백엔드에서 모델 속성을 변경할 때와 같은 상황으로 어려움을 겪고 있습니다. textboxfor 또는 hiddenfor를 사용하면 나에게 중요하지 않습니다.

페이지 스크립트를 사용하여 모델 값을 js 변수로 저장하여 상황을 우회합니다. 처음에는 해당 필드에 숨겨진 필드가 필요하기 때문입니다.

이것이 도움이되는지 확실하지 않지만 고려하십시오 ..

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.