Use Azure Services from Unity (Azure App Service/Mobile Apps, Event Hubs, Table Storage/CosmosDB with Table API)

tl;dr – Azure and Unity, really?

Azure Services for Unity is a small library (currently in beta) that provides you an easy way you to access an Azure database and/or APIs (hosted on Azure App Service) via the Unity game engine. You can use it to save highscores, status messages, send messages between players and much more. As there are no plugins involved, library is cross-platform and can run everywhere that Unity runs (editor, standalone players, iOS, Android, Windows Phone and Windows Store Apps). Of course, it is completely open source and free to use. It was last tested on Unity 5.3.4f1. Current version 0.0.13.

Update: for some additions and fixes to the library check out my newer blog post here
Update2: check this blog post for an addition to the library that allows you to access Azure Table Storage Service or CosmosDB with Table Storage API.

Intro

Azure App Service is quite an interesting cloud platform to develop web and mobile apps. One can easily create web apps that scale, create mobile apps backend and integrate with existing services either on the cloud or on-premise. App Service also has a very simple mechanism to store data and use various APIs, called Easy Tables and Easy APIs, respectively. Those can be rather helpful to game developers that want to create a backend for their game. In this blog post, we’ll describe a small library that allows a game written in Unity to access them.

Creating an Azure App Service and database

We assume you have an active Azure subscription. If not, refer to the last paragraph on this blog post to find out easy ways to get one. First, you’ll need to visit the new Azure portal at http://portal.azure.com.

Create the App Service

Select “New”, “Web+Mobile”, “Mobile App”. Select a URL, a Resource Group and a Service Plan (you can even use a free tier).

Screen Shot 2016-04-13 at 19.29.26.png

Click “Create” and wait a few minutes, till the new App Service is deployed.

Create the Database

Find the newly created App Service via the “All Resources” blade. Click “Settings”, then “Easy Tables”. You’ll see a message that there is a need to “Configure Easy Tables/Easy APIs”. Click there to continue. You’ll see another message that you need a database. Click it.

On the “Data Connections” window, click the “+” sign to create a new connection. Click “Create a new database” (we suppose that you do not have one).

Screen Shot 2016-04-13 at 19.35.48.png

Fill the necessary settings to create a new database and a new database server to host it. You can use a free database (up to 32MB, so be careful!).

Screen Shot 2016-04-13 at 19.37.37.png

Press “OK” on the blades that you have opened (I counted 3 “OK” button clicks) and wait for the data connection to be created, it may take a couple of minutes. Once it’s done, close the “Data Connection” blade and return to the “Easy Tables” one. Press the “Initialize App”, after you acknowledge that this will overwrite your existing contents. Again, wait for a few minutes for the backend to initialize.

Create a table

On the “Easy Tables” blade, click on the “Add” button to create a new table. Let’s name it “Highscore”. Take notice that you can set authentication options for each table operation. Click “OK”. Once it’s created, click on it and then click on “Manage Schema”. You’ll see some columns already defined, click “Add a column” to add a couple more. We’ll add a “score” with datatype “Number” and a “playername” with datatype “String”.

Screen Shot 2016-04-13 at 20.04.35.png

Create an Easy API

Return to the App Service’s “Settings” blade. Click the “Easy APIs” setting. Click the “Add” button and select a name for your new API. Again, take notice of the fact that you can alter authorization options for the various HTTP operations you can perform on this specific API. We named our API “Hello”.

Once you click “Edit”, you will be transferred to “Visual Studio Online” where you’ll see that your App Service is based on a Node.js backend. So, your API will be a JavaScript method. Since we named our API “Hello”, the Azure portal created a file “Hello.js” on the “api” subfolder. There, I created the following method that just responds with a simple JSON message.

Screen Shot 2016-04-13 at 20.10.43.png

How do I use the library?

Simple! You can download the code. Inside it you’ll find a scene with some buttons that call the relevant code to do CRUD operations on the database or call an Easy API. The calls have the following format

AzureUnityServices.Instance.Operation(arguments, callback)

