15

I'm having trouble understanding why the Newtonsoft JSON parser has to be device specific under Xamarin. I cannot seem to find any way to have the parser exist in a common, shared library. I'm using the Tasky Pro sample app. I can get the JSON.Net DLLs from the Xamarin store to work in the Android and iOS projects, however that makes no architecural sense. E.g., the SQLite stuff is all in a shared lib, as you'd expect - as one set of c# source files.

Ideally I'd like to just add some kind of reference to "Tasky.Core" and be able to serialize/deserialize JSON.

Is there any way to get JSON.Net to work in a shared library (across droid/ios/wp8)? The source is pretty huge to try to manage as linked files, if that's even possible...

If not, is there some alternative way of managing JSON that will work in this way?

Steve Macdonald
  • 1,745
  • 2
  • 20
  • 34
  • Are you using Xamarin Forms? If so you can just wrap the parser in an interface, and provide an instance of the platform specific one through the dependency resolver. As an additional benefit, you won't be tied to JSON.NET in your code if you decide to use another library in the future. – Mathieson Jun 04 '15 at 19:35

2 Answers2

35

You should be able to use the JSon.NET NuGet Package for this. The implementation is actually platform-specific [1], but NuGet will transparently take care of that for you and pick the correct one for you.

Note that you need Mono 3.2.6 and Xamarin.iOS 7.0.6 for this, which just hit the alpha channel this week, I have just fixed some critical bugs in this area. You should also upgrade the NuGet Add-In in Xamarin Studio to the latest version (0.8), which contains several PCL-related bug fixes.

Simply add the NuGet Add-In to Xamarin Studio if you have not done so already, then search for "JSon.NET", the add-in will automatically install the package and add the required library references for you.

[1] The NuGet package contains different .dll's for different target frameworks and then picks and references the best one for your project - so your application will only contain a single implementation, but an iOS app may use a different one than a desktop application.

Update 01/14/14:

NuGet packages usually contain different implementations - unfortunately, not all of them will work with Xamarin.iOS due to APIs such as Reflection.Emit or Full DLR that are not available on iOS.

If you look into the packages/Newtonsoft.Json.5.0.8/lib/ directory, you'll see different sub-directories - each of these contain a different implementation and NuGet will use the one that best fits the current target framework. Unfortunately, NuGet does not always pick the right one :-(

For Newtonsoft.Json.5.0.8, the "portable-net45+wp80+win8" implementation uses DLR features that are not available on iOS, the "portable-net40+sl4+wp7+win8" one is ok. So if you add the NuGet package to a PCL that's targeting for instance Profile136, you'll get the correct implementation.

There is no GUI to choose another implementation, but you can edit the .csproj file. Replace

<Reference Include="Newtonsoft.Json">
  <HintPath>..\packages\Newtonsoft.Json.5.0.8\lib\portable-net45+wp80+win8\Newtonsoft.Json.dll</HintPath>
</Reference>

with

<Reference Include="Newtonsoft.Json">
  <HintPath>..\packages\Newtonsoft.Json.5.0.8\lib\portable-net40+sl4+wp7+win8\Newtonsoft.Json.dll</HintPath>
</Reference>

and it should work.

In general, when you're getting an error message about missing types after adding a new NuGet package, go to the corresponding package directory and grep -r for that symbol - chances are that there's a different implementation which does not use this type.

Hopefully, a more elegant solution will be available in the future, but that needs coordination with the NuGet team and package authors, so it'll take some time.

Martin Baulig
  • 3,010
  • 1
  • 17
  • 22
  • Awesome! Will try this shortly. In the mean time I determined that if I reference the "portable40" dll in the Tasky.Core project, and the device-specific dll in the iOS Tasky project, it seems to work. Your way definitely sounds less kludgy so I'll give it a go in the morning. – Steve Macdonald Dec 17 '13 at 23:47
  • So NuGet worked fine for my base "Core" Portable lib, and for the iOS project. Doesn't work for Android though (I get /Users/Steve/Projects/JSON3/JSON3/MyClass.cs(52,52): Error CS0012: The type `System.Object' is defined in an assembly that is not referenced. Consider adding a reference to assembly `System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' (CS0012) (JSON3.Android). If I reference the DLL that I downloaded from the Xamarin store, it works however. – Steve Macdonald Dec 18 '13 at 00:48
  • 1
    That's the same bug, there will also be a new version of Xamarin.Android shortly. As a workaround, add `<_HasReferenceToSystemRuntime>true` to the top `` in your .csproj file, that should fix it. – Martin Baulig Dec 18 '13 at 09:36
  • I have the same issue and am stuck. I was excited to see this answer until I went to get the Xamarin.iOS 7.0.6 release on the alpha channel and saw that it didn't exist (all I see is 7.0.5). Also not sure this solution will address my environment (Windows Visual Studio). Any insight? – BobDickinson Dec 24 '13 at 01:43
  • 1
    Actually, my issue is different. I can't even use the NuGet JSON.Net in a Xamarin iOS project. I saw 7.0.6 pop up today on the alpha channel and I upgraded. Still no joy. I can create a brand new iOS project, use NuGet to add JSON.Net, add a reference to JSON.Net in main.cs, build and get: The type 'System.Dynamic.IDynamicMetaObjectProvider' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Dynamic.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. – BobDickinson Dec 24 '13 at 09:34
  • Yes, that is a known limitation - you cannot directly add it to the iOS project without some little modifications. I'll update my answer to provide a detailed explanation. – Martin Baulig Jan 14 '14 at 16:41
  • Any update to this problem I'm running into it trying to implement the latest Google API - Thanks, Rick – Rick Mar 13 '14 at 22:23
  • @MartinBaulig thanks for sharing, it lead me to solution. It looks like there's a NuGet issue in Json.NET. When adding Json.NET (curently v6.02) from NuGet to a PCL targeting Xamarin, it is mistakenly adding from 'portable-net45+wp80+win8+wpa81' instead of 'portable-net40+sl5+wp80+win8+monotouch+monoandroid'. With the latter, I confirm Json.NET works on both iOS and Android. – WriteEatSleepRepeat Apr 04 '14 at 21:25
1

Just add it to Shared Library via NuGet. Actually, all your request/response tasks should be done in library. You should use JSON.Net to parse response.