With CloudCode C# module, is it possible to customize how the return value of a method is JSONified ?
My game client expects a JSON response formatted in a certain way but on CloudCode C# the JSON serialization is not the same, so when I get a response from a endpoint it might not be in the correct format (for example I serialize some struct with a custom JsonConverter, from System.Text.Json).
Right now, I can workaround this by serializing to JSON my structs with the same way as I do on my client and return the as a string, but I would like to use the actual type of my structs for the return type.
The thing is that I don’t use the Unity’ SDK to use their services, I use their REST API directly (for reasons, using their SDK is not the solution !). I also use System.Text.Json to serialize/deserialize my stuff to JSON, but I think that CloudCode module using something else to handle JSON (maybe Newtonsoft.Json), and there is most likely differences in how the JSON is serialized/deserialized.
That is why I would like to customize how CloudCode serializes the return value to Json, because my game client expects the response to be formatted a certain way. I have customs JsonConverter, but the JSON string returned by CloudCode is not formatted as it should for my client, so I end up with default value for some type …
Cloud Code uses Newtonsoft.Json - you can apply custom serialization using Newtonsoft classes/attributes. Newtonsoft has a very similar JsonConverter/JsonConverterAttribute implementation to System.Text.Json, so it should be able to fit your use case.
Great thanks ! If I set JsonConvert.DefaultSettings in a ICloudCodeSetup class (in the the Setup method), will it use that settings in a module call ?
Another issue somewhat related : it seems that CloudCode module doesn’t support parameters where the type is nested in another type, like MyClass.MyNestedClass. When I try to call a module that have a nested type parameter, the call fail with a code 422 - Invocation Error.
Edit : it also doesn’t work if any of the field or sub-fields of struct/class contains a field of a nested type.
I dont know the answer to that off the top of my head, but Dan probably does, otoh
You have access to things like JsonProperty and JsonIgnore as well. Just be careful that you’re using the attribues that come from the Newtonsoft namespace, as the ones from Microsoft’s System.Text.Json copied nearly identical api, so it’s easy to confuse which one is being applied. (i.e.: There’s a JsonProperty in the Newtonsoft namespace and another one in System.Text.Json, the one that matters is the former).
With regards to the nested type, that’s a rather strange limitation, but just to confirm, if I have this:
class TypeOne
{
class TypeNested {} // this cannot be used
}
But if the type is not nested, it’ll work?
Would love to get some insight as to why this is the case ! might be an opportunity for us to improve on it
Good question. We intended for attributes to be used for this, the DefaultSettings option is untested and I can’t confirm that it will be used. I’ll look into this.
Nested types are supported. Are you sure that you’re exposing the nested class/struct? The default accessibility for a nested class is private, in which case Cloud Code won’t be able to see it. Does it work if it’s explicitly declared as public? Also, make sure any classes/structs used have a public parameterless constructor.
Yes, my nested struct are public, all field are get/set properties and have a default ctor. I worked around this by creating duplicate structs with the same layout, but not nested. It okay for now as I don’t have a lot to duplicate, but I would rather use the right one.
There is some limitations right now, mainly that it is not possible to authenticate with a Service Account and also impersonate another player with the said Service Account. This make some feature unusable of the game server, unless I use the RESP API directly. I implemented my own API binding and a SDK, which allows my to use the same code base on my client and server, and I can use my API binding on Cloud Code too, which is nice.
Bumping again! We should really be able to customize the DefaultSettings object! Including type information (via TypeNameHandling.All) in my responses is required!
Related: it would be important to set MissingMemberHandling to ignore to improve backwards compatibility when making cloud code additions. Otherwise whenever you add a new data field on a class model, old clients break unnecessarily because they do not know about the new data member.
DeserializationException: Could not find member
at Unity.Services.CloudCode.Internal.Http.JsonObject.GetAs[T]
By default NewtonSoft ignores, but looks like Unity services.core explicitly sets to Error by default.
If you are developing for mobile, JSON for data transfer between client and Cloud Code is pretty much a non-starter. You’ll soon end up in a situation that your new server version will not be able to talk to an older client version.
We just implemented Protobuf-net serialization for client-cloud code data with a single cloud endpoint to process all cloud calls. The data is base64 encoded in the JSON.
In case it helps anybody else, I was able to customize the Json handling during deserialization by adding a partial class with the same generated class name into the CloudCode/GeneratedModuleBindings folder. For instance below I’m able to set MissingMemberHandling to ignore new fields.
using Newtonsoft.Json;
namespace Unity.Services.CloudCode.GeneratedBindings.GameServer
{
// This partial class exists to modify GameModel deserialization parameters
// Since the real GameModel is generated as a partial class, we can tag it here
// Now when we add new members to the server it will not immediately break
// old clients that do not know about that field
[JsonObject(MissingMemberHandling = MissingMemberHandling.Ignore)]
public partial class GameModel
{
static GameModel() { }
}
}