背景
最近遇到一个Json串反序列化失败,提示“使用 JSON JavaScriptSerializer 进行序列化或反序列化时出错。字符串的长度超过了为 maxJsonLength 属性设置的值”。
配置文件中Web.Config设置“<jsonSerialization maxJsonLength=2147483647”很遗憾设置了依然无效。
提供的接口接收Json字符串直接序列化实体。但json字符串中会有图片base64(可能多张图片),Json字符串如下:
//参数picture是base64格式
{
"PictureInfo": [
{
"creationDate": "2023-12-17 10:37:04",
"extendName": "jpg",
"id": "xxxxxxx",
"picture": "/9j/4*****3Vb/apNy71XYi/w/N/D/wKiigo/9k=",
},
{
"creationDate": "2023-12-17 10:37:04",
"extendName": "jpg",
"id": "xxx",
"picture": "/9j/*****A01JGRQ+3apZsbn+bePWiiiJJ//9k=",
}
],
"orderNumber": "xxxxx"
}
实体类
public class OrderInfo
{
public List<PictureInfo> PictureInfo { get; set; }
public string orderNumber { get; set; }
}
public class PictureInfo {
public string id { get; set; }
public DateTime creationDate { get; set; }
public string extendName { get; set; }
/// <summary>
/// base64格式
/// </summary>
public string picture { get; set; }
}
public class ResultJson
{
public int code { get; set; }
public string msg { get; set; }
}
Post方法
对于ClientPost一个Json回Server,网上说post请求没有限制参数大小,但在如下方法中就直接不进入该方法,给用户直接返回错误信息:“Internal Server Error”。
.NET 会根据接收到的Json字符串自动序列化成实体OrderInfo,运用的是.Net自带的序列化方法,会有一些缺陷导致失败。
[System.Web.Http.HttpPost]
public JsonResult SavePicture(OrderInfo orderInfo)
{ try
{
ResultJson result = new ResultJson();
foreach (PictureInfo item in OrderInfo.PictureInfo)
{
//用运单号+时间流水为图片命名,存储图片到指定路径
if (!string.IsNullOrWhiteSpace(item.picture))
{
string filePath = "/Picture/";
string fileName = orderInfo.orderNumber + "-" + item.id + "-" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpeg";
byte[] imageByte = Convert.FromBase64String(item.picture);
using (MemoryStream memoryStream = new MemoryStream(imageByte))
{
Bitmap bmp = new Bitmap(memoryStream);
if (!Directory.Exists(Server.MapPath(filePath)))
{
Directory.CreateDirectory(Server.MapPath(filePath));
}
//新建第二个bitmap类型的bmp2变量。
Bitmap bmp2 = new Bitmap(bmp, bmp.Width, bmp.Height);
Graphics draw = Graphics.FromImage(bmp2);
draw.DrawImage(bmp, 0, 0);
draw.Dispose();
bmp2.Save(Server.MapPath(filePath + fileName), System.Drawing.Imaging.ImageFormat.Jpeg);
memoryStream.Close();
}
result.code = 1;
result.msg = "图片处理ok";
}
else
{
result.code = -1;
result.msg = "无图片内容!";
}
}
}
catch (Exception ex)
{
result.code = -1;
result.msg = $"图片处理异常:{ex.Message}";
}
}
用户调用接口收到返回信息“Internal Server Error”
org.apache.http.client.HttpResponseException: Internal Server Error
at org.apache.http.impl.client.AbstractResponseHandler.handleResponse(Abstr
at com.kyexpress.open.commons.feign.client.HttpClientService.execute(HttpCl
at com.kyexpress.open.commons.feign.client.HttpClientService.postJson(Httpc
at com.kyexpress.ka.waybill.router.provider.handler.receipt.StandardReceipt
at com.kyexpress.ka.waybill.router.provider.handler,receit.bstractReceipt
at com.kyexpress.ka.waybill.router.provider.handler.receipt.StandardReceipt
at sun.reflect.GeneratedlethodAccessor2153.invoke(Unknown Source)
at sun.reflect.DelegatingMlethodAccessorImpl.invoke (DelegatingllethodAccessor
at java.lang.reflect.Method.invoke(Method.java:498)
解决方案
- 建立Json.Net的ValueProviderFactory,这个类主要就是用于Json字符串的反序列化。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace FileProject.Common.Helper
{
using System.Collections;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Web.Mvc;
using System.Web.Script.Serialization;
public class JsonNetValueProviderFactory : ValueProviderFactory
{
private void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)
{
IDictionary<string, object> d = value as IDictionary<string, object>;
if (d != null)
{
foreach (KeyValuePair<string, object> entry in d)
{
AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
}
return;
}
IList l = value as IList;
if (l != null)
{
for (int i = 0; i < l.Count; i++)
{
AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
}
return;
}
// primitive
backingStore[prefix] = value;
}
private object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.InvariantCultureIgnoreCase))
{
// 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;
}
//接下来的代码是关键,判断content type,如果是json.net,那么就使用Json.Net的反序列化方法,如果不是,那么就使用系统默认的反序列化方法
if (controllerContext.HttpContext.Request.ContentType.StartsWith("application/json.net", StringComparison.InvariantCultureIgnoreCase))
{
//var jsonData = JsonConvert.DeserializeObject<ExpandoObject>(bodyText);
JavaScriptSerializer serializerReq = new JavaScriptSerializer();
serializerReq.MaxJsonLength = int.MaxValue;
var jsonData = serializerReq.Deserialize<ExpandoObject>(bodyText);
return jsonData;
}
else
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.MaxJsonLength = int.MaxValue;
object jsonData = serializer.DeserializeObject(bodyText);
return jsonData;
}
}
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
object jsonData = GetDeserializedObject(controllerContext);
if (jsonData == null)
{
return null;
}
Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
AddToBackingStore(backingStore, String.Empty, jsonData);
return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);
}
private string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
}
private string MakePropertyKey(string prefix, string propertyName)
{
return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;
}
}
}
2、在初始化MVC时替换掉默认的JsonValueProviderFactory。
在Global.asax的Application_Start时,写入以下代码:
namespace FileProject
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// 添加如下代码
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory());
}
}
}
以上Post请求问题就完整解决了~~~~
补充:针对Get请求返回值处理
可以写如下辅助类,直接调用即可~
public static class JsonHelper
{
public static JsonResult MaxJson(object data, JsonRequestBehavior behavior)
{
return MaxJson(data, null, null, behavior);
}
private static JsonResult MaxJson(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
{
JsonResult jsonResult = new JsonResult();
jsonResult.Data = data;
jsonResult.ContentType = contentType;
jsonResult.ContentEncoding = contentEncoding;
jsonResult.JsonRequestBehavior = behavior;
jsonResult.MaxJsonLength = Int32.MaxValue; //设置为int的最大值
return jsonResult;
}
}