1

在 JsonValueProviderFactory 的默认实现中,使用了 JavaScriptSerializer.DeserializeObject() 方法。如果 json 字符串格式错误,此方法将引发异常。然后服务器向浏览器抛出一个 500 黄页。我想抑制异常并通过我的控制器操作显示自定义错误消息。

这是我尝试过的。我删除了默认的 JsonValueProviderFactory 并引入了一个具有基本相同代码的自定义 JsonValueProviderFactory。唯一的区别在于我在 GetDeserializedObject 方法中引入了一个 try-catch 块。

private static object GetDeserializedObject(ControllerContext controllerContext)
    {
        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
        {
            // not JSON request
            return null;
        }

        StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
        string bodyText = reader.ReadToEnd();
        if (String.IsNullOrEmpty(bodyText))
        {
            // no JSON data
            return null;
        }

        JavaScriptSerializer serializer = new JavaScriptSerializer();
        object jsonData = null;
        try
        {
            jsonData = serializer.DeserializeObject(bodyText);
        }
        catch (Exception ex) {
            ex.Data["jsonString"] = bodyText;
            throw;
        }
        return jsonData;
    }

我不想简单地抛出异常,而是想将异常错误消息传递给模型绑定器,并最终将其设置在模型状态字典中。然后我可以在控制器操作中读取模型状态字典并自定义发送到浏览器的错误消息。这可以做到吗?如果做不到,是否有其他方法可以实现相同的目标?

4

2 回答 2

0

这个我没试过,你可以试试

controllerContext.ParentActionViewContext.ViewData.ModelState.AddModelError
于 2012-07-19T13:10:02.683 回答
0

我终于找到了正确的方法。我正在记录它以供其他人将来参考。

controllerContext.Controller.ViewData.ModelState.AddModelError("improper json", ex)

这正是modelbinder的modelbindingContext中的modelstate是如何设置的。我从 MVC3 源代码中复制了相关的代码片段。该方法存在于 ControllerActionInvoker.cs 中。

 protected virtual object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) {
        // collect all of the necessary binding properties
        Type parameterType = parameterDescriptor.ParameterType;
        IModelBinder binder = GetModelBinder(parameterDescriptor);
        IValueProvider valueProvider = controllerContext.Controller.ValueProvider;
        string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
        Predicate<string> propertyFilter = GetPropertyFilter(parameterDescriptor);

        // finally, call into the binder
        ModelBindingContext bindingContext = new ModelBindingContext() {
            FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix == null), // only fall back if prefix not specified
            ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, parameterType),
            ModelName = parameterName,
            ModelState = controllerContext.Controller.ViewData.ModelState,
            PropertyFilter = propertyFilter,
            ValueProvider = valueProvider
        };

        object result = binder.BindModel(controllerContext, bindingContext);
        return result ?? parameterDescriptor.DefaultValue;
    }
于 2012-07-23T10:41:28.317 回答