programing tip

RedirectToAction으로 ModelState를 유지하려면 어떻게해야합니까?

itbloger 2020. 11. 1. 17:24
반응형

RedirectToAction으로 ModelState를 유지하려면 어떻게해야합니까?


ModelState 정보를 잃지 않고 ModelState에 오류가있는 경우 다른 작업의 결과를 반환하거나 사용자를 다른 작업으로 이동하려면 어떻게해야합니까?

시나리오는 다음과 같습니다. 삭제 작업은 내 색인 작업 /보기에서 렌더링 한 DELETE 양식에서 POST를 수락합니다. 삭제에 오류가있는 경우 사용자를 다시 색인 작업 /보기로 이동하고 .NET Framework에서 삭제 작업으로 저장된 오류를 표시합니다 ViewData.ModelState. ASP.NET MVC에서 어떻게이 작업을 수행 할 수 있습니까?

[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Delete)]
public ActionResult Delete([ModelBinder(typeof(RdfUriBinder))] RdfUri graphUri)
{
    if (!ModelState.IsValid)
        return Index(); //this needs to be replaced with something that works :)

    return RedirectToAction("Index");
}

뷰 데이터를 TempData에 저장하고 인덱스 작업에서 검색합니다 (있는 경우).

   ...
   if (!ModelState.IsValid)
       TempData["ViewData"] = ViewData;

   RedirectToAction( "Index" );
}

 public ActionResult Index()
 {
     if (TempData["ViewData"] != null)
     {
         ViewData = (ViewDataDictionary)TempData["ViewData"];
     }

     ...
 }

[편집] MVC의 온라인 소스를 확인한 결과 Controller의 ViewData가 설정 가능한 것으로 보이므로 ModelState를 포함한 모든 ViewData를 Index 액션으로 전송하는 것이 가장 쉽습니다.


작업 필터 (PRG 패턴) 사용 (속성을 사용하는 것만 큼 쉬움)

여기여기에 언급 되었습니다 .


tvanfosson의 솔루션이 항상 작동하는 것은 아니지만 대부분의 경우 괜찮을 것입니다.

특정 솔루션의 문제는 이미 ViewData 또는 ModelState가있는 경우 이전 요청의 상태로 모두 덮어 쓰게된다는 것입니다. 예를 들어, 새 요청에는 작업에 전달되는 잘못된 매개 변수와 관련된 일부 모델 상태 오류가있을 수 있지만 이러한 오류는 덮어 쓰기 때문에 숨겨집니다.

예상대로 작동하지 않을 수있는 또 다른 상황은 일부 ViewData 또는 ModelState 오류를 초기화 한 작업 필터가있는 경우입니다. 다시 말하지만, 해당 코드로 덮어 쓰게됩니다.

두 요청의 상태를 더 쉽게 병합 할 수있는 ASP.NET MVC 용 솔루션을 찾고 있으므로 계속 지켜봐주십시오.

고마워, Eilon


이것이 PRG를 사용하여 @bob의 권장 솔루션을 사용한 사람에게 유용한 경우 :

항목 13-> 링크 참조 .

VeiwBag에서 View로 전달되는 메시지가 추가 문제로 작성되고 컨트롤러 작업에서 TempData에서 수동으로 확인 /로드됩니다 RedirectToAction("Action"). 단순화 (유지 보수 가능)하기 위해이 접근 방식을 약간 확장하여 다른 데이터도 확인하고 저장 /로드했습니다. 내 행동 방법은 다음과 같습니다.

 [AcceptVerbs(HttpVerbs.Post)]
 [ExportModelStateToTempData]
 public ActionResult ChangePassword(ProfileViewModel pVM) {
      bool result = MyChangePasswordCode(pVM.ChangePasswordViewModel);
      if (result) {
           ViewBag.Message = "Password change success";
      else {
           ModelState.AddModelError("ChangePassword", "Some password error");
      }
      return RedirectToAction("Index");
    }

그리고 내 색인 작업 :

[ImportModelStateFromTempData]
public ActionResult Index() {
    ProfileViewModel pVM = new ProfileViewModel { //setup }
    return View(pVM);
}

액션 필터의 코드 :

// Following best practices as listed here for storing / restoring model data:
// http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#prg
public abstract class ModelStateTempDataTransfer : ActionFilterAttribute {
    protected static readonly string Key = typeof(ModelStateTempDataTransfer).FullName;
}

:

public class ExportModelStateToTempData : ModelStateTempDataTransfer {
    public override void OnActionExecuted(ActionExecutedContext filterContext) {
        //Only export when ModelState is not valid
        if (!filterContext.Controller.ViewData.ModelState.IsValid) {
            //Export if we are redirecting
            if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult)) {
                filterContext.Controller.TempData[Key] = filterContext.Controller.ViewData.ModelState;
            }
        }
        // Added to pull message from ViewBag
        if (!string.IsNullOrEmpty(filterContext.Controller.ViewBag.Message)) {
            filterContext.Controller.TempData["Message"] = filterContext.Controller.ViewBag.Message;
        }

        base.OnActionExecuted(filterContext);
    }
}

:

public class ImportModelStateFromTempData : ModelStateTempDataTransfer {
    public override void OnActionExecuted(ActionExecutedContext filterContext) {
        ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary;

        if (modelState != null) {
            //Only Import if we are viewing
            if (filterContext.Result is ViewResult) {
                filterContext.Controller.ViewData.ModelState.Merge(modelState);
            } else {
                //Otherwise remove it.
                filterContext.Controller.TempData.Remove(Key);
            }
        }
        // Restore Viewbag message
        if (!string.IsNullOrEmpty((string)filterContext.Controller.TempData["Message"])) {
            filterContext.Controller.ViewBag.Message = filterContext.Controller.TempData["Message"];
        }

        base.OnActionExecuted(filterContext);
    }
}

I realize my changes here are a pretty obvious extension of what was already being done with the ModelState by the code @ the link provided by @bob - but I had to stumble on this thread before I even thought of handling it in this way.


Maybe try

return View("Index");

instead of

return Index();

참고URL : https://stackoverflow.com/questions/279665/how-can-i-maintain-modelstate-with-redirecttoaction

반응형