如何在同时转义特殊字符的情况下序列化List<object>?

3
我们有一个非常大的List<object>,我们将其转换为JSON字符串,然后发送到存储过程。为了简化本文,让我们假设该对象看起来像这样:
public class Customer
{
    public string Name { get; set; }
}

其中一个客户是“Bob的修理店”。当包含此值的列表进行序列化时,它将包含以下内容:

{
    "Name": "Bob's Repair Shop"
}

在我们想要将这个 JSON 发送到存储过程时,情况就不那么好了。当它到达存储过程时,单引号会抛出错误(我理解这一点)。

最初,我们通过在 C# 代码中对 json 字符串执行 .replace("'", "~") 操作,然后在存储过程中执行反向操作来处理此问题。那段时间还行。但是现在我们遇到的问题是,我们要处理一些复杂得多的 List<> 中的对象,并且列表中有数十万条记录。当 json 字符串变得很大时,.replace("'", "~") 就会抛出一个 Out of Range 异常。 而且,让我们诚实面对吧,这种方法本质上只是一个 hack。

我希望能找到一种序列化我们的 List<object> 的方法,以使在序列化过程中转义单引号。 这可能吗?如果可以,怎么做呢?

编辑:

我真的应该最开始就说这个。我错过了。下面是存储过程接收 JSON 字符串的方式:

ALTER PROCEDURE [dbo].[name_of_proc]
    @jsonString NVARCHAR(MAX)
AS

然后,我们使用 OPENJSON@jsonString 转换为表变量。

编辑 2:

存储过程的调用方式:

    public void UpdateBulk(List<object> myObject)
    {
        string json = Newtonsoft.Json.JsonConvert.SerializeObject(myObject);
        json.replace("'", "~");
        var dParam = new DynamicParameters();
        dParam.Add("@jsonString", json);
        QuerySP<myObject>("name_of_proc", dParam);
    }

    protected IEnumerable<T> QuerySP<T>(string storedProcedure, object param = null)
    {
        using (var db = this.Context)
        {
            var output = db.Query<T>(storedProcedure, param: param, commandType: CommandType.StoredProcedure,commandTimeout: 32767);
            return output;
        }
    }

编辑3: 被指向的线程可能是一个重复问题,它询问如何更改这个:

{"key" : "value"}

转换为:

{'key' : 'value'}

那不是我问的问题。我问如何更改这个:

{
    "Name": "Bob's Repair Shop"
}

变为:

{
    "Name": "Bob\'s Repair Shop"
}

7
你是否没有使用SQL参数将JSON发送到存储过程中? - user47589
3
你应该(始终!)使用SqlParameters:https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.parameters - Peter B
3
这是存储过程收到它的方式。你是怎样将 JSON 发送给存储过程的呢?你是用 exec sprocname '<my json>' 吗?如果是这样,那么你没有使用 SQL 参数将数据传递给数据库。我试图看看当你将单引号作为参数传递时它怎样导致错误。 - user47589
3
我的直觉是你传递JSON给存储过程的某个方面是不正确的。如果正确地作为参数传递,单引号不应该成为问题。也许我错了,但我有信心那里存在问题。 - user47589
2
@EJoshuaS,我不认为这是重复的问题。那个问题是关于用单引号而不是双引号括起键和值。而这个问题是关于在值中转义单引号。 - steve16351
显示剩余28条评论
1个回答

4
您可以添加一个自定义的JSON转换器,在序列化过程中对单个字符串实例进行替换。这仍然使用了string.Replace,但此时所有字符串实例应该都很小。
public class EscapeQuotes : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string);
    }

    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 escapedValue = ((string)value).Replace("'", "\\'");
        writer.WriteValue(escapedValue);
    }
}

使用方法:

Customer myObject = new Customer() { Name = "Bob's repair shop" };
var output = JsonConvert.SerializeObject(myObject, new EscapeQuotes());

输出结果:

{"名称": "Bob的修车店"}


太棒了,Steve!我真的很感激你回答我的问题。太好了。事实证明,JSON 不是问题所在。我还不知道是什么问题,但无论如何,我都很感激。 - Casey Crookston

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接