如何在MonoTouch中使用Protobuf-Net?

时间:2011-10-28 11:40:40

标签: xamarin.ios protobuf-net

有没有人真的设法完成这个?

我尝试了建议here的方法,但无论我如何生成预编译的序列化程序,mtouch都无法将其复制到app bundle,从而导致运行时异常。我认为这是因为生成的二进制文件可能与MonoTouch不兼容。

我尝试了以下内容:

1)我使用最新提供的iO和Mono二进制文件(此时为r450)构建,以生成预编译的序列化程序。

2)我使用源代码生成两个不同的程序集,为MonoTouch构建。第一个程序集使用符号FEAT_SAFE; MONOTOUCH; NO_RUNTIME构建,第二个程序集使用符号FEAT_SAFE; MONOTOUCH; FEAT_COMPILER构建。我已经定义了符号MONOTOUCH并使用它与使用MONODROID符号相同(参见protobuf-net源文件中的CallbackAttribute.cs和Helpers.cs文件)。

我使用了这两个程序集并尝试从模拟器中的MonoTouch应用程序生成预编译的序列化程序。

但无论我使用哪个版本的预编译序列化程序,程序集仍未包含在应用程序包中,mtouch发出:“警告:应用程序包中缺少库'MyLibrary.dll',无法提取内容”,尽管事实是i do reference it in my code

3 个答案:

答案 0 :(得分:3)

我终于明白了。似乎当实际程序集名称与包含它的文件名不同时,mtouch将不会将其包含在应用程序包中。这种情况发生在我的情况下。我正在生成像这样的程序集:

model.Compile("Taxi.ProtoBufSerializers.MQTTContractsSerializer", "MQTTContractsSerializer.dll");

因此,假设Protobuf-Net将程序集名称设置为此方法的第一个参数并将其保存在第二个参数给出的文件名中,则mtouch将无法将其包含在应用程序包中。

但是,我想保留我的命名空间,所以我摆弄了Protobuf-Net的源代码来生成这样的程序集:

  • 文件路径:作为第二个参数给出;
  • 程序集名称:Path.GetFileNameWithoutExtension(path);
  • 模块名称:Path.GetFileName(路径)。

我目前没有在路径上执行任何验证,但我还不需要这样做。

瞧:样本在模拟器和设备上都有效。

最后但并非最不重要的是,我不知道这是mtouch应该表现的方式还是错误。不过,我会针对它提交错误报告。

答案 1 :(得分:0)

我只是让它在模拟器上工作。我在VS.NET 2010上创建了自定义序列化程序集。我遇到的一个问题是创建的IL / DLL具有错误的命名空间。我做了这样的事情:

model.Compile("X.Y.Serializer.MySerializer", "X.Y.Serializer.dll")

但是IL就像是:

.assembly X.Y.Serializer.MySerializer
{
   .hash algorithm 0x00008004
   .ver 0:0:0:0
}
.module X.Y.Serializer.MySerializer

即。类名是汇编名。

所以我写了一个perl程序:

  • 反编译DLL - > IL
  • 修复IL
  • 编译IL - > DLL

这是脚本:

#!/usr/bin/perl

# Usage: fix-protobuf-assembly assembly bad-namespace
#
# Example: fix-protobuf-assembly X.Y.Serializer.dll X.Y.Serializer.MySerializer
# X.Y.Serializer.MySerializer gets converted to X.Y.Serializer

use strict;
use File::Slurp;
use Cwd;

print "Current directory is " . getcwd() . "\n";
my $asm_file = shift || die "missing assembly file";
my $bad_ns = shift || die "missing namespace";

die "no such file '$asm_file'" if (! -f $asm_file);

my $il_file = $asm_file;
$il_file =~ s#dll$#il#;

Run("ildasm /out=$il_file $asm_file");
my $il = read_file($il_file) || die "error reading $il_file: $!";

my $ns = $bad_ns;
$ns =~ s#\.[^.]+$##;
if (($il =~ s#(\.assembly|module) $bad_ns#$1 $ns#g) == 0)
{
   die "$bad_ns not found in input dll; aborting";
}
write_file($il_file, $il);

Run("ilasm /dll $il_file");

sub Run
{
   my($command) = @_;

   warn "Running $command ...\n";
   system($command) && die "error running last command; bailing out";
}

也许我错过了调用Compile()的正确方法,而且我的hack是不必要的。

该程序集在Windows和iOS模拟器上运行良好。但它然后在设备上给出了运行时JIT编译违例错误。我刚刚创建了一个SO问题:

JIT compile error with protobuf-net on MonoTouch/iOS device (iPhone/iPad)

我尝试在Mac上使用MonoDevelop与标准控制台项目一起创建序列化程序集。我有一些问题,但说实话,我很困倦和脾气暴躁,可能是用户错误,并迅速决定跳到Windows,因为我的项目有我在那里开发的其他组件。

我在Windows上使用了.NET 4.0项目,一切正常。我只需要创建两个仅限MT的库的轻量级版本,以便我可以访问将被序列化的类。

答案 2 :(得分:0)

是的,自2012年以来,我们一直在项目中使用它来提高XML序列化的性能。主要是因为我们当时使用的RESTFul服务无法为某些文件执行大小超过1MB的JSON。在2017年的这一点上,我们现在可以更轻松地使用JSON,而不是为每个对象构建自定义序列化器的额外麻烦。