从 POST 方法返回 JSON 时出现“无法转换 Unicode 字符 uD83C”错误 asp.net
本文关键字:字符 Unicode 无法转换 uD83C net asp 错误 转换 JSON 返回 方法 | 更新日期: 2023-09-27 17:56:26
我在MVC项目中开发了一个Web api。我在我的 post 方法中返回一个 JToken 对象。通常我的 api 工作正常,但有时在特定数据中我会收到此错误:
"Message": "An error has occurred.",
"ExceptionMessage": "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": null,
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Unable to translate Unicode character ''uD83C
at index 411 to specified code page."
这是我的发布方法
public JToken Post([FromBody]Classes.Search search)
{
Classes.ReturnSearch returnSearch = new Classes.ReturnSearch();
try
{
string con = System.Configuration.ConfigurationManager.ConnectionStrings["TConnectionString"].ConnectionString;
SqlConnection cn = new SqlConnection(con);
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter("SP_Searchi", cn);
sqlDataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
sqlDataAdapter.SelectCommand.Parameters.Add(new SqlParameter("@word", search.word));
sqlDataAdapter.SelectCommand.Parameters.Add(new SqlParameter("@num", search.num));
DataSet d = new DataSet();
sqlDataAdapter.Fill(d);
DataTable table = d.Tables[0];
foreach(DataRow row in table.Rows)
{
string result=row[1].ToString();
returnSearch.search_items.Add(new Classes.SearchItem(row[0].ToString(), row[1].ToString(),search.word));
}
returnSearch.status = "Success";
return JObject.Parse(JsonConvert.SerializeObject(returnSearch));
}
catch (Exception e)
{
returnSearch.status = "Failed";
returnSearch.search_items = null;
ValuesController.Log("Error in Search: "+e.Message);
return JObject.Parse(JsonConvert.SerializeObject(returnSearch));
}
}
有什么问题?!
这是一个
表情符号修饰符。您可能会在解析输入的表情符号(可以拆分为多个''u####实例)后看到它。
您的问题是U+D83C
不是一个有效的 unicode 字符,但它以某种方式进入了 returnSearch
对象中的一个字符串。 然后随后 asp.net-mvc 框架抛出一个异常,试图将这样的字符编码为 utf-8。
您需要做的是确定此角色如何进入您的returnSearch
结果并解决该潜在问题。 由于您已经在手动将返回的结果转换为 JObject
,为了使调试更容易,您可以使用以下转换器将所有字符串测试编码为 utf-8 并在出现问题时抛出异常:
public class EncodingValidatingStringConverter : JsonConverter
{
readonly Encoding encoding;
public EncodingValidatingStringConverter()
: this(Encoding.GetEncoding(Encoding.UTF8.CodePage, new EncoderReplacementFallback("?"), new DecoderExceptionFallback()))
{
}
public EncodingValidatingStringConverter(Encoding encoding)
{
if (encoding == null)
throw new ArgumentNullException();
this.encoding = encoding;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(string);
}
public override bool CanRead { get { return false; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var s = (string)value;
var bytes = encoding.GetBytes(s);
var sFixed = encoding.GetString(bytes);
writer.WriteValue(sFixed);
}
}
然后修改您的Post()
方法以捕获和记录EncoderFallbackException
并根据需要处理问题。 例如,以下版本的方法在日志记录后将无效字符替换为?
字符:
try
{
// Fill in the returnSearch
// Convert to JObject and return
var settings = new JsonSerializerSettings
{
Converters = new[] { new EncodingValidatingStringConverter(Encoding.GetEncoding(Encoding.UTF8.CodePage, new EncoderExceptionFallback(), new DecoderExceptionFallback())) },
};
return JObject.FromObject(returnSearch, JsonSerializer.CreateDefault(settings));
}
catch (EncoderFallbackException ex)
{
// Log the encoding error for debugging:
ValuesController.Log("Encoding exception:'n" + ex.ToString());
// You could log the search parameters or entire search_items list as well if desired.
// Return whatever seems most advisable, e.g. replacing the bad character with a fallback if preferred.
var settings = new JsonSerializerSettings
{
Converters = new[] { new EncodingValidatingStringConverter(Encoding.GetEncoding(Encoding.UTF8.CodePage, new EncoderReplacementFallback("?"), new DecoderExceptionFallback())) },
};
return JObject.FromObject(returnSearch, JsonSerializer.CreateDefault(settings));
}
catch (Exception ex)
{
returnSearch.status = "Failed";
returnSearch.search_items = null;
ValuesController.Log("Error in Search: " + ex.Message);
var settings = new JsonSerializerSettings
{
Converters = new[] { new EncodingValidatingStringConverter(Encoding.GetEncoding(Encoding.UTF8.CodePage, new EncoderReplacementFallback("?"), new DecoderExceptionFallback())) },
};
return JObject.FromObject(returnSearch, JsonSerializer.CreateDefault(settings));
}
请注意,对每个字符串进行测试编码会对性能产生负面影响,因此修复基础问题后,应删除此解决方法。
顺便说一句,与其JObject.Parse(JsonConvert.SerializeObject(returnSearch))
,不如JObject.FromObject(returnSearch)
.此方法直接写入没有中间字符串表示形式的JToken
层次结构,因此应该具有更好的性能。