2013-06-13 1 views
0

с помощью Ben Foster Automatic Validate Model State У меня есть этот код:ASP.NET MVC Done Right: ValidateModelState теряет параметры запроса с использованием ValidateModelStateAttribute

[ImportModelStateFromTempData] 
public ActionResult Edit(int id, int otherProperty) { 
    // ... 
    return View() 
} 

[HttpPost,ValidateModelState] 
public ActionResult Edit(int id, PaymentOrderCreateUpdateCommand order) { 
    // ... 
    return RedirectToAction("Index", new {otherProperty = order.otherProperty} 
} 

Быть на URL:

/Edit/5?otherProperty=4 

Если заполнить некоторые формы, которые после для изменения действия [HttpPost] с недопустимым состоянием модели, ValidateModelState делает это и возвращает запрос на

/Edit/5 

Проблема заключается в следующем: otherProperty = 4, необходимый для генерируемого представления, теряется в Redirect.

Кто-нибудь знает способ изменения атрибута проверки состояния автоматической модели, чтобы он включал в него параметры запроса?

для завершения на вопрос, который я добавить класс ValidateModelStateAttribute:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 
public class ValidateModelStateAttribute : ModelStateTempDataTransfer { 
    public override void OnActionExecuting(ActionExecutingContext filterContext) { 
     if (!filterContext.Controller.ViewData.ModelState.IsValid) { 
      if (filterContext.HttpContext.Request.IsAjaxRequest()) { 
       ProcessAjax(filterContext); 
      } else { 
       ProcessNormal(filterContext); 
      } 
     } 

     base.OnActionExecuting(filterContext); 
    } 

    protected virtual void ProcessNormal(ActionExecutingContext filterContext) { 
     // Export ModelState to TempData so it's available on next request 
     ExportModelStateToTempData(filterContext); 

     // redirect back to GET action 
     filterContext.Result = new RedirectToRouteResult(filterContext.RouteData.Values); 
    } 

    protected virtual void ProcessAjax(ActionExecutingContext filterContext) { 

     var errors = filterContext.Controller.ViewData.ModelState.ToSerializableDictionary(); 
     var json = new JavaScriptSerializer().Serialize(errors); 
     // send 400 status code (Bad Request) 
     filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
     filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; 
     filterContext.HttpContext.Response.StatusDescription = "Invalid Model State"; 
     filterContext.Result = new ContentResult() { Content = json }; 
    } 
} 
+0

Не является поклонником этого подхода: 1. Он нарушает разделение проблем, поскольку часть цели контроллера заключается в том, чтобы обрабатывать такие вещи, как проверка модели. 2. Это отлаживает кошмар. – Maess

+0

Я поклонник такого подхода: D –

ответ

0

добавив это в ProcessNormal:

// add query string values. 
var qs = filterContext.HttpContext.Request.QueryString; 
foreach (string key in qs.Keys) { 
    filterContext.RouteData.Values.Add(key, qs.Get(key)); 
} 

выглядит как это делает трюк. Я не уверен, что это нормально или может быть проблемой.

0

Вы также можете использовать RouteValues ​​вместо параметров запроса и соответственно изменить свои маршруты. Например:

routes.MapRoute(
      name: "", 
      url: "{controller}/{action}/{id}/{p1}", 
      defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional,p1 = UrlParameter.Optional } 
     ); 

Таким образом, вы можете Получать Ид и p1 параметры. Используя вашу настройку [ValidateModelState], важно помнить, что вам необходимо передать параметры запроса с помощью routeArgument. Если вы используете @ Html.HiddenFor, они не будут в строке запроса.