MicrosoftDocs / azure-docs

Open source documentation of Microsoft Azure
https://docs.microsoft.com/azure
Creative Commons Attribution 4.0 International
10.28k stars 21.47k forks source link

Please provide example for C# (isolated process) / .NET 5 #82392

Open deanwiles opened 3 years ago

deanwiles commented 3 years ago

I am trying to write an HTTP Trigger using C# (isolated process) / .NET 5.

The code created by the Visual Studio 2019 Azure Functions new project template uses HttpRequestData and HttpResponseData to access the request and response data, however the C# examples here use HttpRequest and IActionResult.

I've discovered through debugging that executionContext.BindingContext.BindingData.TryGetValue("parameter", out object value) does a pretty good job of extracting GET query parameters or top-level JSON fields in a POST body.

However I could not find any documentation or examples of getting and sending JSON objects in an HTTP Trigger using C# (isolated process) / .NET 5.

Please expand your examples / documentation to clarify the best way to implement an HTTP Trigger using C# (isolated process).

Thanks.


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

mikeurnun commented 3 years ago

Hello @deanwiles - Thank you for your feedback! We will review and update as appropriate.

MughundhanRaveendran-MSFT commented 3 years ago

Hello @deanwiles , By "Isolated Storage" do you mean "Isolated Process" also known as out of process Azure Functions? https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-csharp?tabs=isolated-process%2Cazure-cli&pivots=programming-runtime-functions-v3#configure-your-local-environment

Please let me know.

MughundhanRaveendran-MSFT commented 3 years ago

@deanwiles , still awaiting for your response. Please let me know if you are referring to Isolated process (out of process) in Azure Functions

deanwiles commented 3 years ago

Yes, thanks for catching that. I meant "isolated process".

Here is what I ended up implementing. It worked but not sure if it is ideal:

` using Azure.Core.Serialization; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Extensions.Logging; using System; using System.Net; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks;

namespace Magic8Ball.Api
{
    public static class Magic8BallApi
    {
        [Function("Ask")]
        public static async Task<HttpResponseData> Ask([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
            FunctionContext executionContext)
        {
            var logger = executionContext.GetLogger("Ask");
            logger.LogInformation("C# HTTP trigger function processing an 'Ask' request...");

            // Check for Question in GET query or in POST body
            string question = null;
            if (executionContext.BindingContext.BindingData.TryGetValue("question", out object value))
            {
                // Yes, save the string value
                question = value as string;
            }
            logger.LogInformation($"Question = '{question}'.");

            // Ask the Classic Magic 8 Ball service the provided question
            var magic8Ball = new Classic.ClassicMagic8Ball();
            try
            {
                await magic8Ball.AskAsync(question);
                logger.LogInformation($"Answer = '{magic8Ball.Answer}', Type = '{magic8Ball.Type}'.");
            }
            catch (Exception ex)
            {
                // Return error message
                string msg = ex.Message;
                if (null != ex.InnerException) msg += $"{Environment.NewLine}{ex.InnerException.Message}";
                var error = req.CreateResponse(HttpStatusCode.BadRequest);
                await error.WriteStringAsync(msg);
                return error;
            }

            // Create JSON serializer that handles enumerations
            var options = new JsonSerializerOptions
            {
                WriteIndented = true,
                Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
            };
            var serializer = new JsonObjectSerializer(options);

            // Return Magic8Ball object as JSON
            var response = req.CreateResponse(HttpStatusCode.OK);
            await response.WriteAsJsonAsync(magic8Ball, serializer);

            return response;
        }

        [Function("App")]
        public static HttpResponseData App([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req,
            FunctionContext executionContext)
        {
            var logger = executionContext.GetLogger("App");
            logger.LogInformation("C# HTTP trigger function processing an 'App' request...");

            // Redirect to Magic 8 Ball Azure Static Web App
            string Url = Environment.GetEnvironmentVariable("Magic8Ball_WebApp_URL");
            var response = req.CreateResponse(HttpStatusCode.Moved);
            response.Headers.Add("Location", Url);

            return response;
        }
    }
}

`

ggailey777 commented 3 years ago

@deanwiles sorry that we are a little behind updating the binding reference docs with C# isolated process (.NET 5.0) examples. In the meantime, you can review the reference sample in the project repo.

deanwiles commented 3 years ago

Thanks, I had already reviewed that sample. Unfortunately there appears to be minimal documentation and no samples covering how to extract incoming data (GET parameters or PUT json body), nor the recommended way to build a json response with the new HTTPTrigger method parameters. Through debugging and trial and error, I did discover that the executionContext.BindingContext.BindingData provided a lot of help extracting the input data, including the root json fields. Hopefully that behavior is by design and will soon be documented. If you have any suggested improvements for what I implemented above, that would be appreciated. Thanks again, Dean