我有一个控制器操作,其中应用了一个属性,如果ModelState有错误,它会将它们设置为JsonResult
方法中的OnResultExecuting
。
我在MyAction
中设置了值。我在OnResultExecuting
中的属性中更改它,但在控制器中的OnResultExecuted
中,结果是控制器中的结果,而不是属性中设置的结果。
所以我的问题是为什么OnResultExecuted
中的值保持不变,我如何让它停止这样做?
public class MyController:Controller
{
[ValidateDatedObject(SkipActionExecution = true, LeaveJustModelState = true)]
public JsonResult MyAction(ViewModel viewModel)
{
return new JsonResult { Data = new { Success = false }}; // Setting the initial value
}
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);//filterContext.Result here is the on from the controller instead of the one from the attribute
}
}
public class ValidateDatedObject : ModelValidationFilter
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
base.OnResultExecuting(filterContext);
}//filterContext.Result here is the one from the attribute
}
public abstract class ModelValidationFilter : ActionFilterAttribute
{
private JsonResult getModelStateAsJsonResult(ModelStateDictionary modelState)
{
return new JsonResult { Data = new { modelState = SerializeErrors(modelState) } };
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.Result = getModelStateAsJsonResult(filterContext.Controller.ViewData.ModelState); //Setting filterContext.Result here
}
}
答案 0 :(得分:4)
那是因为在OnResultExecuting
中你用新实例替换当前结果。这将修改ResultExecutingContext
中的结果,但会保持整体结果不变。
然而,您可以修改结果而不是替换它
public abstract class ModelValidationFilter : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
//Modify the values in the current filterContext.Result instead of replacing it with a new instance
var jsonResult = filterContext.Result as JsonResult;
if(jsonResult == null) return;
//possibly replace Data only under certain conditions
jsonResult.Data = new { modelState = SerializeErrors(modelState) };
}
}
原因是MVC执行ResultFilters的方式。您可以查看ControllerActionInvoker.InvokeActionResultFilterRecursive
的实施情况。这是在每个过滤器上调用OnResultExecuting
的代码,执行操作,然后以相反的顺序调用OnResultExecuted
。
如果仔细观察,您会注意到ResultExecutedContext
是通过对原始actionResult对象的引用创建的,而不是对ResultExecutingContext.Result
的引用。 (除非你设置ResultExecutingContext.Cancel=true
将停止处理其他过滤器并返回它当时的结果,但这也意味着控制器OnResultExecute将不会被执行)
因此,在此代码中假设ResultFilters可以修改ResultExecutingContext.Result
中属性的值,但不能完全用新实例替换它。