从 POST 方法返回 JSON 时"Unable to translate Unicode character \uD83C"错误 asp.net



我在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层次结构,因此应该具有更好的性能。

最新更新