在Azure函数中序列化 [英] Serializing in Azure Function

查看:140
本文介绍了在Azure函数中序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Azure Function应用程序遇到了一个奇怪的问题. Newtonsoft Json.NET反序列化不喜欢$type批注.我的反序列化代码如下:

I'm running into a strange issue with Azure Function Apps. Newtonsoft Json.NET deserialization is not liking the $type annotations. My deserialization code looks like:

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.

如您所见,类型似乎是相同的.此代码在本地经过了良好的测试,可以正常工作.不管我删除了多少,在Azure中遇到的第一个$type注释都将失败.

As you can see, the types appear to be identical. This code is well tested locally and works as expected. It will fail in Azure on the first $type annotation encountered, regardless of how many I remove.

我想继续使用注释,因为我需要它们来反序列化从抽象类派生的对象.

I would like to keep using the annotations, as I need them for deserializing objects derived from an abstract class.

这是在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"可以引用它.有任何想法吗?非常感谢.

This is compiled in x64, .NET 4.7, Json.NET v10.0.3, Azure Function Apps v1.0.11027.0 (~1). I have the Newtonsoft.Json.dll file in the bin folder, with #r "Newtonsoft.Json.dll" to reference it. Any ideas? Much appreciated.

我还尝试过添加一个类似于以下内容的project.json文件:

I have also tried adding a project.json file looking like:

{
  "frameworks": {
    "net47":{
      "dependencies": {
        "Newtonsoft.Json": "10.0.3"
      }
    }
   }
}

已成功安装.我删除了我上传的程序集文件,并导入了#r.现在的错误是:

which successfully installed. I removed the assembly file I uploaded, and the #r import. The error is now:

2017-08-01T18:30:18.971 Error resolving type specified in JSON 'Trading.Control.Json.TradingConfig, Trading'. Path '$type', line 2, position 56.

我怀疑存在基本名称空间"或某种类似的查找错误.

I suspect there is a "base namespace" or somesuch lookup error.

该函数的文件系统如下所示:/site/wwwroot/TimerTriggerCSharp3/在bin文件夹中具有程序集.它们都装有#r导入文件,效果很好.

The filesystem of the function looks like: /site/wwwroot/TimerTriggerCSharp3/ with assemblies in a bin folder. They are all loaded with #r imports, which work fine.

推荐答案

我遇到了同样的问题,并使用SerializationBinder解决了它.发生这种情况是由于函数运行时

I had the same problem and resolved it using a SerializationBinder. It happens because of the load context of assemblies loaded by the function runtime

下面的代码让您采用一个任意的程序集名称并对其进行解析.您可以将其与序列化设置一起传递.因此,您可以检查交易程序集.在班级上的注释,说明为什么有必要

The below code let's you take an arbitrary assembly name and resolve it. You can pass it in with the serialization settings. So you could check for the trading assembly. The the comment on the class for why it's necessary

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);
    }
}

`

这篇关于在Azure函数中序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