在OnResultExecuting中更改filterContext.Result

时间:2015-04-17 07:52:57

标签: c# asp.net-mvc action-filter

我有一个控制器操作,其中应用了一个属性,如果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
    }
}

1 个答案:

答案 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中属性的值,但不能完全用新实例替换它。