2017-08-01 12 views
1

Azure Function Appsで奇妙な問題が発生しています。 Newtonsoft Json.NETの逆シリアル化では$type注釈が好きではありません。 JSONがどのように見えるAzure関数でシリアライズ

return JsonConvert.DeserializeObject<T>(json, new JsonSerializerSettings { 
    TypeNameHandling = TypeNameHandling.Auto 
}); 

{ 
    "$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. 

のように私のデシリアライゼーションコードが見えます見ることができる、タイプはidenticaと思われるl。このコードはローカルで十分にテストされており、期待どおりに動作します。何度削除しても、最初の$typeアノテーションでAzureでエラーが発生します。

抽象クラスから派生したオブジェクトを逆シリアル化するために必要なので、私は注釈を使い続けたいと思います。

これはx64、.NET 4.7、Json.NET v10.0.3 Azure Function Apps v1.0.11027.0(〜1)でコンパイルされています。私はそれを参照するために#r "Newtonsoft.Json.dll"と、binフォルダにNewtonsoft.Json.dllファイルがあります。何か案は?とても有難い。

編集:

正常にインストール
{ 
    "frameworks": { 
    "net47":{ 
     "dependencies": { 
     "Newtonsoft.Json": "10.0.3" 
     } 
    } 
    } 
} 

: は、私はまた、のように見えるproject.jsonファイルを追加しようとしています。アップロードしたアセンブリファイルを削除し、#rをインポートしました。エラーは次のようになりました。

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

「ベースネームスペース」または一部のルックアップエラーが疑われます。

このファイルシステムのファイルシステムは、/site/wwwroot/TimerTriggerCSharp3/のようにbinフォルダ内にあります。それらはすべて、#rの読み込みで読み込まれ、正常に動作します。

+0

動作させるために、この部分を変更しなければなりませんでした。アプリサービスエディタをチェックして、そこから機能アプリファイルシステム構造の説明を追加してください。自分で組み立てているアセンブリをやっていますか? – Jeff

+0

また、csxまたはプリコンパイルされた関数dllを使用していますか? – Jeff

+0

@Jeff私はcsxを使用しています。自分のアセンブリを読み込んでいましたが、project.jsonファイルを追加した後でファイルとインポートを削除しました。私は今、別のエラー(上に更新)を取得しています。 – Osan

答えて

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

`

0

Newtonsoft.Json NuGetパッケージは自動的にランタイムによって参照されている必要があります理由のクラスにコメント。手動で行うべきではありません。そうしないと、バージョンの競合が発生する可能性があります。ちょうど

#r "Newtonsoft.Json" 

これで問題が解決しない場合は、C#クラスを含め、問題を完全に再現するための最小限の例を投稿してください。

+0

これは役に立ちません。これは、json .netのアセンブリ解決とAzure関数のランタイムとの間に固有の非互換性です。 – Jeff

0

は、それはあなたが最も可能性の高いロードされたDLLの2つのコピーを持っている

      if (num1 == 0) 
          { 
           var typeArgumentName = SplitFullyQualifiedTypeName(typeName.Substring(startIndex, index - startIndex)); 
           typeList.Add(Type.GetType(typeArgumentName)); 
          }