简体   繁体   English

如何从 TypeScript 中的可调用 Firebase Cloud Function 向我的 Unity 应用程序发送自定义 object?

[英]How can I send custom object from my callable Firebase Cloud Function in TypeScript to my Unity app?

I'm trying to use Firebase and its callable Cloud Functions for my Unity project.我正在尝试为我的 Unity 项目使用 Firebase 及其可调用的 Cloud Functions。

With the docs and different posts I found on the web I struggle to understand how returning data works.通过我在 web 上找到的文档和不同的帖子,我很难理解返回数据的工作原理。 (I come from Azure Functions in C#) (本人来自Azure Functions in C#)

I use TypeScript, and try to return a custom object CharactersResponse :我使用 TypeScript,并尝试返回自定义 object CharactersResponse

export class CharactersResponse //extends CustomResponse
{
    Code!: CharactersCode;
    CharacterID?: string;
}

export enum CharactersCode
{
    Success = 0,
    InvalidName = 2000,
    CharacterNameAlreadyExists = 2009,
    NoCharacterSlotAvailable = 3000,
    InvalidCharacterClass = 4000,
    EmptyResponse = 9000,
    UnknownError = 9999,
}

( Custom Response is a parent class with only an UnknownErrorMessage string property, that I use for adding extra message when needed, but only in Unity. I don't need it in my functions.) Custom Response是父 class 只有一个UnknownErrorMessage字符串属性,我用它来在需要时添加额外的消息,但仅限于 Unity。我的函数中不需要它。)

I have the same in my C# Unity Project:我的 C# Unity 项目中有相同的内容:

public class CharactersResponse : CustomResponse
{
    public CharactersCode Code;
    public string CharacterID;
}

public enum CharactersCode
{
    Success = 0,
    InvalidName = 2000,
    CharacterNameAlreadyExists = 2009,
    NoCharacterSlotAvailable = 3000,
    InvalidCharacterClass = 4000,
    EmptyResponse = 9000,
    UnknownError = 9999,
}

I'm still learning but I found it useful to do this way for displaying correct messages in Unity (and also regarding localization).我仍在学习,但我发现以这种方式在 Unity 中显示正确的消息(以及关于本地化)很有用。 When the Code is 0 (Success), I will usually need to get some data at the same time like in this example CharacterID , or CharacterLevel, CharacterName etc.. CharacterResponse will be used for all functions regarding Characters like "GetAllCharacters", "CreateNewCharacter" etc..当代码为 0(成功)时,我通常需要同时获取一些数据,如本例中的CharacterID或 CharacterLevel、 CharacterResponse等。CharacterResponse 将用于所有与字符相关的函数,如“GetAllCharacters”、“CreateNewCharacter” “ ETC..

My Function ( CreateNewCharacter ) looks like this:我的 Function ( CreateNewCharacter ) 看起来像这样:

import * as functions from "firebase-functions";
import { initializeApp } from "firebase-admin/app";
import { getFirestore } from "firebase-admin/firestore";
import { CharactersResponse } from "./CharactersResponse";
import { CharactersCode } from "./CharactersResponse";
import { StringUtils } from "../Utils/StringUtils";

// DATABASE INITIALIZATION
initializeApp();
const db = getFirestore();

// CREATE NEW CHARACTER
export const CreateNewCharacter =
  functions.https.onCall((data, context) =>
  {
    // Checking that the user is authenticated.
    if (!context.auth)
    {
      // Throwing an HttpsError so that the client gets the error details.
      throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
        'while authenticated.');
    }

    // TEST
    data.text = '';

    // Authentication / user information is automatically added to the request.
    const uid: string = context?.auth?.uid;
    const characterName: string = data.text;

    // Check if UserID is present
    if (StringUtils.isNullOrEmpty(uid))
    {
      // Throwing an HttpsError so that the client gets the error details.
      throw new functions.https.HttpsError('failed-precondition', 'Missing UserID in Auth Context.');
    }

    const response = new CharactersResponse();

    if (StringUtils.isNullOrEmpty(characterName))
    {
      response.Code = CharactersCode.InvalidName;
      console.log("character name null or empty return");
      return response; // PROBLEM IS HERE *****************
    }

    console.log("end return");
    return "Character created is named : " + characterName + ". UID = " + uid;
  });

In Unity, the function call looks like this:在 Unity 中,function 调用如下所示:

private static FirebaseFunctions functions = FirebaseManager.Instance.Func;

    public static void CreateNewCharacter(string text, Action<CharactersResponse> successCallback, Action<CharactersResponse> failureCallback)
    {
        Debug.Log("Preparing Function");
        // Create the arguments to the callable function.
        var data = new Dictionary<string, object>();
        data["text"] = text;

        // Call the function and extract the operation from the result.
        HttpsCallableReference function = functions.GetHttpsCallable("CreateNewCharacter");
        function.CallAsync(data).ContinueWithOnMainThread((task) =>
        {
            if (task.IsFaulted)
            {
                foreach(var inner in task.Exception.InnerExceptions) 
                {
                    if (inner is FunctionsException)
                    {
                        var e = (FunctionsException)inner;
                        // Function error code, will be INTERNAL if the failure
                        // was not handled properly in the function call.
                        var code = e.ErrorCode;
                        var message = e.Message;

                        Debug.LogError($"Code: {code} // Message: {message}");

                        if (failureCallback != null)
                        {
                            failureCallback.Invoke(new CharactersResponse()
                            {
                                Code = CharacterCode.UnknownError,
                                UnknownErrorMessage = $"ERROR: {code} : {message?.ToString()}"
                            });
                        }
                    }
                }
            }
            else
            {
                Debug.Log("About to Deserialize response");
// PROBLEM IS HERE *********************
                CharactersResponse response = JsonConvert.DeserializeObject<CharactersResponse>(task.Result.Data.ToString());
                Debug.Log("Deserialized response");

                if (response == null)
                {
                    Debug.LogError("Response is NULL");
                }
                else
                {
                    Debug.Log("ELSE");
                    Debug.Log($"Response: {response}");
                    Debug.Log(response.Code.ToString());
                }
            }
        });
    }

The problem: In my Unity C# code, task.Result.Data contains the CharactersCode I've set in my function, but I can't find a way to convert it to CharactersResponse.问题:在我的 Unity C# 代码中, task.Result.Data包含我在 function 中设置的CharactersCode ,但我找不到将其转换为 CharactersResponse 的方法。 (It worked in Azure Functions). (它在 Azure 函数中起作用)。 Moreover, the line just after Deserialization Debug.Log("Deserialized response");此外,Deserialization Debug.Log("Deserialized response");之后的行is not executed.没有被执行。 The code seems stuck in the deserialization process.代码似乎卡在了反序列化过程中。

I tried with and without extending my TypeScript class with CustomResponse (because I don't need it in my Function so I didn't extended it at first).我尝试使用和不使用CustomResponse扩展我的 TypeScript class(因为我的 Function 中不需要它,所以我一开始没有扩展它)。 I also tried setting a CharacterID because I thought maybe it didn't like the fact that this property was missing but the result is the same.我还尝试设置一个 CharacterID,因为我认为它可能不喜欢这个属性丢失的事实,但结果是一样的。

I don't understand what is the problem here?我不明白这里有什么问题? If any of you can help.如果你们中的任何一个可以提供帮助。

Thanks.谢谢。

HttpsCallableResult.Data is of type object ! HttpsCallableResult.Data的类型为object

=> Your ToString will simply return the type name something like => 您的ToString将简单地返回类型名称,例如

System.Object

or in your case the result is a dictionary so it prints out that type.或者在您的情况下,结果是一个字典,因此它会打印出该类型。

=> This is of course no valid JSON content and not what you expected. => 这当然不是有效的 JSON 内容,也不是您所期望的。

Simply construct the result yourself from the data:只需自己从数据中构建结果:

var result = (Dictionary<string, object>)task.Result.Data;
CharactersResponse response = new CharactersResponse
{
    Code = (CharactersCode)(int)result["Code"],
    CharacterID = (string)result["CharacterID"];
};       

I wanted to implement derHugo's solution but couldn't find a way to convert task.Result.Data to Dictionary<string, object> .我想实施 derHugo 的解决方案,但找不到将task.Result.Data转换为Dictionary<string, object>的方法。 The code was stuck at var result = (Dictionary<string, object>)task.Result.Data;代码卡在var result = (Dictionary<string, object>)task.Result.Data; even in step by step debugging and no error popped up.即使在逐步调试中也没有弹出错误。

OLD SOLUTION:旧解决方案:

So I did a little research and stumbled upon this post and ended up using this instead:所以我做了一些研究并偶然发现了这篇文章并最终改用了这个:

var json = JsonConvert.SerializeObject(task.Result.Data);
CharactersResponse response = JsonConvert.DeserializeObject<CharactersResponse>(json);

I basically convert the task.Result.Data to JSON and convert it back to CharactersResponse and it works.我基本上将task.Result.Data转换为 JSON 并将其转换回CharactersResponse并且它有效。 I have what I wanted.我有我想要的。 However, I seem to understand that it is not the best solution performance-wise, but for now it is okay and I can now move forward in the project, I'll try to find a better solution later.然而,我似乎明白这不是性能方面的最佳解决方案,但现在还可以,我现在可以继续推进项目,稍后我会尝试找到更好的解决方案。

NEW SOLUTION:新解决方案:

I wanted to try one last thing, out of curiosity.出于好奇,我想尝试最后一件事。 I wondered what if I convert to JSON at the beginning (in my function) instead of at the end (in my Unity app).我想知道如果我在开始时(在我的函数中)而不是在结束时(在我的 Unity 应用程序中)转换为 JSON 会怎么样。 So I did this in my function's TypeScript code:所以我在函数的 TypeScript 代码中这样做了:

response.Code = CharactersCode.InvalidName;
var r = JSON.stringify(response); // Added this line
return r; // return 'r' instead of 'response'

In my C# code, I retried this line of code:在我的 C# 代码中,我重试了这行代码:

CharactersResponse response = JsonConvert.DeserializeObject<CharactersResponse>(task.Result.Data.ToString());

And it works.它有效。 I just needed to convert my object to JSON in my function before returning it.我只需要在返回之前将我的 object 转换为 function 中的 JSON。 It allows me to "save" one line of code to process on the client side compared to the old solution.与旧解决方案相比,它允许我“节省”一行代码在客户端进行处理。

Thanks derHugo for your answer as it helped me finding what I want.感谢 derHugo 的回答,因为它帮助我找到了我想要的东西。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我的 firebase 可调用云 function 被调用了两次(当我只调用一次时),如何避免我的 flutter 应用程序失败? - My firebase callable cloud function is called twice (when I called only once), how can I avoid my flutter app from failure? 如何提高可调用云 function 的安全性? - how to increase the security of my callable cloud function? 如何从云端访问 firebase 自定义声明 function - How can I access firebase custom claims from a cloud function 为什么我的 Firebase Cloud Function 不能使用“allAuthenticatedUsers”? - Why can't I use `allAuthenticatedUsers` for my Firebase Cloud Function? 我正在尝试将我的简单 typescript 应用程序部署到 firebase 云功能。 但我有这个错误 - I'm trying to deploy my simple typescript app to firebase cloud functions. But I have got this error 如何将我的应用程序从 firebase 获取的数据设置到我的 bottomSheetView? (科特林) - How can I set the fetched data of my app from firebase to my bottomSheetView? (Kotlin) URL 重写会使 Firebase 云 function 响应来自我的自定义域吗? - Would URL rewrite make Firebase cloud function response come from my custom domain? 如何从统一中调用 firebase 示例云 function? - how to call a firebase sample cloud function from unity? 从 Firebase 可调用 function(云功能)返回 stream 的正确方法? - Proper way to return stream from Firebase callable function (Cloud function)? 如何在 typescript 编写的谷歌云 Function 中检索和使用 firebase 数据? - How can I retrieve and use firebase data in a Google Cloud Function written in typescript?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM