Monday 2 December 2013

Unity3D 4.3 and WCF Web Service

This post is about how I got Unity3D to talk to my WCF web service. I don’t know if this will be of any use in the future for development on the XB1 as I have no idea what MS are going to allow on their network, I am guessing it will be quite locked down, just as it was for XNA on the 360, but felt it was worth looking at anyway, as I am using Unity3D I may want to deploy to other platforms anyway, so this could still be useful.

So, why can’t I just add a service reference and use that?

Well, you can, and in VS it will build, but, Unity3D won’t have a clue what you are trying to reference..

What helped me find the solution I came to?

As you do, I had a mooch on google, and came across a number of post and cross posts that pointed to this method of accessing a web service in Unity. For some reason, when I used this method, Unity3D would complain about the System.ServiceModel namespace, so, I thought, after finding this link saying I can just drop an assembly in and it gets picked up by Unity3D, I dragged and drop System.ServiceModel and System.Runtime.Serialization into my assets script folder. All this seemed to do was throw up another issue, with the HTTP binding. The assemblies I was adding were .NET 3.0, as I now know, Unity3D is really only compliant with 2.0, though I am sure I read somewhere that it’s a bit of a mix between 2.0 and 3.5, what ever the case, it didn’t like me assembles. In the original post I found it mentioned moving the assemblies to the mono folder, naturally I ignored this, I was not using mono, but, it gave me the idea to start looking around the Unity3D mono installation, and I found a set of C# assemblies in there, two of which are the ones I wanted, so, in an act of desperation, I copied those two assemblies over into my assets script folder….and it only bloody worked!

How am I doing it now?

So, create your WCF service as you would normally, I am using .NET4.0 for mine. Before you do anything else, create a WebClient folder in your script folder, I do this just to keep it separate, you could just drop it anywhere in your assets folder I guess.
As in the original post describing how to do this I use svcutil to build the proxy class for my Unity3d scripts to use, I created a very simple cmd file that I can run for this, before you run it, make sure your service is running, or it wont be able to build it.

cd "f:\development\unity\killercore\webservice"
cls
svcutil -out:F:\Development\Unity\KillerCore\Assets\Scripts\WebClient\KillerCoreWebService.cs http://localhost:9997/KillerCoreWebService.svc?wsdl

copy "C:\Program Files (x86)\Unity\Editor\Data\Mono\lib\mono\2.0\System.Runtime.Serialization.dll" "F:\Development\Unity\KillerCore\Assets\Scripts\WebClient\System.Runtime.Serialization.dll"
copy "C:\Program Files (x86)\Unity\Editor\Data\Mono\lib\mono\2.0\System.ServiceModel.dll" "F:\Development\Unity\KillerCore\Assets\Scripts\WebClient\System.ServiceModel.dll"

IMPORTANT: Only run this cmd in a Visual Studio Command prompt.
As you can see it copies my resulting code into my script folder, it then also copies the mono assemblies I need into that folder too. Switch back to Unity3D and it will load the new cs script and dll’s
KCUWSRef
And that is pretty much that, I can now access my WCF web service from with in my Unity3D game.

KillerCoreWebService Call

My very simple service has one method at the moment called GetHighScoreTable, and for the sake of testing looks like this:
public HighScoreResponse GetHighScoreTable()
{
    HighScoreResponse hst = new HighScoreResponse();

    for (int x = 0; x < 10; x++)
        hst.HighScoreTable.Add(new HighScoreEntity(string.Format("High Score {0}", x + 1), (x + 1 * 501).ToString()));

    return hst;
}
So, my response class holds a list or array of HighScoreEntity, this “entity” just holds a name and a value for a high score, naturally I would wire this up to a database on my server, but this will do for my test, just passing back 10 values.

Client side use of the Web Service

I have a globals script that I use to hold stuff I want to use all over the place, so, the first thing I need is a client object to connect to the service, like this
static KillerCoreWebServiceClient client = new KillerCoreWebServiceClient(new BasicHttpBinding(BasicHttpSecurityMode.None), new EndpointAddress("http://localhost:9997/KillerCoreWebService.svc"));
This client is connecting to the service running on my system, so you would alter the url to point at the service on your server. I then create a static method I can use to call a method on the service.
public static List<HighScoreEntity> GetHighScores()
{
    HighScoreResponse response = client.GetHighScoreTable();

    return response.HighScoreTable.ToList();
}
So, this simply goes off to the web service and gets the high score table.. Now in my test UI I wire it up under a button click.
if (GUI.Button(new Rect(0, 0, 100, 50), "Get Highscores"))
{
    scores = Globals.GetHighScores();
}

if (scores.Count > 0)
{
    GUI.Label(new Rect(10, 110, 100, 20), string.Format("{0} Records", scores.Count));
    int cnt = 0;
    foreach (HighScoreEntity score in scores)
    {
        cnt++;
        GUI.Label(new Rect(10, 110 + (cnt * 20), 100, 20), string.Format("{0} - {1}", score.Name, score.Score));
    }
}
scores is just a list of HighScoreEntity, once populated I display how many records have been returned and the records returned.
1398370_10151784623107218_659661404_o[1]
So, after all my moaning and whinging, it turned out not to be that difficult to set up Unity3D so it can access a WCF web service. I hope this helps make your life a bit easier integrating WCF services into your Unity3D projects. If you find a better way, or have issues with this method, then let me know.

[UPDATE]
Tested this for the Web player and it does not work, I guess just the full executable version, if I do need WS ill end up having to write a post/get class to pull stuff back from a server, unless Unity3D gets an update to the .NET framework I guess.
[/UPDATE]

4 comments:

  1. Hi Charles, wouldn't it be easier to implement a REST service and use the native WWW class from Unity3D
    If you check in this article, it demonstrates getting data from a REST service for use in Unity.
    http://through-the-interface.typepad.com/through_the_interface/2012/04/calling-a-web-service-from-a-unity3d-scene.html

    The WWW class also supports POST as well.
    http://docs.unity3d.com/Documentation/ScriptReference/WWW.html

    An added benefit is that since the WWW class is native to Unity, you don't need to worry about all the cross platform issues as well

    ReplyDelete
    Replies
    1. Yes, we discussed this on the Unity FB group, and that is indeed one way to go about it, and at the moment as Unity3D does not fully support WCF that would be the way to go, as you can probably see in my [UPDATE/] section at the bottom.

      It seems a step backwards to have to use REST, so I am hoping for an update to it WCF could be used in the web player too. But, in the mean time, I can now at least use WCF in a windows deployment :D better than nothing I guess..

      Delete
    2. Unfortunately, in current versions of Unity, this method does not seem to work any longer :(

      http://forum.unity3d.com/threads/invalid-il-code-when-consuming-webservices.296151/#post-1978548

      Delete
    3. Not tried it, that's a shame, thanks for letting me know though mate :)

      Delete