ServiceStack's JSON反序列化器解析无效JSON

本文关键字:JSON 无效 反序列化 ServiceStack | 更新日期: 2023-09-27 17:52:40

给定无效的JSON文本{ "foo" = "bar" }, ServiceStack内置的JSON反序列化器将成功地将其解码为以下DTO:

public class FooDto {
   public string Foo { get; set; }
}

现在,也许这在某些用例中是可以接受的,因为它看起来有点像c#初始化器,所以可能实际上解析JSON不是这个库的功能。

然而,当给定无效的JSON文本{ "foo" xxx "bar" }时,没有抛出错误,可怕的是Foo属性被设置为"xxx"。

是否有一种方法(a)配置ServiceStack。文本,只解析JSON(而不是默认情况下接受的任何非标准变体),或者(b)用JSON替换序列化器。. NET在应用程序级别?

编辑:它看起来也像ServiceStack的反序列化行为,其web路由代码的行为不同于ServiceState.Text.JsonSerializer的行为,这似乎在无效解析上返回default(T)

EDIT 2 (Progress?):

appHost.SetConfig(new HostConfig { UseBclJsonSerializers = true });

设置此选项将导致ServiceStack对格式错误的JSON返回400 Bad Request,但不幸的是无法将JSON反序列化到给定的DTO。也许这是解决方案的一部分?

解决方案:

将ServiceStack的默认JSON序列化器替换为自定义的"application/JSON"处理程序,该处理程序反过来包装JSON。NET序列化器最终解决了这个问题。我在下面的回答中包含了解决方案代码的副本。

ServiceStack's JSON反序列化器解析无效JSON

wiki文档提到了如何注册自己的自定义媒体类型,这将优先于ServiceStack的内置格式。

你可以注册ServiceStack在你的AppHost中使用不同的序列化器:

this.ContentTypes.Register(MimeTypes.Json, 
    serialize: (IRequest req, object response, Stream stream) => ..., 
    deserialize: (Type type, Stream stream) => ...);  

我最终编写了一个自定义JSON序列化器来包装出色的JSON。网络图书馆。该解决方案在无效JSON上引发异常,因此按预期返回400 Bad Request。

警告:这个实现忽略了Accept-Charset报头以及Content-Type报头的charset参数,而是假设UTF8。如果您不能在网络上使用UTF8,那么您需要调整这段代码。

public class UseJsonDotNet : IPlugin
{
    public JsonSerializerSettings Settings { get; set; }
    public void Register(IAppHost appHost)
    {
        appHost.ContentTypes.Register(
            "application/json",
            WriteObjectToStream,
            ReadObjectFromStream);
    }
    public void WriteObjectToStream(
        IRequest request, object response, Stream target)
    {
        var s = JsonConvert.SerializeObject(response, Formatting.None, Settings);
        using (var writer = new StreamWriter(target, Encoding.UTF8, 1024, true))
        {
            writer.Write(s);
        }
    }
    public object ReadObjectFromStream(Type type, Stream source)
    {
        using (var reader = new StreamReader(source, Encoding.UTF8))
        {
            var s = reader.ReadToEnd();
            var o = JsonConvert.DeserializeObject(s, type, Settings);
            return o;
        }
    }
}

要使用它,只需注册它:

Plugins.Add(new UseJsonDotNet { Settings = ... } );

看看JsConfig类。它有一些有用的配置,但我不确定你会找到你想要的。有JsConfig.ThrowOnDeserializationError,你可以设置为true(我不知道如果默认值是false),看看它会如何表现。