문제

이제 나는 이와 같은 몇 가지 질문을 보았지만, 내가 묻고 싶은 것이 정확히는 아니기 때문에 비명을 지르는 모든 사람들에게는 사과합니다 :).

나는 ASP.NET MVC를 간신히 만지 았지만 내가 이해하는 바에 따르면 ViewState/ControlState는 없습니다 ... 좋아요. 그래서 제 질문은 통제 상태를 유지하는 대안이 무엇입니까? 컨트롤의 상태 또는 MVC와 함께 숨겨진 양식 입력을 만들어 ASP.NET ViewState/ControlState가 수행하는 일을 시뮬레이션 할 수있는 구식 ASP로 돌아가서 AJAX를 항상 가정하고 모든 주 클라이언트 측을 유지하고 AJAX를 만들 수 있습니까? 업데이트 호출?

이 질문에는 몇 가지 답이 있습니다. ASP.NET MVC에서 ViewState 유지?, 그러나 내가 답에서 찾고있는 정확히는 아닙니다.

업데이트 : 지금까지 모든 답변에 감사드립니다. 내가 찾고 있지 않은 것과 내가 찾고있는 것을 정리하기 위해 :

찾고 있지 않음 :

  • 세션 솔루션
  • 쿠키 솔루션
  • MVC에서 웹 포름을 모방하려고하지 않습니다

내가 찾고 있던 것 :

  • 데이터가 컨트롤에 반등하지 않은 경우 포스트 백에서 상태 만 유지하는 방법. 초기 페이지로드에서 그리드를 바인딩하는 시나리오를 사용하여 WebForms를 생각하십시오. 즉, 필요할 때만 데이터를 다시 반응합니다. 내가 언급했듯이, 나는 웹 폼을 모방하려고하지 않고 MVC가 어떤 메커니즘을 제공하는지 궁금합니다.
도움이 되었습니까?

해결책

컨벤션은 너무 많은 후프를 뛰어 넘지 않고 이미 사용할 수 있습니다. 트릭은 뷰에 전달되는 모델을 기반으로 텍스트 상자 값을 연결하는 것입니다.

