In the previous tutorial, we gave the game a simple user interface and created some logic to store the local high score. What if we could take this high score and store it in the cloud? So we could compete against the world in our very own game?
This tutorial will do just this! We will create a plugin using Visual Studio 2012 that will connect your game with Windows Azure. We will also create a new Mobile Service in Windows Azure that will be available world wide, so anyone who got your game can compete against each other.
We will learn how to create a new service, how to connect to it, and make it behave as we want. We will also learn how to do client side scripting/programming by creating a Unity plugin, and also how to modify the server-side scripts of our service.
I have been using Windows Azure in almost all of my games – server for MMOs, Highscore/Leaderboards, Save games (nice to have online saves right?) and so on.
Part I – Creating a Windows Azure Mobile Service
A Windows Azure Mobile Service is basically free to use in low end games and games that doesn’t require too much traffic (up to 10 services/month). If you need more services than this, or need additional storage/performance for high-end games, you can upgrade your services as you want.
I usually use one or two services pr. game.
Here is more details regarding the costs on WAMS (Windows Azure Mobile Services): http://www.windowsazure.com/en-us/pricing/details/mobile-services/
Also, using a free trail let’s you get even more free stuff you can play around with (in case you want to explore Windows Azure even more), so jump in there and try the awesomeness Windows Azure is offering.
a) Get your account (it’s worth it!)
Go to http://www.windowsazure.com/en-us/pricing/free-trial/ and create a new account. Don’t worry if you have to put in your credit card details, it will not charge you unless YOU enables this – if you use more than what’s free, the service will just go to pause.
b) Create your Movile Service
Once registered, you will be presented with a pretty nice interface – welcome to Windows Azure.
We want to create a new Mobile Service, so go ahead an click the Mobile Serivces tab:
Then click the big + NEW button on the bottom-left side of the portal:
And create a new Mobile Service:
Now, we need to create a URL for the service – this is usually the name of your app, but it’s really up to you (but it needs to be unique).
You can go ahead and put in your name (if one is taken, put in a random number behind it like SpaceBlaz0r837 or something). If you are following this guide to implement WAMS in your own game, put in the game name or something so you remember that it belongs to that game.
You also need to create a new database (or use an existing one if you have this), and then it needs to know that subscription you are using (usually, you got just one subscription – but there are many good reasons for having more so choose the one that is right for you).
Then it needs to know where in the world the service should be hosted.
Click the next arrow to continue.
Now it’s time to specify some details around the database we are going to use (SQL) for our service. Just fill out the obvious fields and press the check icon down right to start creating the service.
You will now be redirected back to the portal, where your new service is being created.
Click the green “activity” icon indicating that there is one activity currently being processed, and you will see that it is working on your new service.
This might take a minute, but when it is complete the message will be something like this:
Congratulations! Your new Azure Mobile Service is up and running in the cloud! You can see it in the portal overview:
c) Configuring the service
Now, we need to set up the service and make sure everything is working. Click on the service in the overview to be taken to the service settings page:
When there, you are presentated with a cool quickstart page that enables you to quicly get started:
On the top, there is firstly the cloud with a flash in it – that’s the page you see in front of you right now. Then there is a dashboard for statistics, data for the services table, and so on.
d) Creating our data table
In this step, we are going to create the data table that our service will be using. Click the DATA button in the menu bar:
Now, click ADD A TABLE:
Name the table “Leaderboard” and press OK
It will now spend 5 seconds on creating the table for you:
Move on when it is complete
Click the new table from the overview:
Then click the COLUMNS menu bar button:
The awesome new table contains just one columnt named id, and it’s and indexed column meaning that we dont need to set it from our service.
Congratulations! Your service is up and running, with a table in it!
The service is set to automatically add new columns based on what we insert to it. This is great when we build the app, but it’s good practice to turn this setting off when we publish the game (for security reasons).
Part II – Creating the Unity plugin
Windows Azure Mobile Services is not directly supported in Unity, so we need to write a plugin to communicate with it.
Do do this, we need to use Visual Studio 2012. If you don’t yet have it, you can download it for free.
a) Creating a new plugin solution in VS2012
Now, in Visual Studio 2012, create a new solution by clicking File->New->Project..
Find the Visual Studio Solutions tab:
Give it a name like Plugin.MobileServices:
b) How WP8 and Metro plugins work with Unity
Unity works like this. Each plugin that we want to include in our Unity game project needs to be copied in to Assets/Plugins directory. When you export a game, these plugins will follow the project. When it comes to our case, the issue is that the code we will write isn’t really supported in the Unity editor.
This means that we will create two plugins, one “fake” plugin that contains the same functions (so we won’t get any build errors inside the Unity editor), and then another true plugin that acctualy contains the right functionality – that will be copied when we export our Windows 8 game (and another if we want to support Windows Phone 8, and even more if we want iOS or Android (++) too).
The Unity developers have done this easy for us. When we export for Windows 8 (Windows Store Apps), it will look for plugins in the Assets/Plugins folder and copy these over. Then it will look for a subfolder called “Metro” (for Windows 8, “WP8” for Windows Phone 8) and copy these plugins and overwrite the ones that got the same name.
In other words, we need to create two plugins with the same name, one is editor friendly, and another is the one with the actual functionality of connecting to the cloud.
The functions that exists in the fake editor DLL will be visible when we program our games in Unity. This means that the functions and parameters of this will need to mach the ones we use in the other DLL file.
c) Creating the fake editor plugin
We start with creating the fake editor plugin. In Visual Studio 2012, right click the solution and add a new project:
Now, find Visual C# (the language we will write the pluing with), choose .NET Framework 3.5 from the top menu and select Class Library:
Give it the name “Editor” and click OK.
The new project is now added to our solution. Right click the Class1.cs file and rename it to Connector:
The solution now looks something like this:
Double click the Connector.cs file to edit the code. The first thing we want it to change the namespace from Editor to: Plugin.MobileServices
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Plugin.MobileServices
{
public class Connector
{
}
}
Now, it’s time to add some functionality. We simply want to do two things, one is to insert a new entry to our service, and then another one that downloads the best result from our service.
That’s two functions!
public void Insert(int score)
{
}
public void GetScore()
{
}
We also want to have an integer that keeps track of the best score available.
Let’s add these to our plugin code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Plugin.MobileServices
{
public class Connector
{
public int BestScore = 0;
public void Insert(int score)
{
}
public void GetScore()
{
}
}
}
To simulate the plugin that really gets the data from the cloud, we can set the BestScore integer to 1000, just to see some data when we work in the Unity editor:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Plugin.MobileServices
{
public class Connector
{
public int BestScore = 0;
public void Insert(int score)
{
}
public void GetScore()
{
BestScore = 1000;
}
}
}
Thats it for the fake editor dll It basically does nothing – except for making the functions available in the editor (or else you will get build errors – and not be able to play the game in the editor or export it).
d) Creating the real plugin project
Now we are going to create the real stuff! Right click the main solution and add another project:
Select the Windows Store catgeroy under Visual C#, make sure to select .Net Framework 4.5 (important!) and select the Class Library (since we are creating a DLL for our Windows 8 game).
Give the new project the name “Windows8” and click OK.
Again, rename the Class1.cs file that automatically gets generated to Connector:
Now, open the Connector.cs file in the Windows8 project and implement the same logic as we did in the fake DLL (and make sure the namespace is the same as in the editor plugin):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Plugin.MobileServices
{
public class Connector
{
public int BestScore = 0;
public void Insert(int score)
{
}
public void GetScore()
{
BestScore = 1000;
}
}
}
Now, we must connect this to the service we have in the cloud (isn’t this awesome??)!
e) Adding Windows Azure Mobile Services to our project
To do this we need to install the Windows Azure Mobile Services packages to our project. This is very simple
Right click the Windows8 project and select “Manage NuGet Packages…”
This is a service that makes adding libraries and pacakges to our projects very simple.
Now, search for Windows Azure in the search box:
A lot of results will be displayed in the result box, find Windows Azure Mobile Services and click Install:
This will start the download and installation of the Windows Azure Mobile Services pacakge in our project. Once done, it will be visible in the references folder of the project:
f) Adding the logic
Now we are going to use the new package to connect to our service and insert new score items to our service. We also need to make sure that our table contains the right columns.
A Leaderboard entry should consist of an id and the score we just did. We define this by implementing a class in Connector.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Plugin.MobileServices
{
public class Connector
{
public int BestScore = 0;
public void Insert(int score)
{
}
public void GetScore()
{
BestScore = 1000;
}
}
public class Leaderboard
{
public int Id { get; set; }
public int Score { get; set; }
}
}
This class need to have the same name as our table in the service. It contains an id and the score, both integers!
Now, we need to add a variable that will work as the thing that binds this plugin with the mobile service. To set this up correctly, go to the Windows Azure portal again, and open the quickstart screen for our new service:
Now, find and click the Connect an existing Windows Store app button:
Step 1 contains very important information about the service, the URL of the service and the authentication token (only this with this string will be able to connect to our service – so don’t share it ).
Now, this is the variable we need to add to our script to be able to connect to our service. So, click the copy button in the top right side of the code view or mark it and press CTRL+C (or however you usually copy text ) and past it in our Connector.cs class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Plugin.MobileServices
{
public class Connector
{
public static MobileServiceClient MobileService = new MobileServiceClient(
“https://spazeblaz0r.azure-mobile.net/”,
“<your key>”
);
public int BestScore = 0;
public void Insert(int score)
{
}
public void GetScore()
{
BestScore = 1000;
}
}
public class Leaderboard
{
public int Id { get; set; }
public int Score { get; set; }
}
}
Note: Remeber to use your own URL and key for your service
Also, we need to add a using statement for the reference to our Windows Azure Mobile Services library, or else the compliler wont understand what MobileServicesClient is.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MobileServices;
namespace Plugin.MobileServices
{
public class Connector
{
public static MobileServiceClient MobileService = new MobileServiceClient(
“https://spazeblaz0r.azure-mobile.net/”,
“<your key>”
);
public int BestScore = 0;
public void Insert(int score)
{
}
public void GetScore()
{
BestScore = 1000;
}
}
public class Leaderboard
{
public int Id { get; set; }
public int Score { get; set; }
}
}
Nice! Let’s work with that Insert() function
What we want to do here is to create a new Leaderboard item, fill the data and send it to our service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MobileServices;
namespace Plugin.MobileServices
{
public class Connector
{
public static MobileServiceClient MobileService = new MobileServiceClient(
“https://spazeblaz0r.azure-mobile.net/”,
“<your key>”
);
public int BestScore = 0;
public async void Insert(int score)
{
Leaderboard entry = new Leaderboard { Score = score};
await MobileService.GetTable<Leaderboard>().InsertAsync(entry);
}
public void GetScore()
{
BestScore = 1000;
}
}
public class Leaderboard
{
public int Id { get; set; }
public int Score { get; set; }
}
}
Ok, we should now be able to insert things to our Mobile Services table named Leaderboard. Let’s add this to Unity and try it out!
Part III – Adding the plugins to our Unity game
The final part is to add the plugins to Unity and make the functionality available for our games. The first thing we should do is to build the plugin solution so we get the DLLs we need. Right click the Plugin.MovileServices project and click Build Solution:
Now, go to the solution directory in Windows Explorer:
First, lets copy the Editor plugin DLL file. Go to the Plugin.MobileServices\Editor\bin\Debug directory:
Now, copy the Editor.dll file.
Go to the Unity game project in Windows Explorer and create a new folder called “Plugins” in the Assets folder:
Paste the dll file in the Plugins folder:
Now, we need to get the real DLL, so go back to the Plugin solution directory and go to the “Plugin.MobileServices\Windows8\bin\Debug” folder:
Rename the Windows8.dll file to Editor.dll and copy all the DLL files in this folder.
Go to the new Plugins folder in your Unity game using Windows Explorer and create a new folder called Metro:
Paste the DLL files in to this Metro folder:
Phew!
That’s it!
Now, when we work in the Unity editor, writing scripts and whatever, we can find the functionality in the Editor.dll file located in the Plugins-folder.
When we export our project to Windows Store App, the DLL files in Plugins will be copied, and then replaced (if conflict) by the DLLs in the Metro-folder (overwriting the Editor.dll thats really just the fake Editor.dll with the other Editor.dll (Windows8.dll) ) containing the same functions Smart huh?
Part IV – Adding our score entries to our cloud service
Start Unity and open the project we created in part IV of this tutorial series, and open the Game Over scene:
Click the Main Camera game object in the scene hierarchy:
Now, open the game over controller script by double clicking it from the Main Cameras properties/components list:
The scripts look like this:
using UnityEngine;
using System.Collections;
public class GameOverController : MonoBehaviour {
float gameOverTimer;
public GUIText scoreText;
public GUIText highScoreText;
void CheckHighscore()
{
int _score = PlayerPrefs.GetInt(“CurrentScore”, 0);
int _highscore = PlayerPrefs.GetInt(“HighScore”, 0);
if (_score > _highscore)
PlayerPrefs.SetInt(“HighScore”, _score);
}
// Use this for initialization
void Start () {
gameOverTimer = 5.0f;
CheckHighscore();
scoreText.text = “Score: ” + PlayerPrefs.GetInt(“CurrentScore”, 0);
highScoreText.text = “Highscore: ” + PlayerPrefs.GetInt(“HighScore”, 0);
}
// Update is called once per frame
void Update () {
gameOverTimer -= Time.deltaTime;
if(gameOverTimer <= 0.0f)
Application.LoadLevel(0);
}
}
What we want to do is to modify the CheckHighscore() function so it uploads our own highscore to the cloud (but only if we beat our own – or else it will upload bad scores that wont have any chance anyways):
using UnityEngine;
using System.Collections;
public class GameOverController : MonoBehaviour {
float gameOverTimer;
public GUIText scoreText;
public GUIText highScoreText;
Plugin.MobileServices.Connector connector = new Plugin.MobileServices.Connector();
void CheckHighscore()
{
int _score = PlayerPrefs.GetInt(“CurrentScore”, 0);
int _highscore = PlayerPrefs.GetInt(“HighScore”, 0);
if (_score > _highscore)
{
PlayerPrefs.SetInt(“HighScore”, _score);
connector.Insert(_score);
}
}
// Use this for initialization
void Start () {
gameOverTimer = 5.0f;
CheckHighscore();
scoreText.text = “Score: ” + PlayerPrefs.GetInt(“CurrentScore”, 0);
highScoreText.text = “Highscore: ” + PlayerPrefs.GetInt(“HighScore”, 0);
}
// Update is called once per frame
void Update () {
gameOverTimer -= Time.deltaTime;
if(gameOverTimer <= 0.0f)
Application.LoadLevel(0);
}
}
When the game is going to the game over scene, it starts with checking if we have a new high score, and if yes – store this in the local PlayerPrefs variable and insert it to the cloud using our own plugin!
Before trying this, we must make sure that the Windows Store App is allowed to connect to the internet. Go to Unity, and then player settings:
Scroll down and check the InternetClient capability:
Now, export the game as a Windows Store game and open the solution in Visual Studio 2012:
Run the game by pressing the green play icon:
(Must be a Windows 8 machine)
Play the game, make a high score and check the cloud services DATA tab:
Click it and you can see all the entries:
That’s it for sending entries to the cloud!
Part V – Getting the high score from the cloud
The last part will use what we know to get the high score from the cloud and to display it in a third text label in Unity.
a) Adding the UI game objects
Let’s fist add the next text label in Unity. Go to the GUI game object in the scene hierarchy and duplicate the high score text game object:
Rename it to OnlineLeaderText:
Transform the OnlineLeaderText so it’s not on top of the High Score Text:
Now, still in the game over controller script, add a new public variable to hold a reference to our GUI item:
using UnityEngine;
using System.Collections;
public class GameOverController : MonoBehaviour {
float gameOverTimer;
public GUIText scoreText;
public GUIText highScoreText;
public GUIText onlineLeaderText;
Plugin.MobileServices.Connector connector = new Plugin.MobileServices.Connector();
void CheckHighscore()
{
int _score = PlayerPrefs.GetInt(“CurrentScore”, 0);
int _highscore = PlayerPrefs.GetInt(“HighScore”, 0);
if (_score > _highscore)
{
PlayerPrefs.SetInt(“HighScore”, _score);
connector.Insert(_score);
}
}
// Use this for initialization
void Start () {
gameOverTimer = 5.0f;
CheckHighscore();
scoreText.text = “Score: ” + PlayerPrefs.GetInt(“CurrentScore”, 0);
highScoreText.text = “Highscore: ” + PlayerPrefs.GetInt(“HighScore”, 0);
}
// Update is called once per frame
void Update () {
gameOverTimer -= Time.deltaTime;
if(gameOverTimer <= 0.0f)
Application.LoadLevel(0);
}
}
Now, go back to Unity and drag the GUI Text to the variable on the Main Camera script, and redrag the high score if needed:
So it becomes:
Now Score, High Score and Online Score is referencing to the correct game objects in our game over scene.
b) Setting the Online UI Text
Time to change more to the script. We want to query the service
and set the text of the Online High Score to the best score integer from our plugin:
using UnityEngine;
using System.Collections;
public class GameOverController : MonoBehaviour {
float gameOverTimer;
public GUIText scoreText;
public GUIText highScoreText;
public GUIText onlineLeaderText;
Plugin.MobileServices.Connector connector = new Plugin.MobileServices.Connector();
void CheckHighscore()
{
int _score = PlayerPrefs.GetInt(“CurrentScore”, 0);
int _highscore = PlayerPrefs.GetInt(“HighScore”, 0);
if (_score > _highscore)
{
PlayerPrefs.SetInt(“HighScore”, _score);
connector.Insert(_score);
}
}
// Use this for initialization
void Start () {
gameOverTimer = 5.0f;
CheckHighscore();
connector.GetScore();
scoreText.text = “Score: ” + PlayerPrefs.GetInt(“CurrentScore”, 0);
highScoreText.text = “Highscore: ” + PlayerPrefs.GetInt(“HighScore”, 0);
}
// Update is called once per frame
void Update () {
gameOverTimer -= Time.deltaTime;
if(gameOverTimer <= 0.0f)
Application.LoadLevel(0);
onlineLeaderText.text = “Online: ” + connector.BestScore;
}
}
Everything we need to do is to update the online score every frame (since connect.GetScore() is async, so it might take some time untill it is ready), and when the script starts, we check for high score, upload if new, and then download the best score.
c) Changing the Plugin code so it downloads the data
Open the Connector.cs class in the Windows8 project of the Plugin solution and make the following changes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.MobileServices;
namespace Plugin.MobileServices
{
public class Connector
{
public static MobileServiceCollection<Leaderboard, Leaderboard> Items = null;
public static MobileServiceClient MobileService = new MobileServiceClient(
“https://spazeblaz0r.azure-mobile.net/”,
“<your key>”
);
public int BestScore = 0;
public async void Insert(int score)
{
Leaderboard entry = new Leaderboard { Score = score};
await MobileService.GetTable<Leaderboard>().InsertAsync(entry);
}
public async void GetScore()
{
Items = await MobileService.GetTable<Leaderboard>().ToCollectionAsync();
if (Items != null)
{
if (Items.Count > 0)
{
BestScore = Items[0].Score;
}
}
}
}
public class Leaderboard
{
public int Id { get; set; }
public int Score { get; set; }
}
}
What we are doing here is to add an Items collection that will contain the data we get from the service. Then we set the BestScore integert to equal the Score of the first item we get back from the service. We are going to change the server side script to only send us the best score (less data traffic, less cost from mobile networks ).¨
Right click the Windows8 project, Build it. Copy the new DLL file, and replace the one in the Plugins/Metro folder with this new built dll.
Now, delete the contents of the previously exported Windows Store project and export it again. Run it and see that the entry on the Online UI Text item is set to the first item on our Leaderboard list that exists in the cloud.
Yeah, this is not the best score – it’s the first score ever uploaded to the service..
Let’s fix this!
d) Changing the server side script so it only returns the best score
Go to the DATA tab of your Mobile Service in the Windows Azure portal:
Click the table Leaderboard:
Now, click the SCRIPTS button on the top menu bar:
Modify the script so it looks like this:
function read(query, user, request) {
query.orderByDescending(‘Score’).take(1);
request.execute();
}
Click Save and wait for the changes to be saved.
What this code does is to modify how the service are reading items from our table. What we are doing here is to modify the query that came in to the function (it was pretty much blank since we havent sent in anything from the client/game when we asked for the data), so it orders descending on score, and then takes the first item (best score since its ordered by score descending).
This is how it looks in my browser:
Since we just modified the server side of the code, we dont need to rebuild or export our solution again. Just press play in Visual Studio to play the Windows 8 game again and see the changes!
And it sure seems a lot better now – just wait for the async operation to finish, might take a second or two
The online score is set to 60:
And if we check the high score we can see that the best entry is 60:
That is for this tutorial. I know it was a long run, but now that you know it, you can implement Azure services in your own games in less then 10 minutes.
To do for you?
This plugin is very spesific for our purpose, but it wont be too much work to make this general where you can pass in types and classes for our data, and so on.
Also, to make this work for Windows Phone 8, just add a new Windows Phone 8 class library and do the same plugin logic.
Assets and source code
Download tutorial assets and source code: http://sdrv.ms/16B7n4Q
One of the best tutorials ever.. finally not using some PHP highscore thing.. anyways..Tried creating the plugin and using the existing code as well.. kept getting this error when I build.. any ideas?
Error building Player: Exception: Could not load file or assembly ‘file:///C:\temp\Unity Game Part V\Temp\StagingArea\Data\Managed\Plugins\Editor.dll’ or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515)
Did you copy all the dependencies thats located at the same folder as the ready built dll file? It looks like it’s the “Fake” dll that’s having troubles?
Reloaded everything.. build project.. compiled in vs2013 RC.. works.. Ran it.. let the game finish.. unhandled exception… so I loaded the plugin code and used my static key and compiled… strangely the dll is ‘windows8’ and not editor though.. but in your finished version it seems ‘editor.dll. is used for the real and fake.. Where is the connection in the c# script that connects the code to the DLL? Where on the unity side does is know how to find what DLL this belongs too ?
Plugin.MobileServices.Connector connector = new Plugin.MobileServices.Connector();
This whole series is really great. Thanks!
Does this leaderboard work in the basic version of Unity or does it require Unity Pro?
Great tutorial! Any thoughts on implementing this on Android/iOS? Would the Azure Mobile port for Xamarin be able to run in Unity’s mono environment? Would love your thoughts on this.
Pingback: 크로스 플랫폼 대상의 앱 개발 - 중스의 마이크로소프트 이야기 - Site Home - MSDN Blogs
I went through and tried again. Got further this time. This happenes when I try to build the solution from unity as a windows store app
Error building Player: Exception: Failed to run Reference Rewriter with cmdline –target=”Temp/StagingArea\Newtonsoft.Json.dll” –framework=”C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5.1″ –platform=”C:\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral\Windows.winmd” –support=”Temp/StagingArea\WinRTLegacy.dll” –system=System –dbg=pdb –alt=System.Xml.Serialization.[Temp/StagingArea\Newtonsoft.Json.dll]
Error: method `System.String System.Char::ToString(System.IFormatProvider)` doesn’t exist in target framework. It is referenced from Newtonsoft.Json.dll at System.Void Newtonsoft.Json.Bson.BsonWriter::WriteValue(System.Char).
Error: method `System.Boolean System.Type::op_Equality(System.Type,System.Type)` doesn’t exist in target framework. It is referenced from Newtonsoft.Json.dll at System.Object Newtonsoft.Json.Converters.BinaryConverter::ReadJson(Newtonsoft.Json.JsonReader,System.Type,System.Object,Newtonsoft.Json.JsonSerializer).
Error: method `System.Boolean System.Type::op_Equality(System.Type,System.Type)` doesn’t exist in target framework. It is referenced from Newtonsoft.Json.dll at System.Boolean Newtonsoft.Json.Converters.BinaryConverter::CanConvert(System.Type).
Error: method `System.Boolean System.Type::op_Equality(System.Type,System.Type)` doesn’t exist in target framework. It is referenced from Newtonsoft.Json.dll at System.Boolean Newtonsoft.Json.Converters.BinaryConverter::CanConvert(System.Type).
Matt Herb – did you figure this out. I have the same issue? Thanks