Azure function CRUD on Table Storage - azure

How can we do CRUD with table storage in Azure functions:
I have insert working, but would like to know how to return entities and do updates and deletes too.
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, IAsyncCollector<User> outputTable)
{
log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
var user = new User();
user.PartitionKey = "Users";
user.RowKey = DateTime.Now.Ticks.ToString();
user.UserId = "aaaa";
user.Country = "uk";
await outputTable.AddAsync(user);
....

You can bind your function to an instance of CloudTable class, and then you get all its API at your hands.
I think you should be able to just replace IAsyncCollector<User> with CloudTable in your function definition and adjust the usage (provided you have a valid output binding).
See "Output usage" under Azure Functions Storage table bindings.

Related

Azure Function App documentation using API Management

I have created a Azure Function App. The function app connects to a SQL DB and has the following features
Return all the records in a table
Returns the records based on the column name using the below code
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
string loan_id = req.Query["loanid"];
string loan_amount = req.Query["loanamount"];
if (string.IsNullOrEmpty(loan_id)) {
//Do something when dont give loan id.
} else if (string.IsNullOrEmpty(loan_amount)) {
//DO something when dont give loan amount.
}
return new OkObjectResult("This is a test.");
}
I would like to document the function app using API Management/Swagger. Can you please let me know how this can be achieved?
Thanks in advance
You just need to create an API management service instance from the portal and add the function endpoint using the open api.
You can follow this documentation on how to do the same.

Get function key (name) used when calling Azure Function

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

Redirect service (302) in Azure, best possible approach?

I need to create a redirector that redirects user to an external domain while retaining the query params and one additional param.
e.g. When a user visits
https://contoso.com/redirect?docId=123, it will redirect the user to
https://contoso-v2.com/home?docId=123&token=xxxxxxx
Once user visits https://contoso.com/redirect?docId=123, this endpoint will process the info (from query params) and generate a token that needs to be appended in target URL.
What would be the most efficient and best way in Azure? Writing a simple Azure Web App or is there any better way?
You could use Azure Function with HttpTrigger Binding. With consumption plan the cost would be minimal (1 million invocations are free in pay-as-you-go plan).
using System.Net;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
var uri = req.RequestUri;
var updatedUri = ReplaceHostInUri(uri, "contoso-v2.com");
//return req.CreateResponse(HttpStatusCode.OK, "Original: " + uri + " Updated: " + updatedUri);
return req.CreateResponse(HttpStatusCode.Found, updatedUri);
}
private static string ReplaceHostInUri(Uri uri, string newHostName) {
var builder = new UriBuilder(uri);
builder.Host = newHostName;
//Do more trasformations e.g. modify path, add more query string vars
return builder.Uri.ToString();
}

Azure function inserting but not updating cosmosDB

I have an azure function taking in messages from an Azure service bus queue and sending documents to cosmosDB. I'm using Azure functions 1.x:
public static class Function1
{
[FunctionName("Function1")]
public static void Run([ServiceBusTrigger("ServiceBusQueue", AccessRights.Manage, Connection = "ServiceBusQueueConnection")]BrokeredMessage current, [DocumentDB(
databaseName: "DBname",
collectionName: "Colname",
ConnectionStringSetting = "CosmosDBConnection")]out dynamic document, TraceWriter log)
{
document = current.GetBody<MyObject>();
log.Info($"C# ServiceBus queue triggered function processed the message and sent to cosmos");
}
}
This inserts to cosmos successfully, but when updating I get errors:
Microsoft.Azure.Documents.DocumentClintException: Entity with the specified id already exists in the system.
They key I'm trying to update on is the partition key of that collection.
I saw this question: Azure function C#: Create or replace document in cosmos db on HTTP request
But It seems like my usage is similar to the one in Matias Quarantas answer. Also he mentioned that using an out parameter causes an upsert on cosmos.
How can I create this "upsert" function, while still using azure function 1.x?
The binding does indeed do an Upsert operation.
I created this sample Function that takes an Http payload (JSON) and stores it in Cosmos DB as-is:
[FunctionName("Function1")]
public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req,
[DocumentDB("MyDb", "MyCollection", ConnectionStringSetting = "MyCosmosConnectionString")] out dynamic document,
TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
dynamic data = req.Content.ReadAsAsync<object>().GetAwaiter().GetResult();
document = data;
return req.CreateResponse(HttpStatusCode.OK);
}
If I send a JSON payload to the Http endpoint, the output binding works as expected:
When I check the Data Explorer, I see:
If I send a second payload, this time, adding a property (same id):
The Data Explorer shows the document was updated, with the same Function code:
Can you add the full Exception/Error trace? Is your Service Bus Message including an "id"? Is your collection partitioned?
If your collection is partitioned and you are changing the value of the Partition key property, then the binding won't update the existing document, it will create a new one because the Upsert operation won't find an existing document (based on the id/partition key). But it won't throw an exception.

Custom Message Properties on Azure Queue/Topic Message from Azure Function

I would like to be able to add custom properties to a queue/topic message as I place it in a queue from and Azure Function. The custom properties are for filtering the messages into different topics. I must be missing something because this working example doesn't seem to have anywhere to put custom properties.
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req,
TraceWriter log,
ICollector<Contact> outputSbMsg)
{
var contactList = await req.Content.ReadAsAsync<ContactList>();
foreach(var contact in contactList.Contacts)
{
if (contact.ContactId == -1)
{
continue;
}
contact.State = contactList.State;
outputSbMsg.Add(contact);
}
}
I'm coding the function through the Azure Portal. The contact list comes into the function through in the body of an http request. The functions parses out each contact, adds modifies some properties and submits each contact to the queue topic. Additionally I pull other data from the request headers and the contact list and I would like to use that data in the queue topic to filter the requests into different subscriptions.
Edit:
As per #Sean Feldman's suggestion below, the data is added to a BrokeredMessage before adding the BrokeredMessage to the output collection. The key part is to serialize the contact object before adding it to the BrokeredMessage.
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req,
TraceWriter log,
ICollector<BrokeredMessage> outputSbMsg)
{
var contactList = await req.Content.ReadAsAsync<ContactList>();
foreach(var contact in contactList.Contacts)
{
if (contact.ContactId == -1)
{
continue;
}
string jsonData = JsonConvert.SerializeObject(contact);
BrokeredMessage message = new BrokeredMessage(jsonData);
message.Properties.Add("State", contactList.State);
outputSbMsg.Add(message);
}
}
Thank you
To be able to set custom/user properties, the output collector should be of a native Azure Service Bus message type, BrokeredMessage.
In your case, you'll have to change ICollector<Contact> to ICollector<BrokeredMessage>.

Resources