[AcceptVerbs(HttpVerbs.Get)]   
public ActionResult CreatePost()
{
  return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(FormCollection formCollection)
{
  try
  {
    // do your logic here

    // maybe u want to stop and return the form
    return View(formCollection);
  }
  catch 
  {
    // this will pass the collection back to the ViewEngine
    return View(formCollection);
  }
}

다음에 일어나는 일은 ViewEngine이 FormCollection을 취하고 HTML 도우미를 사용하여 시야에있는 ID 이름/값과 컬렉션의 키를 일치시키는 것입니다. 예를 들어:

<div id="content">

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: <%= Html.TextBox("Title", Model["Title"], 50) %><br />
  Enter the Post Body: <%= Html.TextArea("Body", Model["Body"]) %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

TextBox와 TextArea에는 제목과 신체의 ID가 있습니까? 이제 뷰의 모델 객체에서 값을 어떻게 설정하고 있습니까? FormCollection으로 통과 했으므로 (FormCollection으로 강력하게 입력하도록보기를 설정해야 함) 이제 액세스 할 수 있습니다. 또는 강하게 타자 없이는 ViewData [ "Title"] (내 생각)를 사용할 수 있습니다.

푸프 당신의 마법의 견해. 이 개념을 구성에 대한 규칙이라고합니다.

이제 위의 코드는 FormCollection을 사용하여 가장 단순하고 생생한 형태입니다. FormCollection 대신 ViewModels를 사용하기 시작하면 상황이 흥미로워집니다. 모델/뷰 모델의 자체 유효성 검사를 추가하고 컨트롤러에 사용자 정의 유효성 검사 오류를 자동으로 기포 할 수 있습니다. 그래도 그것은 또 다른 날에 대한 답입니다.

Post Object 대신 PostFormViewModel을 사용하지만 각각의 소유권을 사용하는 것이 좋습니다. 어느 쪽이든, 액션 메소드에 객체를 요구하면 이제 호출 할 수있는 isvalid () 메소드가 나타납니다.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(Post post)
{

  // errors should already be in the collection here
  if (false == ModelState.IsValid())
    return View(post);

  try
  {
    // do your logic here

    // maybe u want to stop and return the form
    return View(post);
  }
  catch 
  {
    // this will pass the collection back to the ViewEngine
    return View(post);
  }
}

그리고 당신의 강력한 견해는 조정해야합니다.

<div id="content">

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: <%= Html.TextBox("Title", Model.Title, 50) %><br />
  Enter the Post Body: <%= Html.TextArea("Body", Model.Body) %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

한 단계 더 나아가 컨트롤러에서 설정 한 ModelState에서 직접보기에서 오류를 표시 할 수 있습니다.

<div id="content">

  <%= Html.ValidationSummary() %>

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: 
    <%= Html.TextBox("Title", Model.Title, 50) %>
    <%= Html.ValidationMessage("Title") %><br />

  Enter the Post Body: 
    <%= Html.TextArea("Body", Model.Body) %>
    <%= Html.ValidationMessage("Body") %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

이 접근법의 흥미로운 점은 내가 검증 요약이나보기에서 개별 검증 메시지를 설정하지 않는다는 것을 알게 될 것입니다. DDD 개념을 연습하고 싶습니다. 이는 내 검증 메시지 (및 요약)가 내 도메인에서 제어되고 컬렉션 형태로 전달되는 것을 의미합니다. 그런 다음 HE 컬렉션을 통과하여 (오류가 있으면) 현재 ModelSTate.adderrors Collection에 추가합니다. 나머지는 뷰 (post)를 반환 할 때 자동입니다.

많은 컨벤션이 나왔습니다. 이 패턴을 훨씬 더 자세하게 다루는 것을 강력히 권장하는 몇 권의 책은 다음과 같습니다.

그리고 순서대로 첫 번째는 전체 MVC 프레임 워크의 생 너트와 볼트를 덮습니다. 후자는 Microsoft 공식 RELM 외부의 고급 기술을 다루며, 삶을 훨씬 쉽게 만들기위한 몇 가지 외부 도구 (Castle Windsor, MOQ 등).

다른 팁

보기는 MVC 패턴으로 바보로되어있어 컨트롤러가 제공하는 내용 만 표시합니다 (분명히 우리는 종종 일부 논리로 끝나지 만 전제는 그렇지 않기위한 것입니다). 컨트롤은 책임이 없습니다. 그들의 상태는 매번 컨트롤러에서 나옵니다.

이 패턴과이 구현을 구현하기에 충분한 Apress의 Steven Sanderson의 Book Pro ASP.NET MVC를 추천 할 수 없습니다.

웹 양식에서는 제어 값이 ViewState에서 유지되므로 귀하는 (이론적으로) 각 PostBack과 마찬가지로 리뉴얼 화 될 필요가 없습니다. 값은 (이론적으로) 프레임 워크에 의해 유지됩니다.

ASP.NET MVC에서 패러다임을 따르는 경우 양식 요소에 상태를 유지할 필요가 없습니다. 양식 요소 값은 컨트롤러가 작동 할 수있는 게시물 (유효성 검사, 데이터베이스 업데이트 등)에서 사용할 수 있습니다. 게시물이 처리되면 표시되는 모든 양식 요소의 경우 귀하 (개발자)가 초기화 할 책임이 있습니다. 프레임 워크는 자동으로이를 수행하지 않습니다.

즉, 컨트롤러가 리디렉션에 따라 데이터를 다른 컨트롤러로 전달할 수있는 TempData라는 메커니즘에 대해 읽었습니다. 실제로 세션 변수 (또는 쿠키를 구성하는 경우 쿠키)이지만 다음 요청 후에 자동으로 정리됩니다.

답은 실제로 상태를 유지하려는 컨트롤 유형에 달려 있습니다. 기본 HTML 컨트롤의 경우 모델로 상태를 유지하기가 매우 쉽습니다.이를 위해서는 강력하게 입력 된보기를 만들어야합니다.

따라서 속성이있는 사용자 모델이있는 경우 사용자 이름, 풀 이름, 이메일이 있으면 다음을 수행 할 수 있습니다.

<%= Html.ValidationSummary() %>

<% using (Html.BeginForm()) { %>
  <fieldset>
    <legend>User details</legend>
    <%= Html.AntiForgeryToken() %>

    <p>
      <label for="Username">Username:</label>
      <%= Html.Textbox("Username", Model.Username, "*") %>
    </p>
    <p>
      <label for="FullName">FullName:</label>
      <%= Html.Textbox("FullName", Model.FullName, "*") %>
    </p>
    <p>
      <label for="Email">Email:</label>
      <%= Html.Textbox("Email", Model.Email, "*") %>
    </p>
    <p>
       <input type+"submit" value="Save user" />
    </p>
  </fieldset>
<% } %>

그런 다음이보기를 표시하는 두 가지 컨트롤러 작업이 있습니다.

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult User()
{
  return View(new User())
}

[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult User([Bind(Include = "Username,FullName,Email")]User user)
{
   if (!ModelState.IsValid()) return View(user);

   try
   {
     user.save()
     // return the view again or redirect the user to another page
   }
   catch(Exception e)
   {
     ViewData["Message"] = e.Message;
     return View(user)
   }
}

이것이 당신이 찾고있는 것입니까? 아니면 요청 사이에 형식으로 표시되지 않는 모델 상태를 유지하고 싶습니까?

기억해야 할 핵심은 요청 및 종료 기간 동안 코드가 서버에서 실행된다는 것입니다. 요청 사이에 전달할 수있는 유일한 정보는 기본 HTML 양식 데이터, URL 매개 변수 및 세션 정보입니다.

다른 사람들이 언급했듯이 MVC 프레임 워크 작업에 대한 완전한 이해를 위해 Steve Sandersan의 Pro ASP.NET MVC 프레임 워크를 강력히 추천합니다.

  • 숨겨진 필드 : :

    <% using (Html.BeginForm<SomeController>(c=>c.SomeAction(null))) {%>
      <%= Html.Hidden("SomeField", Model.SomeField)%>
      <%= Html.Hidden("AnotherField", Model.AnotherField)%>
    
  • 특정 모델을 설정하고 명시 적 필드가 없습니다 (숨겨진 필드를 제공 함). 아래의 예에서 모델은 마지막 게시물에서 수신 된 값으로 컨트롤러로 채워 지므로 상태를 기반으로 필터링 할 수있는 페이지에서 NO JS 옵션이 가능합니다.

    Some Filter: <% using( Html.BeginForm<SomeController>(
            c => c.SomeAction(model.SomeField, model.AnotherField, model.YetAnotherField, null, model.SomeOtherField)
            )) { %>
                <%= Html.DropDownList("status", Model.StatusSelectList)%>
                <input type="submit" value="Filter" class="button" />
                <% } %>
    
  • 확장 방법을 사용하여 필드를 작성하십시오. 제출 된 양식에 실패한 유효성 검사 메시지를 표시 할 때 필드에 게시 된 값으로 채워지기를 원한다면.
  • ASP.NET MVC 2에서 그들은 숨겨진 필드에 인스턴스를 저장하는 방법을 소개했습니다 ... 인코딩 + (I 생각) 서명
  • TempData 위의 모든 것이 수행되지 않으면 (세션을 진행합니다 - 다음 요청에 청소)
  • 언급했듯이 Ajax를 사용할 때 상태는 이미 클라이언트 사이트의 이전로드 된 필드에 있습니다. U L8R에서 전체 게시물을 수행 해야하는 경우 JS와 함께 필요한 필드를 업데이트하십시오.

위의 내용은 다른 시나리오에서 사용할 수있는 다른 독립 옵션입니다. IE 쿠키, 세션, DB에 물건을 저장하지 않은 더 많은 옵션이 있습니다 (재개 가능한 멀티 스텝 마법사와 같이), 매개 변수는 동작으로 전달되었습니다. 그것들을 모두 지배 할 단일 메커니즘이 없으며, 그렇지 않아야합니다.

이를 수행하는 가장 좋은 방법은 원래 모델을 숨겨진 필드로 직렬화 한 다음 필자적으로 해제하고 게시물에서 모델을 업데이트하는 것입니다. 이것은 ViewState 접근 방식에 대해 다소 비슷합니다. 만 직접 구현해야합니다. 나는 이것을 사용한다 :

먼저 물건을 더 쉽게 할 수있는 몇 가지 방법이 필요합니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using LuvDaSun.Extensions;
using System.Web.UI;

namespace LuvDaSun.Web.Mvc
{
    public static class HtmlHelperExtensions
    {
        static LosFormatter _losFormatter = new LosFormatter();
        public static string Serialize(this HtmlHelper helper, object objectInstance)
        {
            var sb = new StringBuilder();
            using (var writer = new System.IO.StringWriter(sb))
            {
                _losFormatter.Serialize(writer, objectInstance);
            }
            return sb.ToString();
        }


    }

    [AttributeUsage(AttributeTargets.Parameter)]
    public class DeserializeAttribute : CustomModelBinderAttribute
    {
        public override IModelBinder GetBinder()
        {
            return new DeserializeModelBinder();
        }
    }

    public class DeserializeModelBinder : IModelBinder
    {
        static LosFormatter _losFormatter = new LosFormatter();

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType.IsArray)
            {
                var type = bindingContext.ModelType.GetElementType();
                var serializedObjects = (string[])bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string[]));
                var deserializedObjects = Array.CreateInstance(bindingContext.ModelType.GetElementType(), serializedObjects.Length);

                for (var index = 0; index < serializedObjects.Length; index++)
                {
                    var serializedObject = serializedObjects[index];
                    var deserializedObject = _losFormatter.Deserialize(serializedObject);

                    deserializedObjects.SetValue(deserializedObject, index);
                }

                return deserializedObjects;
            }
            else
            {
                var serializedObject = (string)bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string));
                var deserializedObject = _losFormatter.Deserialize(serializedObject);

                return deserializedObject;
            }
        }
    }

}

