I have deployed .Net core function app in Azure. Have successfully created a Build and release pipeline. When I go the the specific function in Azure and click the button Get Function URL, I dont see function key appended to the url
All i see is the following error
https://srlcustomermanagerapp.azurewebsites.net/api/customers-details
When I try to run this url , I get 500 internal error. I have run the function app locally and it runs perfectly fine.
Am I missing some configuration in the Azure portal as when I click the Get Url button I should be getting an URL with the function key to it
I tried running the function from code + Test shown below as well as using postman and get 500 error
Screenshot
Get Function URL
Function
public class GetCustomersOrders
{
private readonly ICustomerOrdersRepository _repo;
private readonly IMapper _mapper;
private readonly TelemetryClient _telemetryClient;
public GetCustomersOrders(ICustomerOrdersRepository repo, IMapper mapper, TelemetryConfiguration configuration)
{
_repo = repo;
_mapper = mapper;
_telemetryClient = new TelemetryClient(configuration);
}
[FunctionName("GetCustomersOrders")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "customer-orders")] HttpRequest req,
ILogger log)
{
this._telemetryClient.TrackTrace("C# HTTP trigger function processed a request.");
var customersOrders = _repo.GetCustomerOrders();
return new OkObjectResult(_mapper.Map<List<CustomerOrdersViewModel>>(customersOrders));
}
}
The configuration setting "authLevel": "anonymous" may be to blame. As per the documentation:
Functions lets you use keys to make it harder to access your HTTP function endpoints during development. Unless the HTTP access level on an HTTP triggered function is set to anonymous, requests must include an API access key in the request.
So my guess is that the function isn't expecting a function key because of this setting, and the fact you're getting a 500 back is a red herring and nothing to do with a missing function key.
Related
My goal is to:
In scheduled functions - add message to SignalR
In SPA application (vue.js) subscribe to the event and call API to update the view
For now I'm trying to get anything to/from SignalR in my Function app (isolated, .net 6.0).
What I have in a function app:
[Function("negotiate")]
public HttpResponseData Negotiate(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req,
[SignalRConnectionInfoInput(HubName = "AdminHub", ConnectionStringSetting = "AzureSignalRConnectionString")] SignalRConnectionInfo connectionInfo)
{
_logger.LogInformation($"SignalR Connection URL = '{connectionInfo.Url}'");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString($"Connection URL = '{connectionInfo.Url}'");
return response;
}
}
[Function("SendMessage")]
[SignalROutput(HubName = "AdminHub", ConnectionStringSetting = "AzureSignalRConnectionString")]
public SignalRMessage SendMessage(
[HttpTrigger(AuthorizationLevel.Anonymous, "get")] Microsoft.Azure.Functions.Worker.Http.HttpRequestData req)
{
return
new SignalRMessage
{
Target = "cancelToHandle",
MethodName = "cancelToHandle",
Arguments = new[] { "hello" }
};
}
[Function("SignalRTest")]
public static async Task SignalRTest([SignalRTrigger("AdminHub", "messages", "cancelToHandle", ConnectionStringSetting = "AzureSignalRConnectionString")] string message, ILogger logger)
{
logger.LogInformation($"Receive {message}.");
}
Negotiate function is not called. When should it be called?
If I call SendMessage, no error, but nothing happens in SignalR service. Should I see connections and messages there? (zero in the Metrics for now).
I've tried to create a test "emulator" client - just a console application:
var url = "http://<azureSignalRUrl>/AdminHub";
var connection = new HubConnectionBuilder()
.WithUrl(url)
.WithAutomaticReconnect()
.Build();
// receive a message from the hub
connection.On<string, string>("cancelToHandle", (user, message) => OnReceiveMessage(user, message));
await connection.StartAsync();
// send a message to the hub
await connection.InvokeAsync("SendMessage", "ConsoleApp", "Message from the console app");
void OnReceiveMessage(string user, string message)
{
Console.WriteLine($"{user}: {message}");
}
and it throws the exception ": 'A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (:80)'
I think I'm missing overall understanding of what is supposed to happen:
when should negotiate function be triggered
can I see messages that I send in Azure portal (in SignalR service)?
how can I easily receive them in testing purposes
what do parameters/properties mean (target / method name / category). Example:
SignalRTriggerAttribute has the following constructor
public SignalRTriggerAttribute(string hubName, string category, string #event, params string[] parameterNames);
and Output binding receives any custom model I create?
which settings should be set in SignalR service - for now all I set it Serverless mode + CORS
Here are the few link which will help in using SignalIr service extension in functions
Using SignalIr service extension
https://github.com/Azure/azure-functions-dotnet-worker/blob/main/samples/Extensions/SignalR/SignalRFunction.cs
Below is the sample link for triggering negotiate function
https://github.com/Log234/azure-functions-signalr-dotnet-isolated-demo/blob/main/SignalRDemo/NegotiationFunctions.cs
for complete understanding of SignalIR here is the Github and MS document.
I have created below HttpTrigger function which takes CosmosDb item as input. This code works perfectly fine on when run locally. I am using Visual Studio Code to create function and deploying to Azure after successfully ran locally. But it doesn't work on Azure, it doesn't give error or it seems it not getting any response.
public static class HttpTriggerWithCosmosDb
{
[FunctionName("HttpTriggerWithCosmosDb")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "HttpTriggerWithCosmosDb/{id}")] HttpRequest req,
[CosmosDB(
databaseName : "func-io-learn-db",
collectionName : "Bookmarks",
ConnectionStringSetting = "CosmosDBConnection",
Id = "{id}",
PartitionKey = "{id}"
)] BookMarkItem item,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = item.Url;
Console.Write( item.Id);
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
string responseMessage = string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}
}
While publishing, in output I see below message:
HttpTriggerCSharp1:
https://nps-func.azurewebsites.net/api/HttpTriggerCSharp1
TestMessage: https://nps-func.azurewebsites.net/api/TestMessage
5:33:02 PM nps-func: WARNING: Some http trigger urls cannot be
displayed in the output window because they require an authentication
token.
It is not showing This above function in response.
Update:
Full code can be found on Git
I got the issue, what is happening here. I had to manually add CosmosDBConnection to Azure with Azure Function:Add New Settings... command before I publish the function.
I am new to function, I was not aware this is how app_settings need to be added.
I've created a test HTTP Trigger azure function. I can trigger it correctly on azure portal and browser. However trigger from Unity editor gives "Error HTTP/1.1 500 Internal Server Error".
starting Azure function:
public static async Task<IActionResult> Run(HttpRequest req, ILogger log){
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");}
My Unity code:
formData.Add(new MultipartFormDataSection("name", "SampleName", "text/plain"));
UnityWebRequest www = UnityWebRequest.Post("https://samplefunction.azurewebsites.net/api/HttpTriggerTest?herelongblob", formData);
yield return www.SendWebRequest();
Azure CORS configuration: Request Credentials ON: Enable Access-Control-Allow-Credentials.
Function is setup always on. Integrate-Trigger: selected methods GET, POST. Authorisation level:Function.
function's host.json: "version": "2.0", "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[1.*, 2.0.0)"
App Service authentication:Anonymous
Unity-Azure sdk and google setup search results seems all outdated/not supported :(
What route should I take to get this to work please? happy to try any sdk / unity asset store to reach azure you may suggest! Cheers!
The error occurs in the two lines below in your code:
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
Since you set text/plain in your code. So when you do the www.SendWebRequest(), it will send a form data but not a json format data. So it will show the error message.
Below I provide the code for your reference:
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var arr = req.Form.Keys;
foreach (var key in arr) {
log.LogInformation(key);
log.LogInformation(req.Form[key]);
}
return (ActionResult)new OkObjectResult("success");
}
You can get the key and the value of the form data in the code above and then compose them to json format and then do DeserializeObject. Or if you want to use the data to create a object, you can even do not do DeserializeObject and just set the value into your object directly.
By the way, you can also try to change the text/plain to application/json in your code new MultipartFormDataSection("name", "SampleName", "text/plain"). But, as I don't know much about MultipartFormDataSection, so I'm not sure if this solution can work.
Hope it helps.
I need to be able to identify the key (ideally key name) provided in the header (x-functions-key) for the POST to the Azure Function in the Run method, e.g.
Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log, ClaimsPrincipal principal)
It is great to be able to protect access to the Azure Function adding Function Keys in the Azure Portal panel, but I must be able to tell which function key was used. Ideally it would be possible to associate claims on each function key, but as long as I can at least figure out which key was used I will be happy.
Simply get the claim "http://schemas.microsoft.com/2017/07/functions/claims/keyid" from the req.HttpContext.User.Claims object. It contains the key id in case a Function key was used.
Works like a charm, and does not require external lookups.
const string KEY_CLAIM = "http://schemas.microsoft.com/2017/07/functions/claims/keyid";
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
var claim = req.HttpContext.User.Claims.FirstOrDefault(c => c.Type == KEY_CLAIM);
if (claim == null)
{
log.LogError("Something went SUPER wrong");
throw new UnauthorizedAccessException();
}
else
{
log.LogInformation( "Processing call from {callSource}", claim.Value);
}
Sajeetharan answered how you can get the Keys using REST API.
About the ability to use RBAC, you need to use Managed Identities and you can find more information about how to set it up: https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=dotnet
In Azure Functions v1:
[FunctionName("MyAuthenticatedFunction")]
public static async Task<HttpResponseMessage> MyAuthenticatedFunction([HttpTrigger(AuthorizationLevel.Function)] System.Net.Http.HttpRequestMessage reqMsg, ILogger log)
{
if (reqMsg.Properties.TryGetValue("MS_AzureFunctionsKeyId", out object val))
log.LogInformation($"MS_AzureFunctionsKeyId: {val}");
}
Code reference: WebJobs.Script.WebHost/Filters/AuthorizationLevelAttribute.cs#L77
I want to make an Azure Function that takes a JSON body passed to it and inserts this document in to an Azure COSMOSDB instance.
To do so, I created this function in the Azure Functions Portal:
And implement the function like so:
#r "Newtonsoft.Json"
using Newtonsoft.Json.Linq;
using System.Net;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, object outputDocument)
{
var requestContent = await req.Content.ReadAsStringAsync();
log.Verbose($#"Received request:\n{requestContent}");
var newDoc = JObject.Parse(requestContent);
newDoc["Id"] = Guid.NewGuid().ToString();
newDoc["shardKey"] = newDoc.Value<string>(#"Id").Substring(8);
outputDocument = newDoc;
return req.CreateResponse(System.Net.HttpStatusCode.Created);
}
In the portal, I put in an easy sample doc:
{
"prop1": 2,
"prop2": "2017-02-20",
}
and click 'Run'
I'm immediately met with
as an overlay in the portal IDE along with
{
"id": "145ee924-f824-4064-8364-f96dc12ab138",
"requestId": "5a27c287-2c91-40f5-be52-6a79c7c86bc2",
"statusCode": 500,
"errorCode": 0,
"message": "'UploadDocumentToCosmos' can't be invoked from Azure WebJobs SDK. Is it missing Azure WebJobs SDK attributes?"
}
in the log area.
There seems to be nothing I can do to fix the issue, yet I sure feel like I'm doing everything right.
What do I need to do to simply take a JSON object as an HTTP Request to an Azure Function, and insert/upsert said object in to an Azure Cosmos DB instance??
For async functions you should use IAsyncCollector:
public static async Task<HttpResponseMessage> Run(
HttpRequestMessage req, TraceWriter log,
IAsyncCollector<object> outputDocuments)
{
...
await outputDocuments.AddAsync(newDoc);
}
Can you try adding out to dynamic outputDocument?
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, out dynamic outputDocument)