我遇到了Azure功能应用程序的一个奇怪问题。 Newtonsoft Json.NET反序列化不喜欢$type
注释。我的反序列化代码如下:
return JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.Auto
});
json看起来像:
{
"$type": "Trading.Control.Json.TradingConfig, Trading",
"Config": {
"$type": "Trading.Control.Json.Config, Trading",
"Optimize": false
},
"Trading": {
"$type": "System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[Trading.Platforms.Credentials, Trading]], mscorlib",
...
并序列化:
return JsonConvert.SerializeObject(o, new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.All,
Formatting = Formatting.Indented
});
错误是:
2017-08-01T17:32:46.395 Type specified in JSON
'Trading.Control.Json.TradingConfig, Trading, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with
'Trading.Control.Json.TradingConfig, Trading, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Path '$type', line 2, position 56.
如您所见,类型似乎相同。此代码在本地进行了良好测试,并按预期工作。无论我删除多少注释,它都会在遇到的第一个$type
注释中失败。
我想继续使用注释,因为我需要它们来反序列化从抽象类派生的对象。
这是在x64,.NET 4.7,Json.NET v10.0.3,Azure Function Apps v1.0.11027.0(~1)中编译的。我在bin文件夹中有Newtonsoft.Json.dll文件,#r "Newtonsoft.Json.dll"
引用它。有任何想法吗?非常感谢。
编辑: 我还尝试添加一个project.json文件,如下所示:
{
"frameworks": {
"net47":{
"dependencies": {
"Newtonsoft.Json": "10.0.3"
}
}
}
}
成功安装。我删除了上传的程序集文件和#r
导入。错误现在是:
2017-08-01T18:30:18.971 Error resolving type specified in JSON 'Trading.Control.Json.TradingConfig, Trading'. Path '$type', line 2, position 56.
我怀疑有一个&#34;基本命名空间&#34;或者某些查找错误。
该函数的文件系统如下:/site/wwwroot/TimerTriggerCSharp3/
,bin文件夹中有程序集。它们都加载了#r
个导入,效果很好。
答案 0 :(得分:3)
我遇到了同样的问题并使用SerializationBinder解决了它。这是因为函数运行时加载的程序集的加载上下文
以下代码让您获取任意程序集名称并解决它。您可以使用序列化设置传入它。所以你可以检查交易大会。关于为何必要的课程的评论
a => a.GetName().Name == "Trading" ? typeof(Trading.Control.Json.TradingConfig).Assembly : null;
/// <summary>
/// Uses the func to resolve assembly instances by name, since they may be in a different directory and not
/// directly resolvable by Assembly.Load (the default method used by JSON.NET)
/// </summary>
internal class SerializationBinder : DefaultSerializationBinder
{
private readonly Func<string, Assembly> assemblyResolver;
public SerializationBinder(Func<string, Assembly> assemblyResolver)
{
this.assemblyResolver = assemblyResolver;
}
public override Type BindToType(string assemblyName, string typeName)
{
Assembly assembly;
try
{
assembly = assemblyResolver(assemblyName);
}
catch
{
// not registered
return base.BindToType(assemblyName, typeName);
}
var type = assembly.GetType(typeName);
if (type == null)
type = GetGenericTypeFromTypeName(typeName, assembly);
if (type != null) return type;
return base.BindToType(assemblyName, typeName);
}
/// <summary>
/// From DefaultSerializationBinder.
/// </summary>
/// <param name="typeName"></param>
/// <param name="assembly"></param>
/// <returns></returns>
private Type GetGenericTypeFromTypeName(string typeName, Assembly assembly)
{
Type type1 = null;
var length = typeName.IndexOf('[');
if (length >= 0)
{
var name = typeName.Substring(0, length);
var type2 = assembly.GetType(name);
if (type2 != null)
{
var typeList = new List<Type>();
var num1 = 0;
var startIndex = 0;
var num2 = typeName.Length - 1;
for (var index = length + 1; index < num2; ++index)
switch (typeName[index])
{
case '[':
if (num1 == 0)
startIndex = index + 1;
++num1;
break;
case ']':
--num1;
if (num1 == 0)
{
typeName = SplitFullyQualifiedTypeName(typeName.Substring(startIndex, index - startIndex));
return Type.GetType(typeName);
}
break;
}
type1 = type2.MakeGenericType(typeList.ToArray());
}
}
return type1;
}
/// <summary>
/// From Reflectionutils
/// </summary>
/// <param name="fullyQualifiedTypeName"></param>
/// <returns></returns>
private static string SplitFullyQualifiedTypeName(string fullyQualifiedTypeName)
{
var assemblyDelimiterIndex = GetAssemblyDelimiterIndex(fullyQualifiedTypeName);
string typeName;
if (assemblyDelimiterIndex.HasValue)
typeName = Trim(fullyQualifiedTypeName, 0, assemblyDelimiterIndex.GetValueOrDefault());
else
typeName = fullyQualifiedTypeName;
return typeName;
}
/// <summary>
/// From Reflectionutils
/// </summary>
/// <param name="fullyQualifiedTypeName"></param>
/// <returns></returns>
private static int? GetAssemblyDelimiterIndex(string fullyQualifiedTypeName)
{
var num = 0;
for (var index = 0; index < fullyQualifiedTypeName.Length; ++index)
switch (fullyQualifiedTypeName[index])
{
case ',':
if (num == 0)
return index;
break;
case '[':
++num;
break;
case ']':
--num;
break;
}
return new int?();
}
private static string Trim(string s, int start, int length)
{
if (s == null)
throw new ArgumentNullException();
if (start < 0)
throw new ArgumentOutOfRangeException("start");
if (length < 0)
throw new ArgumentOutOfRangeException("length");
var index = start + length - 1;
if (index >= s.Length)
throw new ArgumentOutOfRangeException("length");
while (start < index && char.IsWhiteSpace(s[start]))
++start;
while (index >= start && char.IsWhiteSpace(s[index]))
--index;
return s.Substring(start, index - start + 1);
}
}
`
答案 1 :(得分:0)
必须更改此部分才能使其正常工作
DataTable dt = (DataTable)JsonConvert.DeserializeObject(YourJsonHere, (typeof(DataTable)));