그런 다음 내 컨트롤러에는 이와 같은 것이 있습니다 (제품 업데이트)

    public ActionResult Update(string productKey)
    {
        var model = _shopping.RetrieveProduct(productKey);

        return View(model);
    }
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Update([Deserialize]Shopping.IProduct _model, FormCollection collection)
    {
        UpdateModel(model);

        model.Save();

        return RedirectAfterPost();
    }

그리고 직렬화 된 객체를 양식으로 보유하는 숨겨진 필드가 필요합니다.

    <% 
        using (Html.BeginRouteForm("Product", FormMethod.Post, new { id = UniqueID, }))
        {
    %>
<%= Html.Hidden("Model", Html.Serialize(Model)) %>
    <h1>
        Product bewerken</h1>
    <p>
        <label for="<%=UniqueID %>_Name">
            Naam:</label>
        <input id="<%=UniqueID %>_Name" name="Name" type="text" value="<%= Html.AttributeEncode(Model.Name) %>"
            class="required" />
        <br />
    </p>
    <p>
        Omschrijving:<br />
        <textarea id="<%= UniqueID %>_Description" name="Description" cols="40" rows="8"><%= Html.Encode(Model.Description) %></textarea>
        <br />
    </p>
    <p>
        <label for="<%=UniqueID %>_Price">
            Prijs:</label>
        <input id="<%= UniqueID %>_Price" name="Price" type="text" value="<%= Model.Price.ToString("0.00") %>"
            class="required" />
        <br />
    </p>
    <ul class="Commands">
        <li><a href="" class="ClosePopup">Annuleren</a></li>
        <li>
            <input type="submit" value="Opslaan" /></li>
    </ul>
    <% 
        } 
    %>

    <script type="text/javascript">

        jQuery('#<%= UniqueID %>').validate();

    </script>

보시다시피, 숨겨진 필드 (모델)가 양식에 추가됩니다. 원래 객체에 대한 직렬화 정보가 포함되어 있습니다. 양식이 게시되면 숨겨진 필드도 게시되며 (코스) 내용은 사용자 정의 모델 바인더에 의해 원래 객체로 사형화 된 다음 컨트롤러에 의해 업데이트되고 저장됩니다.

직렬화중인 객체는 직렬화 가능한 속성으로 장식해야하거나 객체를 문자열로 변환 할 수있는 타입 개수가 있어야합니다.

Losformatter (Limited Object Serialization)는 WebForms의 ViewState에서 사용합니다. 또한 직렬화 데이터의 암호화를 제공합니다.

인사 ...

Ajax 전화는 우리가하는 일입니다. 일반적으로 그리드에 대해 이야기하고 있다면 확인하십시오. JQGRID 그리고 그들이 Ajax 구현을 추천하는 방법.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top