The callback method carries a CallbackResponse object that has

  • a Status property, that determines the status of the operation
  • a Result property, that carries the response object (of type ReturnObjectType

All the code resides in the AzureServicesForUnity folder. Inside it you can also find a prefab GameObject that you can drag/drop onto existing scenes to take advantage of the library. Don’t forget to set the url of your App Service in the format http://yourdomain.azurewebsites.net

ab

Check the UIScript file on the Scripts folder, you’ll find that the method calls are easily self-explainable.

Last but not least, you need to create a class that corresponds to the Easy Table you’ve created. For example, for the Highscore table we created on the Azure portal, we have created this class

[Serializable()]
public class Highscore : AzureObjectBase
{
    public int score;
    public string playername;
}

This class needs to inherit the AzureObjectBase class (which just provides an ID variable) and be Serializable.

What operations are offered by the library?

The following operations are supported by the library

  • CallAPI(apiname, httpMethod, callback) – to access EasyAPIs
  • Insert(instance, callback)
  • SelectFiltered(query, callback) – query can be null in order to get all rows
  • SelectByID(id, callback) – returns single object
  • UpdateObject(instance, callback)
  • DeleteByID(id, callback)

The most interesting method is the SelectFiltered one. The query object is an IQueryable object, like

string pn = "d";
var query = q.Where(x => x.score > 500 || x.playername.StartsWith(pn)).OrderBy(x => x.score);

This is by no means a fully functional IQueryable implementation! We’ve implemented some features of it which are the most commonly used, specifically

  • Where
  • Select (simple projections)
  • OrderBy and OrderByDescending
  • Skip
  • Take
  • some string operations, like StartsWith, Contains, ToUpper, ToLower

These are all translated to their OData equivalents (yup, Easy Tables are OData friendly!). For example, this piece of code

ODataQueryProvider odqp = new ODataQueryProvider();
ODataQuery query = new ODataQuery(odqp);
int min = 50, max = 100;
string name = “Dimitris”;
var q = query.OrderBy(x => x.score).Skip(3).Take(2).
Where(x => ((x.score > min && x.score < max && x.playername.ToLower().Contains(“d”)) || x.playername == name).Select(x=>
new { x.id, x.playername });

would be translated to

?$filter=((((score gt 50) and (score lt 100)) and substringof(‘d’,tolower(playername))) or (playername eq ‘Dimitris’))&$skip=3&$take=2&$orderby=score&$select=id,playername

and get appended to the URL. Of course, it would bring the relevant results. Unfortunately, I had to remove the IQueryable implementation as I couldn’t get it to work on UWP. You need to pass the query by string, check here for the options.

How can I use authentication?

Using authentication almost always involves calling platform specific (native) code. Since we wanted this library to be plugin free, we opted to leave the authentication method completely to other relevant libraries.

Let’s suppose you want to use Facebook Authentication. You need to follow the below steps

  1. Register as a developer on Facebook, create a Facebook app and configure your App Service App to use Facebook SDK for authentication
  2. Make sure your redirect URI is your application’s URL concatenated with /.auth/login/facebook/callback
  3. Finally, use Facebook’s Unity SDK to get an authentication token for logged in users. Once you have it, you can pass it to AzureUnityServices.Instance.AuthenticationToken field and your Azure App Service calls would be authenticated and authorized.

Why beta?

This library is in beta, for, well, many reasons. First of all, our OData implementation is pretty basic and still may contain bugs. Secondly, Unity’s JSON Parser is still pretty basic since it can’t deserialize responses that contain object arrays, so we had to resort to a small hack to get it working. Finally, we use a fairly new Unity class to do the HTTP Requests, called UnityWebRequest. It currently resides in a namespace called UnityEngine.Experimental.Networking. Well, from the “Experimental” word you can feel the beta of it! Update: UnityWebRequest is not longer in Beta!

Where does it run?

That’s the best part. Almost everywhere! Copying and pasting from the Unity manual (as of April 14th, 2016)

The UnityWebRequest system supports most Unity platforms, with the notable exception of the Unity Web Player.

Platforms supported in 5.2:

  • All versions of the Editor & Standalone players
  • WebGL

Platforms supported in 5.3:

  • Mobile Platforms: iOS, Android, Windows Phone 8
  • Windows Store Apps

Additional platform support will be rolled out in further 5.x releases:

  • PS3, PS4, PS Vita, and PS Mobile
  • XBox 360 and XBox One
  • Wii U

Can I use it in my game?

Yes, feel free to do whatever you want with it. Check the MIT license file here.

I can’t find any documentation for Azure App Service REST API. How did you do it?

Two things

  • Fiddler. If you are doing anything related to HTTP and don’t use it, DOWNLOAD IT NOW
  • Lots of step by step debugging and variable monitoring on official Azure Mobile Apps SDK. If you ask “hey, there’s an official SDK for that, so what am I doing here?” the answer is that the official SDK relies heavily (and for good reason) on azync/await methods (and other C# goodies) which Unity does not support yet.

Next steps

Well, a lot! We basically want to see if you use it, if it’s useful for you, extinguish possible bugs. Some specific things:

  • We definitely want to enhance the OData parser since, well, it’s pretty basic now
  • Probably merge the SelectFiltered and SelectByID methods, still under consideration

How do I get some Azure???

So, you’ve read the blog post (thanks, by the way!) and you may be wondering how to get access to Azure to use for your game. Well, there are many ways!

    • You can use a free trial here
    • If you only want to test the App Service, check out this page
    • If you’re a student, try getting access by visiting www.dreamspark.com. There, among other things, you can find some free access to Azure. It’s a bit limited regarding services you’ll get, but it’s more than enough to get you started.
    • You can also try and enroll into the Visual Studio Dev Essentials program that also includes some free access to Azure services.
    • If you’re an indie game dev team, you may qualify as a startup and, thus, have access to the BizSpark program.

 

 

66 thoughts on “Use Azure Services from Unity (Azure App Service/Mobile Apps, Event Hubs, Table Storage/CosmosDB with Table API)

  1. Hi,

    Just wanted to show my appreciation for the work that was done. This is a really simply and easy to use solution. Managed to customize to meet my requirements in minutes, good job on this post.

    Thank you very much.

    Any chance there is a support blog or some way to report issues if found?

    Like

  2. Hi

    Please help,

    We tested our project on an IOS device today and when you try to use “SelectFiltered()” we are getting the following error:

    ExecutionEngineException: Attempting to JIT compile method ‘(wrapper dynamic-method) System.Runtime.CompilerServices.ExecutionScope:lambda_method (System.Runtime.CompilerServices.ExecutionScope)’ while running with –aot-only.

    Like

  3. IOS does not support JIT only AOT.

    so this is what we have found to try and resolve, but still too much of a noob to understand what they are saying.

    http://www.reentrygames.com/unity-3d-using-extension-methods-to-solve-problems-with-generics-and-aot-on-ios/

    This link discusses the issue in detail, but again we tried but it does not look like we understand what they are saying.
    http://forum.unity3d.com/threads/executionengineexception-on-ios-only.113750/

    Like

      • This is the complete debug log.

        ExecutionEngineException: Attempting to JIT compile method ‘(wrapper dynamic-method) System.Runtime.CompilerServices.ExecutionScope:lambda_method (System.Runtime.CompilerServices.ExecutionScope)’ while running with –aot-only.

        (Filename: Line: -1)

        Loading…

        (Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 37)

        Like

      • Thank you. Try something for me and let me know if the debug log is any different.
        Visit the PartialEvaluator.cs class and in the EvaluateIndependentSubtrees change these lines of code

        if (expr != null &&
        subtrees.Contains(expr) &&
        expr.NodeType != ExpressionType.Constant)
        {
        // Turn the expression into a parameterless lambda,
        // evaluate it, and return the response as a constant.
        Delegate compiled = Expression.Lambda(expr).Compile();
        object value = compiled.DynamicInvoke();
        return Expression.Constant(value, expr.Type);
        }
        else
        {
        return recur(expr);
        }

        to just

        return recur(expr);

        and let me know. I suspect that the problem is in the call of the DynamicInvoke method, which is prohibited due to AOT compiling.

        Like

      • Hi,

        We made the suggested change:
        return VisitorHelper.VisitAll(
        expression,
        (expr, recur) =>
        {
        return recur(expr);
        // if (expr != null &&
        // subtrees.Contains(expr) &&
        // expr.NodeType != ExpressionType.Constant)
        // {
        // // Turn the expression into a parameterless lambda,
        // // evaluate it, and return the response as a constant.
        // Delegate compiled = Expression.Lambda(expr).Compile();
        // object value = compiled.DynamicInvoke();
        // return Expression.Constant(value, expr.Type);
        // }
        // else
        // {
        // return recur(expr);
        // }
        });

        We are getting the following:
        NotSupportedException: The member ‘startWith’ is not supported in the ‘Where’ Mobile Services query expression ‘value(hwsh_Azure_Data_Manager+c__AnonStoreyB).startWith’.

        Our testing led us here,

        Debug.Log(“2========= get tables url: “+ url); //THIS IS THE LAST LOG WE SEE

        private IEnumerator SelectFilteredInternal(EasyTableQuery query, Action<CallbackResponse> onSelectCompleted)
        where T : AzureObjectBase
        {
        Debug.Log (“1========= selectFilteredInternal method”);
        string url = GetTablesUrl();
        Debug.Log(“2========= get tables url: “+ url); //THIS IS THE LAST LOG WE SEE

        if (query != null) {
        Debug.Log (“3========= Query not null: ” + query);
        url += “?” + query.ToODataString ();
        Debug.Log (“4========= url built: ” + url);

        We did test on the device as well and we are no longer seeing the JIT error, only the above described issue.

        Like

  4. this is the code we are calling,

    public void hwsh_Select()
    {
    EasyTableQueryHelper queryHelper = new EasyTableQueryHelper();

    string startWith = “”;
    var query = queryHelper.Where(x => x.hwsh_user_popularity_score x.hwsh_user_popularity_score);

    if we remove this section the query runs successfully and we can retrieve the data.
    x.fb_user_name.StartsWith(startWith)).OrderByDescending(x => x.hwsh_user_popularity_score)

    But now we are unable to sort the data in order. Is there another way to sort the data? Because that would solve our problem and we could carry on. :)

    Like

      • Unfortunately we need the retrieve the data presorted, we first attempted sorting client side but due to the large amount of potential entries we would be retrieving from the database this is not something we can do.

        good news, my buddy just did some magic.
        we are now able to retrieve the data and order it,

        made the following change.
        var query = queryHelper.Where(x => x.hwsh_user_popularity_score > 0).OrderByDescending(x => x.hwsh_user_popularity_score);

        and it is now working.

        Like

  5. Thanks for the amazing work, however it doesn’t work everywhere as stated in your description for example try to build a UWP project from unity and you get 104 errors, mostly because some code is not supported in UWP library and so you would have to provide 2 casses for each one for #if NETFX_CORE and the #else for others.
    I’ve added an issue on github with a small part of the errors I get when building.
    Thank you!

    Like

  6. Hi there, great tutorial you got there..very easy to implement..
    However i got problem to understand the authentication part.
    Did you got any tutorial of it? it seem i really cant understand the about facebook auth for unity using ms azure very well. Any help is greatly appreciate..Thank you :D

    Like

    • I would recommend checking Facebook SDK for Unity and its relevant documentation here. When you use it in your game, you will allow your player to login using Facebook. When this does happen, you will get a token which you pass here AzureUnityServices.Instance.AuthenticationToken. Let me know, thanks!

      Like

  7. I’m getting this following error for some reason
    everything was working fine until i updated unity to 5.5
    Error occurred AzureFunctions and AzureIntegration are my scripts, (where i did not change anything with the implementation of your plugin )

    UnityEngine.Debug:Log(Object)
    AzureFunctions:ShowError(String) (at Assets/_Script/Networking/AzureIntegration/AzureFunctions.cs:27)
    AzureFunctions:m__4(CallbackResponse`1) (at Assets/_Script/Networking/AzureIntegration/AzureFunctions.cs:235)
    AzureServicesForUnity.c__Iterator3`1:MoveNext() (at Assets/AzureServicesForUnity/EasyTables.cs:218)
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

    and this

    Null
    UnityEngine.Debug:Log(Object)
    AzureServicesForUnity.c__Iterator3`1:MoveNext() (at Assets/AzureServicesForUnity/EasyTables.cs:185)
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

    Like

  8. and also this error

    400
    UnityEngine.Debug:Log(Object)
    AzureServicesForUnity.c__Iterator3`1:MoveNext() (at Assets/AzureServicesForUnity/EasyTables.cs:179)
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

    Like

  9. Sorry for multiple comments i could not find the edit button

    digging deeper the web request when i go to the generated url myself i get this following message

    {“error”:”An invalid API version was specified in the request, this request needs to specify a ZUMO-API-VERSION of 2.0.0.”}

    Like

      • GET /tables/Highscore?$filter=(userfbid EQ ‘1130072253785153’) HTTP/1.1
        Host: WEBSITENAME.azurewebsites.net
        User-Agent: UnityPlayer/5.5.2f1 (UnityWebRequest/1.0, libcurl/7.46.0-DEV)
        Accept-Encoding: identity
        Connection: Keep-Alive
        Accept: application/json
        Content-Type: application/json
        X-Unity-Version: 5.5.2f1
        ZUMO-API-VERSION: 2.0.0

        This is the request header

        Like

      • /\ after updating the project with the newer version of the commit and also i modified the highscore with facebook which is why i am trying to get data with the ‘userfbid’ (which works fine), for some reason things started to break when i updated unity from Unity 5.4.0f3 (64-bit) to Unity 5.5.2f1 (64-bit),

        stuff like insert works just fine, things tend to break when i am using query this is what i am using ” var query = queryHelper.Where(x => x.userfbid == azure.playerFbUserId);”

        azure.playerFbUserId is set after facebook is logged in.

        Like

      • Haven’t checked yet, what I would do is compare the headers of the breaking request to one that actually works, to see if there are any differences. By the way, maybe also use a Select() after the Where() you have?

        Like

      • I tried the previous query in your build that comes with the project as it is and my game’s build to

        ” string pn = “d”;
        var query = queryHelper.Where(x => x.score > 500 || x.playername.StartsWith(pn)).OrderBy(x => x.score);”

        And i still get the same header for both the projects

        GET http://WEBSITENAME.azurewebsites.net/tables/Highscore?$filter=((score GT 500) OR STARTSWITH(PLAYERNAME,’D’))&$ORDERBY=SCORE HTTP/1.1
        Host: unum.azurewebsites.net
        User-Agent: UnityPlayer/5.5.2f1 (UnityWebRequest/1.0, libcurl/7.46.0-DEV)
        Accept-Encoding: identity
        Connection: Keep-Alive
        Accept: application/json
        Content-Type: application/json
        X-Unity-Version: 5.5.2f1
        ZUMO-API-VERSION: 2.0.0

        Like

      • This is very weird, but when i revert back to Unity 5.4.0f3 everything works like a charm, The code is the same with no difference, anyways.
        Thank you sir for your patience, in helping me and the effort you put in. I’m full of appreciation!

        Like

      • That’s even more interesting, maybe something changed in UnityWebRequest between these versions? Again, I would check and compare the headers being sent, to check what’s going on.

        Like

  10. Hi, Im planning to use this, inorder to get data from table and display that data as a paragraph/summary in each line of textblock.. Do I still have to do the facebook sdk part though?
    Your help will be greatful…

    Like

  11. Actually that data is updated by a UWP desktop app and sent to thetable… Now, Unity android app is suppose to read data from that same table and display… Is it possible through your code? Do I still require facebook SDK and authentication? or can I ignore it?

    Like

  12. private void SelectFilteredExecute(bool includeTotalCount)
    {
    EasyTableQueryHelper queryHelper = new EasyTableQueryHelper();

    string pn = “d”;
    var query = queryHelper.Where(x => x.masterscore > 50 || x.username.StartsWith(pn)).OrderBy(x => x.masterscore);

    if (includeTotalCount)
    query = query.IncludeTotalCount();

    EasyTables.Instance.SelectFiltered(query, x =>
    {
    if (x.Status == CallBackResult.Success)
    {
    foreach (var item in x.Result.results)
    {
    Debug.Log(string.Format(“ID is {0},masterscore is {1}”, item.id, item.masterscore ));
    }
    if (includeTotalCount)
    {
    StatusText.text = string.Format(“Brought {0} rows out of {1}”, x.Result.results.Count(), x.Result.count);
    }
    else
    {
    StatusText.text = string.Format(“Brought {0} rows”, x.Result.results.Count());
    }
    }
    else
    {
    ShowError(x.Exception.Message);
    }
    });
    StatusText.text = “Loading…”;
    }

    Like

  13. I tried this tutorial and it actually worked. But as I look at the easy tables section of my app service in azure, the inserted values of the added columns in the easy tables were not sent to azure and are not seen in the easy tables, only the columns id, createdAt, updateAt, verifiedAt, and deleted have values in it. Any response/comment/suggestion would really help a lot.

    Like

  14. I just changed the object to be sent. Instead of HighScore, I changed it to Player object with its corresponding attributes.

    Like

Leave a comment