1

MonoDroid プロジェクトで Json シリアライゼーション/デシリアライゼーションに ServiceStack を使用しようとしています。

MonoDroid 環境で実行する ServiceStack を構築しましたが、JSON の逆シリアル化に問題があります。

コード例:

public class Track
{
        public string Id { get; set; }
        public string Title { get; set; }
        public string Artist { get; set; }
        public string Hash { get; set; }
        public string Type { get; set; }
    }
}
...
var track = new Track { Id = "1", Artist = "artist name", Hash = "654874", Title = "song title", Type = "mp3", };
var json = ServiceStack.Text.JsonSerializer.SerializeToString(track);
var track1 = ServiceStack.Text.JsonSerializer.DeserializeFromString<Track>(json);

逆シリアル化で例外があります: Unhandled Exception:

System.ArgumentNullException: Argument cannot be null.
Parameter name: method

スタックトレース:

[External Code] 
0x5E in ServiceStack.Text.Json.JsonReader.GetParseFn at [...]\Android\ServiceStack.Text\src\ServiceStack.Text\Json\JsonReader.Generic.cs:36 C#
0x2 in ServiceStack.Text.Json.JsonTypeSerializer.GetParseFn at [...]\Android\ServiceStack.Text\src\ServiceStack.Text\Json\JsonTypeSerializer.cs:283 C#
0xF in ServiceStack.Text.Common.TypeAccessor.Create at [...]\Android\ServiceStack.Text\src\ServiceStack.Text\Common\DeserializeType.cs:146  C#
0x142 in ServiceStack.Text.Common.DeserializeType`1[[ServiceStack.Text.Json.JsonTypeSerializer, ServiceStack.Text, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].GetParseMethod at [...]\Android\ServiceStack.Text\src\ServiceStack.Text\Common\DeserializeType.cs:60 C#
0x43A in ServiceStack.Text.Common.JsReader`1[[ServiceStack.Text.Json.JsonTypeSerializer, ServiceStack.Text, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].GetParseFn at [...]\Android\ServiceStack.Text\src\ServiceStack.Text\Common\JsReader.cs:100  C#
0x6 in ServiceStack.Text.Json.JsonReader`1[[Database.Models.Track, AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]..cctor at [...]\Android\ServiceStack.Text\src\ServiceStack.Text\Json\JsonReader.Generic.cs:58  C#
0x1B in ServiceStack.Text.JsonSerializer.DeserializeFromString at [...]\Android\ServiceStack.Text\src\ServiceStack.Text\JsonSerializer.cs:33    C#

私が見るように:

var genericType = typeof(JsonReader<>).MakeGenericType(type);
var mi = genericType.GetMethod("GetParseFn", BindingFlags.Public | BindingFlags.Static);
parseFactoryFn = (ParseFactoryDelegate)Delegate.CreateDelegate(typeof(ParseFactoryDelegate), mi);

genericType は「ServiceStack.Text.Json.JsonReader`1[System.String]」 タイプは「System.String」

したがって、「mi」変数はnullです

それを修正する方法、またはどこを見るべきかについてのアイデアはありますか?

ありがとう。

4

1 に答える 1

5

ここでの問題は、ビルド構成でリンクGetParseFn()が有効になっていて、明示的に参照されていなかったため、メソッドがリンクされていたことです。

リンカーは、Mono for Android のビルド プロセスの一部として含まれている静的分析ツールです。コンパイルされたアプリケーションをスキャンし、明示的に参照されていない .NET (この場合はコンパイル済みの ServiceStack クラス ライブラリ) を実際に取り除きます。これはアプリケーションのサイズを大幅に削減するのに役立ちますが、ここに示すように問題が発生する可能性があります。メソッドが明示的に参照されることはなかったGetParseFn()(リフレクション経由で呼び出された) ため、リンカはそれが必要であることを認識せず、リンクしてしまいました。

今後、この問題を処理する方法はいくつかあります。

  1. リンクを完全に無効にする: プロジェクトのプロパティでリンクをオフにすることができます。一般に、デバッグ ビルドではオフのままにし、リリース ビルドではオンにする方が簡単です。もちろん、リリースビルドを計画している場合、これは明らかに完全な解決策ではありません。
  2. SDK アセンブリのみをリンクする: このオプションは、.NET BCL および Android SDK でのみ動作するようにリンカーに指示し、ライブラリはそのままにします。
  3. Use PreserveAttribute: この属性を使用すると、明示的に参照されていなくても、必要であることがわかっている特定の部分を残すようにリンカーに指示できます。ServiceStack は外部ライブラリであり、独自のものではないため、この場合、これはおそらく最善の解決策ではありません。
  4. Use Linkskip : このオプションを使用すると、リンカーが触れてはならない特定のアセンブリを指定できます。これにより、リンカーをオンのままにし、必要に応じて単にオプトアウトすることができます。

個人的には、ここでのあなたの状況では、Linkskip ルートに進むことをお勧めします。リンカーのすべての利点を引き続き得ることができますが、このような問題を回避するために ServiceStack を無視します。プロジェクト ファイルでは、次のような内容になります。

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <AndroidLinkMode>Full</AndroidLinkMode>
    <AndroidLinkSkip>ServiceStack.Text</AndroidLinkSkip>
</PropertyGroup>
于 2012-04-20T13:21:11.590 に答える