从asp.net POST方法返回JSON时“无法转换Unicode字符\\ uD83C”错误

时间:2016-07-10 19:42:14

标签: c# asp.net-mvc post unicode json.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));
        }


    }

有什么问题?!

2 个答案:

答案 0 :(得分:2)

这是表情符号修饰符。您可能在解析输入的表情符号后可能会看到它(可以将其拆分为多个\ u ####实例)。

答案 1 :(得分:1)

你的问题是U+D83C is not a valid unicode character以某种方式进入returnSearch对象中的一个字符串。然后,asp.net-mvc框架抛出异常,试图将这样的字符编码为utf-8。

您需要做的是确定此角色如何进入returnSearch结果并解决潜在问题。由于您已经手动将返回的结果转换为JObject,为了使调试更容易,您可以将所有字符串测试编码为utf-8,并在出现问题时抛出异常,使用以下转换器: / p>

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)) JToken而不是function WebUI() { this.updateLoadingMessage = function (message) { $("#loading-header").html(message); }; addAlertInfo = function (message) { }; addAlertWarning = function (message) { }; addAlertDanger = function (message) { }; addAlertSuccess = function (message) { }; }; 。此方法直接写入WebUI.addAlertInfo("testing"); 层次结构而没有中间字符串表示,因此应具有更好的性能。