Reputation: 734
Has anyone actually managed to accomplish this?
I tried the approach suggested here, but no matter how i generate the precompiled serializer, mtouch fails to copy it to the app bundle, thus resulting in a runtime exception. I think this happens because the resulting binary may not be compatible with MonoTouch.
I have tried the following:
1) I used the provided iOs and Mono binaries included in the latest (r450 as this time) build in order to generate the precompiled serializer.
2) I used the source code to produce two different assemblies, built for MonoTouch. The first assembly is built using the symbols FEAT_SAFE;MONOTOUCH;NO_RUNTIME and the second is built using the symbols FEAT_SAFE;MONOTOUCH;FEAT_COMPILER. I have defined the symbol MONOTOUCH and used it the same as MONODROID symbol is used (see file CallbackAttribute.cs and Helpers.cs in the protobuf-net source).
I the used this two assemblies and tried to generate the precompiled serializer from a MonoTouch application in the simulator.
But no matter which version of the precompiled serializer i use, the assembly is still not included in the app bundle, with mtouch issuing: "Warning: Library 'MyLibrary.dll' missing in app bundle, cannot extract content", despite the fact that i do reference it in my code.
Upvotes: 2
Views: 1274
Reputation: 1005
Yes, we have been using it on a project since 2012 to improve performance over XML serialization. Mostly because the RESTFul services we had at the time could not do JSON over 1MB in size for some of the files. At this point in 2017, it would be a lot easier for us to use JSON now, instead of the extra hassle of building the custom serializers for each object.
Upvotes: 0
Reputation: 734
I finally got it. It seems that when the actual assembly name is different from the file name that contains it mtouch will not include it in the application bundle. And that was happening in my case. I am generating the assembly like this:
model.Compile("Taxi.ProtoBufSerializers.MQTTContractsSerializer", "MQTTContractsSerializer.dll");
So, given that Protobuf-Net sets the assembly name to the first parameter of this method and saves it in the file name given by the second parameter, mtouch will fail to include it in the application bundle.
However, i wanted to keep my namespace so i fiddled with Protobuf-Net's source code to generate the assembly like this:
I am not performing any validations on the path at this time, but i don't need to do this just yet.
And voila: The sample works both on the simulator and the device.
Last but not least, i don't know if this is the way mtouch is supposed to behave or if it is a bug. I will however file a bug report against it.
Upvotes: 3
Reputation: 1626
I have only gotten it to work on the simulator. I created the custom serialization assembly on VS.NET 2010. One issue I had was that the IL/DLL that gets created had the wrong namespace. I did something like this:
model.Compile("X.Y.Serializer.MySerializer", "X.Y.Serializer.dll")
But the IL was something like:
.assembly X.Y.Serializer.MySerializer
{
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module X.Y.Serializer.MySerializer
I.e. the class name was in the assembly name.
So I wrote a perl program to:
Here is the script:
#!/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";
}
Maybe I just missed the proper way to call Compile() and my hack is unnecessary.
The assembly worked fine on Windows and iOS simulator. But it then gave a runtime JIT compile violation error on the device. I just created a SO question:
JIT compile error with protobuf-net on MonoTouch/iOS device (iPhone/iPad)
I did try using MonoDevelop on Mac w/ standard console project to first create the serialization assembly. I had some issues, but to be honest I was sleepy and grumpy and it could have been user error, and quickly decided to jump over to Windows since my project has other components that I develop there.
I used .NET 4.0 projects on Windows and everything worked OK. I just had to create a lightweight version of two MT-only libraries so that I could access the classes that would be serialized.
Upvotes: 0