question

Matt avatar image
Matt asked

Azure Functions for CloudScript Confusion

As much as I hate the complexity and unintuitive nature of Azure Functions vs the legacy Cloudscript system, I've accepted the mandate and I'm now trying to adapt. It's not going well. I think the problem is that you provided contradictory tutorials. Your PlayFab samples on github do not match your documentation for the QuickStart but are referenced there.

1. When I run an Azure Function locally, I pass in the request body {"name":"Matt"}. I assume that Json body is what the FunctionParameter would be when I call ExecuteFunction from my client. When I use the following code, however, there's no data there.

FunctionExecutionContext<dynamic> context = JsonConvert.DeserializeObject<FunctionExecut	ionContext<dynamic>>(await req.ReadAsStringAsync());
dynamic args = context.FunctionArgument;

I try to just output args and it's an empty string.

2. You mentioned having access to CurrentPlayerId the same way the legacy cloudscript did, however, I have not been able to find access to it without the compiler error for not knowing what the symbol means. The PlayFab.Samples seems to get it from the context, but the context there is just a FunctionContext of which I can't use because it doesn't exist?

3. The following line produces an error, but perhaps that's because I'm making the call locally?

string message = $"Hello {context.CallerEntityProfile.Lineage.MasterPlayerAccountId}!";

If that's the case, what's the point of running locally once I actually start building my code if it'll always return errors?

Honestly, I'm very confused as to what is correct and what is old. I can't even successfully get a function to spit out the argument I sent in, so I can only imagine it'll be more difficult once I try to actually make server calls (if I even can with how I built this).

Can someone please provide a very clear-cut example of what my function should look like, today in 2022, that would take in a Json argument, make some PlayFab server API calls, then return another Json object the way I used to in legacy cloud.

Please include the using directives, because they also don't match and I'm not even sure if, for a production build, I should be using something called PlayFab.Samples.


Thank you very much for the help, I really want to get a handle on how this works!

-Matt

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Made Wang avatar image
Made Wang answered

What I mean is that the way Cloud Script passes parameters in Azure Function is different from the Hello World case in Azure Function documentation, you need to pass parameters in FunctionParameter of ExecuteFunction, not in post body. And, in Azure Function Cloud Script you need to get parameters in args, below is the case I provided.

using System;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using PlayFab;
using PlayFab.Samples;
using System.Collections.Generic;
using PlayFab.ServerModels;

namespace Company.Function
{
    public static class Test
    {
        [FunctionName("GetUserData")]
        public static async Task<dynamic> GetUserData(
        [HttpTrigger(AuthorizationLevel.Function,"post", Route = null)] HttpRequest req, ILogger log)
        {
            FunctionExecutionContext<dynamic> context = JsonConvert.DeserializeObject<FunctionExecutionContext<dynamic>>(await req.ReadAsStringAsync());
            var args = context.FunctionArgument;
            string key = args["key"];
            var getUserDataRequest = new GetUserDataRequest
            {
                PlayFabId = context.CallerEntityProfile.Lineage.MasterPlayerAccountId,
                Keys=new List<string>()
                {
                    key
                }
            };
            var settings = new PlayFabApiSettings
            {
                TitleId = context.TitleAuthenticationContext.Id,
                DeveloperSecretKey = Environment.GetEnvironmentVariable("PLAYFAB_DEV_SECRET_KEY", EnvironmentVariableTarget.Process)
            };
            var serverApi = new PlayFabServerInstanceAPI(settings);
            var getUserDataResult =await serverApi.GetUserDataAsync(getUserDataRequest);
            return new
            {
                getUserDataResult.Result.Data[key].Value
            };
        }
    }
}

1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Matt avatar image Matt commented ·

Excellent, I truly appreciate the example. I didn't realize I had to create a serverApi instance to make the calls.

Thanks again, this was very helpful!

0 Likes 0 ·
Made Wang avatar image
Made Wang answered

1.If you want to call Azure Function Cloud Script, then you need to use Execute Function to call it instead of running it locally. As for the paremeters, as PlayFab CloudScript using Azure Functions Quickstart Guide - PlayFab | Microsoft Docs mentioned, parameters that you pass in the FunctionParameters field are available in the args. But, unlike the Hello World example in Create your first function using Visual Studio Code guide, parameters while calling ExecuteFunction are passed in the POST body instead of the query string.

2,3.You need to use Execute Function to call it, just running the function locally won't interact with the PlayFab server and won't get the CurrentPlayerId.

The local running of Azure Function is not suitable for Azure Function Cloud Script, but it has its own local debugging method, you can refer to Local debugging for Cloudscript using Azure Functions - PlayFab | Microsoft Docs.

CS2AFHelperClasses.cs is an official tool class, you can use it with confidence. Also, the samples on github are outdated and it is not recommended that you refer to it.

2 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Matt avatar image Matt commented ·

I have to say, it's frustrating that your tutorial doesn't just have the function I'm requesting right there. We don't need an outdated HelloWorld function, we need a SubmitScore function, or something equally relevant. I'm sure most people can get around the issues I'm having, but I'm confused by your GitHub samples which *do* have what I want but are apparently no longer usable.

Sorry, but I can't help but repeat...it's shocking how convoluted your documentation is for something that's already unintuitive and cumbersome compared to the old Cloudscript system that took me 15 seconds to get running.

3 Likes 3 ·
Matt avatar image Matt commented ·

Thank you very much for the response. I appreciate it!

1. I'm not particularly savvy with HTTP related code...when you say it's passed in the POST body and not the args, does that mean I cannot use the following code?

FunctionExecutionContext<dynamic> context = JsonConvert.DeserializeObject<FunctionExecutionContext<dynamic>>(await req.ReadAsStringAsync());
dynamic args = context.FunctionArgument;

2,3. Ok that makes sense that I'm getting an error if not run from the ExecuteFunction, but I still have the issue that CurrentPlayerId doesn't compile. It's fine if I can't use that locally, I would not expect to be able to, but I don't know where it exists in the first place.

Please just show me an actual function instead of sending me to read what I've read. Please, in the function, read and convert a JSON object passed via FunctionParameters in an ExecuteFunction call from the client into a class within the Azure Function. Please make a random call to a server API, using the CurrentPlayerId, and please return a JSON object to the client.


Thanks again!

-Matt

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.