在Azure功能中序列化

时间:2017-08-01 18:11:22

标签: c# json serialization json.net azure-functions

我遇到了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个导入,效果很好。

2 个答案:

答案 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)));