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序列化器最终解决了这个问题。我在下面的回答中包含了解决方案代码的副本。
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
),看看它会如何表现。