[英]My firebase callable cloud function is called twice (when I called only once), how can I avoid my flutter app from failure?
[英]How can I send custom object from my callable Firebase Cloud Function in TypeScript to my Unity app?
我正在嘗試為我的 Unity 項目使用 Firebase 及其可調用的 Cloud Functions。
通過我在 web 上找到的文檔和不同的帖子,我很難理解返回數據的工作原理。 (本人來自Azure Functions in C#)
我使用 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
是父 class 只有一個UnknownErrorMessage
字符串屬性,我用它來在需要時添加額外的消息,但僅限於 Unity。我的函數中不需要它。)
我的 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,
}
我仍在學習,但我發現以這種方式在 Unity 中顯示正確的消息(以及關於本地化)很有用。 當代碼為 0(成功)時,我通常需要同時獲取一些數據,如本例中的CharacterID
或 CharacterLevel、 CharacterResponse
等。CharacterResponse 將用於所有與字符相關的函數,如“GetAllCharacters”、“CreateNewCharacter” “ ETC..
我的 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;
});
在 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());
}
}
});
}
問題:在我的 Unity C# 代碼中, task.Result.Data
包含我在 function 中設置的CharactersCode
,但我找不到將其轉換為 CharactersResponse 的方法。 (它在 Azure 函數中起作用)。 此外,Deserialization Debug.Log("Deserialized response");
之后的行沒有被執行。 代碼似乎卡在了反序列化過程中。
我嘗試使用和不使用CustomResponse
擴展我的 TypeScript class(因為我的 Function 中不需要它,所以我一開始沒有擴展它)。 我還嘗試設置一個 CharacterID,因為我認為它可能不喜歡這個屬性丟失的事實,但結果是一樣的。
我不明白這里有什么問題? 如果你們中的任何一個可以提供幫助。
謝謝。
HttpsCallableResult.Data
的類型為object
!
=> 您的ToString
將簡單地返回類型名稱,例如
System.Object
或者在您的情況下,結果是一個字典,因此它會打印出該類型。
=> 這當然不是有效的 JSON 內容,也不是您所期望的。
只需自己從數據中構建結果:
var result = (Dictionary<string, object>)task.Result.Data;
CharactersResponse response = new CharactersResponse
{
Code = (CharactersCode)(int)result["Code"],
CharacterID = (string)result["CharacterID"];
};
我想實施 derHugo 的解決方案,但找不到將task.Result.Data
轉換為Dictionary<string, object>
的方法。 代碼卡在var result = (Dictionary<string, object>)task.Result.Data;
即使在逐步調試中也沒有彈出錯誤。
舊解決方案:
所以我做了一些研究並偶然發現了這篇文章並最終改用了這個:
var json = JsonConvert.SerializeObject(task.Result.Data);
CharactersResponse response = JsonConvert.DeserializeObject<CharactersResponse>(json);
我基本上將task.Result.Data
轉換為 JSON 並將其轉換回CharactersResponse
並且它有效。 我有我想要的。 然而,我似乎明白這不是性能方面的最佳解決方案,但現在還可以,我現在可以繼續推進項目,稍后我會嘗試找到更好的解決方案。
新解決方案:
出於好奇,我想嘗試最后一件事。 我想知道如果我在開始時(在我的函數中)而不是在結束時(在我的 Unity 應用程序中)轉換為 JSON 會怎么樣。 所以我在函數的 TypeScript 代碼中這樣做了:
response.Code = CharactersCode.InvalidName;
var r = JSON.stringify(response); // Added this line
return r; // return 'r' instead of 'response'
在我的 C# 代碼中,我重試了這行代碼:
CharactersResponse response = JsonConvert.DeserializeObject<CharactersResponse>(task.Result.Data.ToString());
它有效。 我只需要在返回之前將我的 object 轉換為 function 中的 JSON。 與舊解決方案相比,它允許我“節省”一行代碼在客戶端進行處理。
感謝 derHugo 的回答,因為它幫助我找到了我想要的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.