Azure HTTP function failing to publish - c#

I am attempting to publish my Azure HTTP function from Visual Studio Code to our Azure platform.
The code works fine when running the function locally and publishes successfully but throws out the following error when published.
I have tried using DocumentDB instead of CosmosDB but that lacks the insert functionality required for inserting data into CosmosDB. Stackoverflow has no solutions to a problem this specific.
Function code
//write to cosmosdb
[FunctionName("InsertItem")]
public static HttpResponseMessage Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]HttpRequestMessage req,
[CosmosDB(
databaseName: "ToDoList",
collectionName: "RFIDContainer",
ConnectionStringSetting = "myCosmosDBConnection")]
out RFIDBaseTag document,
ILogger log)
{
string hexData = "";
string afi = "";
string eid = "";
string dsfid = "";
//Guid DeviceID = new Guid();
//Guid AppID = new Guid();
var content = req.Content;
string jsonContent = content.ReadAsStringAsync().Result;
dynamic json = JsonConvert.DeserializeObject<MyClass>(jsonContent);
hexData = json?.hexData;
afi = json?.afi;
eid = json?.eid;
dsfid = json?.dsfid;
/*Guid devGuid;
Guid.TryParse(json.AppID.ToString(), out devGuid);
DeviceID = devGuid;
Guid appGuid;
Guid.TryParse(json.AppID.ToString(), out appGuid);
AppID = appGuid;*/
byte[] hexToByte = AzureRFIDTagReader.StringToByteArray(hexData);
RawRFIDReading raw = new RawRFIDReading();
raw.afi = afi;
raw.eid = eid;
raw.dsfid = dsfid;
raw.RawData = hexToByte;
RFIDBaseTag rtag = RFIDTagFactory.GetTag(raw);
string serializedtag = JsonConvert.SerializeObject(rtag);
//document = JsonConvert.DeserializeObject<MyClass>(jsonContent);
//document = JsonConvert.DeserializeObject<RFIDBaseTag(serializedtag);
document = rtag;
log.LogInformation($"C# Queue trigger function inserted one row");
return new HttpResponseMessage(HttpStatusCode.Created);
}
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=xxxx;AccountKey=zzzz",
"myCosmosDBConnection": "AccountEndpoint=xxx:443/;AccountKey=www;"
}
}
Error Message:
Function (xxx/InsertItem) Error: Microsoft.Azure.WebJobs.Host: Error indexing method 'InsertItem'. Microsoft.Azure.WebJobs.Host: Unable to resolve the value for property 'CosmosDBAttribute.ConnectionStringSetting'. Make sure the setting exists and has a valid value.
I am able to post to the function locally but not on Azure.
Any suggestions?

When you publish your Function, your local.settings.json file is not published.
You need to add those settings as part of the Azure Functions Application Settings. In your case, you need to add myCosmosDBConnection there with the value.

Related

Create Lambda proxy integration inside a non-root resource in API Gateway using AWS SDK with C#

The bounty expires in 7 days. Answers to this question are eligible for a +100 reputation bounty.
Harun Ćerim is looking for an answer from a reputable source:
A detailed explanation of how Lambda integration can be done on a non-root resource inside an API Gateway where routes are currently mapped to an underlying Lambda function and its underlying routes
I am trying to create a proxy integration for Lambda invocation from API Gateway for a specific route (example.com/auth/{proxy+}, example.com/user/{proxy+}, etc..).
I am creating a script for automated infrastructure initialization and deployment (without using CloudFormation, Terraform, etc.) directly from .NET script that is planned to be available as an API.
Predefined infrastructure contains: Route53 config, created API Gateway with custom domain.
Dynamic infrastructure contains: S3 and Lambda together with API Gateway modifications and deployment.
Once the bucket for a new service is created and the built app is pushed to the bucket, new Lambda function is created, configured and published. The last thing that is left is to create a new resource (route) that will invoke underlying Lambda function and its underlying routes (e.g. example.com/auth/register).
The issue is that when I create an integration on a non-root resource, Lambda function cannot be found or the Uri is not specified as it should be (this is something I am trying to figure out).
Here is the simplified code that I wrote to accomplish this (I will exclude Lambda function and S3 bucket created and show only API gateway and Lambda resource policy updates as they are relevant here). Important to note is that this code produces the same results as if it would be done via AWS console. Also, this code produces a working solution if the route is not specified (e.g. example.com/register)
var functionArn = await Lambda.GetFunctionArn(accessKey, secretKey, region, lambdaFunction);
var pathResponse = await c.CreateResourceAsync(new CreateResourceRequest
{
ParentId = rootId,
PathPart = path,
RestApiId = apiId
});
await c.PutMethodAsync(new PutMethodRequest
{
AuthorizationType = "NONE",
HttpMethod = "ANY",
ResourceId = pathResponse.Id,
RestApiId = apiId
});
var proxyResponse = await c.CreateResourceAsync(new CreateResourceRequest
{
ParentId = pathResponse.Id,
PathPart = "{proxy+}",
RestApiId = apiId
});
await c.PutMethodAsync(new PutMethodRequest
{
AuthorizationType = "NONE",
HttpMethod = "ANY",
ResourceId = proxyResponse.Id,
RestApiId = apiId
});
await Lambda.AddPermissions(account, accessKey, secretKey, region, lambdaFunction, apiId, path);
await c.PutIntegrationAsync(new PutIntegrationRequest
{
HttpMethod = "ANY",
IntegrationHttpMethod = "POST",
ResourceId = pathResponse.Id,
RestApiId = apiId,
PassthroughBehavior = "WHEN_NO_MATCH",
Type = IntegrationType.AWS_PROXY,
Uri = $"arn:aws:apigateway:{region}:lambda:path/2015-03-31/functions/{functionArn}/invocations"
});
await c.PutIntegrationAsync(new PutIntegrationRequest
{
HttpMethod = "ANY",
IntegrationHttpMethod = "POST",
ResourceId = proxyResponse.Id,
RestApiId = apiId,
PassthroughBehavior = "WHEN_NO_MATCH",
Type = IntegrationType.AWS_PROXY,
Uri = $"arn:aws:apigateway:{region}:lambda:path/2015-03-31/functions/{functionArn}/invocations"
});
var deployment = await c.CreateDeploymentAsync(new CreateDeploymentRequest
{
Description = $"API deployment to {environment}",
RestApiId = apiId,
StageName = environment
});
return deployment.Id;
where Lambda.AddPermissions is as follows:
var basePermission = await c.AddPermissionAsync(new AddPermissionRequest
{
Action = "lambda:InvokeFunction",
FunctionName = name,
Principal = "apigateway.amazonaws.com",
SourceArn = $"arn:aws:execute-api:{region}:{account}:{apiId}/*/*/{path}/*",
StatementId = Guid.NewGuid().ToString()
});
var proxyPermission = await c.AddPermissionAsync(new AddPermissionRequest
{
Action = "lambda:InvokeFunction",
FunctionName = name,
Principal = "apigateway.amazonaws.com",
SourceArn = $"arn:aws:execute-api:{region}:{account}:{apiId}/*/*/{path}",
StatementId = Guid.NewGuid().ToString()
});
return new List<string>
{
basePermission.Statement,
proxyPermission.Statement
};
Is there an issue with SourceArn specifications? I first created them through the AWS console (they are automatically created when the integration is created for Lambda) and they are the same.
Again, this all works when there is no path (non-root resource).

Azure function is not logging custom events, dependencies to app insights

We have a Azure Function V3 developed in C#. We tried to log some custom events, dependencies, etc to Azure Application Insights. We are not able to log in app insights using TelemetryClient. The code runs fine without any errors. Also, could see instrumentation key retrieved from config file. However Ilogger logs can be found in app insights traces table. Please find below code that we used,
public class CommunityCreate
{
private readonly TelemetryClient telemetryClient;
public CommunityCreate(TelemetryConfiguration telemetryConfiguration)
{
this.telemetryClient = new TelemetryClient(telemetryConfiguration);
}
[FunctionName("Function1")]
[return: ServiceBus("sample", Connection = "ServiceBusProducerConnection")]
public async Task<string> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "Account/{id:int?}")] HttpRequest req, string id, ILogger log)
{
//log.LogInformation("C# HTTP trigger function processed a request.");
DateTime start = DateTime.UtcNow;
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
var evt = new EventTelemetry("Function called");
evt.Context.User.Id = name;
this.telemetryClient.TrackEvent(evt);
// Generate a custom metric, in this case let's use ContentLength.
this.telemetryClient.GetMetric("contentLength").TrackValue(req.ContentLength);
// Log a custom dependency in the dependencies table.
var dependency = new DependencyTelemetry
{
Name = "GET api/planets/1/",
Target = "swapi.co",
Data = "https://swapi.co/api/planets/1/",
Timestamp = start,
Duration = DateTime.UtcNow - start,
Success = true
};
dependency.Context.User.Id = name;
this.telemetryClient.TrackDependency(dependency);
telemetryClient.TrackEvent("Ack123 Recieved");
telemetryClient.TrackMetric("Test Metric", DateTime.Now.Millisecond);
return name;
}
}
Please make sure you're using the correct packages as below:
Microsoft.Azure.WebJobs.Logging.ApplicationInsights, version 3.0.18
and
update the package Microsoft.NET.Sdk.Functions the latest version 3.0.9.
If you're running the project locally, please add the APPINSIGHTS_INSTRUMENTATIONKEY in local.settings.json, like below:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "xxxx",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"APPINSIGHTS_INSTRUMENTATIONKEY": "xxx"
}
}
Or if you're running it on azure portal, please configure the Application insights with azure function.
Then I tested your code, the custom events or dependency are correctly logged into Application insights. Here is the screenshot:
If you still have the issue, please let me know(and please also provide more details).

Azure Function and SharePoint webhook: not getting changes from SharePoint list

I'm using a couple of Azure Functions with SharePoint webhook.
The first function is the one used to save messages from SharePoint webhook to a queue (Azure storage queue). This is the function content:
[FunctionName("QueueFunction")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info($"Webhook was triggered!");
// Grab the validationToken URL parameter
string validationToken = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "validationtoken", true) == 0)
.Value;
// If a validation token is present, we need to respond within 5 seconds by
// returning the given validation token. This only happens when a new
// web hook is being added
if (validationToken != null)
{
log.Info($"Validation token {validationToken} received");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(validationToken);
return response;
}
log.Info($"SharePoint triggered our webhook...great :-)");
var content = await req.Content.ReadAsStringAsync();
log.Info($"Received following payload: {content}");
var notifications = JsonConvert.DeserializeObject<ResponseModel<NotificationModel>>(content).Value;
log.Info($"Found {notifications.Count} notifications");
if (notifications.Count > 0)
{
// get the cloud storage account
string queueName = "MYQUEUE";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("AzureWebJobsStorage"));
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
CloudQueue queue = queueClient.GetQueueReference(queueName);
await queue.CreateIfNotExistsAsync();
// store each notification as a queue item
foreach (var notification in notifications)
{
string message = JsonConvert.SerializeObject(notification);
log.Info($"Adding to {queueName}: {message}");
await queue.AddMessageAsync(new CloudQueueMessage(message));
log.Info($"added.");
}
// if we get here we assume the request was well received
return new HttpResponseMessage(HttpStatusCode.OK);
}
The message in queue is correctly added.
Then I've another function triggered by queue. This is the code of the function:
[FunctionName("OCRFunction")]
public static void Run([QueueTrigger("MYQUEUE", Connection = "QueueConn")]string myQueueItem, TraceWriter log)
{
log.Info($"C# Queue trigger function processed: {myQueueItem}");
string siteUrl = "https://MYSHAREPOINT.sharepoint.com/sites/MYSITE";
log.Info($"Processing notifications...");
string json = myQueueItem;
var data = (JObject)JsonConvert.DeserializeObject(json);
string notificationResource = data["resource"].Value<string>();
ClientContext SPClientContext = LoginSharePoint(siteUrl);
log.Info($"Logged in SharePoint");
GetChanges(SPClientContext, notificationResource, log);
}
public static ClientContext LoginSharePoint(string BaseUrl)
{
// Login using UserOnly Credentials (User Name and User PW)
ClientContext cntReturn;
string myUserName = config["spUN"];
string myPassword = config["spPWD"];
SecureString securePassword = new SecureString();
foreach (char oneChar in myPassword) securePassword.AppendChar(oneChar);
SharePointOnlineCredentials myCredentials = new SharePointOnlineCredentials(myUserName, securePassword);
cntReturn = new ClientContext(BaseUrl);
cntReturn.Credentials = myCredentials;
return cntReturn;
}
static void GetChanges(ClientContext SPClientContext, string ListId, TraceWriter log)
{
Web spWeb = SPClientContext.Web;
List myList = spWeb.Lists.GetByTitle("MY LIST");
SPClientContext.Load(myList);
SPClientContext.ExecuteQuery();
ChangeQuery myChangeQuery = GetChangeQueryNew(ListId);
var allChanges = myList.GetChanges(myChangeQuery);
SPClientContext.Load(allChanges);
SPClientContext.ExecuteQuery();
log.Info($"---- Changes found : " + allChanges.Count());
foreach (Change oneChange in allChanges)
{
if (oneChange is ChangeItem)
{
int myItemId = (oneChange as ChangeItem).ItemId;
log.Info($"---- Changed ItemId : " + myItemId);
ListItem myItem = myList.GetItemById(myItemId);
Microsoft.SharePoint.Client.File myFile = myItem.File;
ClientResult<System.IO.Stream> myFileStream = myFile.OpenBinaryStream();
SPClientContext.Load(myFile);
SPClientContext.ExecuteQuery();
byte[] myFileBytes = ConvertStreamToByteArray(myFileStream);
[...] SOME CODE HERE [...]
myItem["OCRText"] = myText;
myItem.Update();
SPClientContext.ExecuteQuery();
log.Info($"---- Text Analyze OCR added to SharePoint Item");
}
}
}
public static ChangeQuery GetChangeQueryNew(string ListId)
{
ChangeToken lastChangeToken = new ChangeToken();
lastChangeToken.StringValue = string.Format("1;3;{0};{1};-1", ListId, DateTime.Now.AddMinutes(-1).ToUniversalTime().Ticks.ToString());
ChangeToken newChangeToken = new ChangeToken();
newChangeToken.StringValue = string.Format("1;3;{0};{1};-1", ListId, DateTime.Now.ToUniversalTime().Ticks.ToString());
ChangeQuery myChangeQuery = new ChangeQuery(false, false);
myChangeQuery.Item = true; // Get only Item changes
myChangeQuery.Add = true; // Get only the new Items
myChangeQuery.ChangeTokenStart = lastChangeToken;
myChangeQuery.ChangeTokenEnd = newChangeToken;
return myChangeQuery;
}
public static Byte[] ConvertStreamToByteArray(ClientResult<System.IO.Stream> myFileStream)
{
Byte[] bytReturn = null;
using (System.IO.MemoryStream myFileMemoryStream = new System.IO.MemoryStream())
{
if (myFileStream != null)
{
myFileStream.Value.CopyTo(myFileMemoryStream);
bytReturn = myFileMemoryStream.ToArray();
}
}
return bytReturn;
}
public static async Task<TextAnalyzeOCRResult> GetAzureTextAnalyzeOCR(byte[] myFileBytes)
{
TextAnalyzeOCRResult resultReturn = new TextAnalyzeOCRResult();
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "XXXXXXXXXXXXXXXXXXXX");
string requestParameters = "language=unk&detectOrientation=true";
/* OCR API */
string uri = "https://MYOCRSERVICE.cognitiveservices.azure.com/vision/v3.0/ocr" + "?" + requestParameters;
string contentString = string.Empty;
HttpResponseMessage response;
using (ByteArrayContent content = new ByteArrayContent(myFileBytes))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response = await client.PostAsync(uri, content);
contentString = await response.Content.ReadAsStringAsync();
resultReturn = JsonConvert.DeserializeObject<TextAnalyzeOCRResult>(contentString);
return resultReturn;
}
}
Before current approach with two functions, I was using a single function where I managed the notifications and I executed some code to update a field in my SharePoint list. This method was having some problem when I was receiving many notifications from SharePoint so I decided to use queue as suggested in Microsoft documentation. This solution was working fine with a single notification received and my SharePoint list item were updated without problem.
To avoid problems with multiple notification, I decided to split functions, one registering notifications in a queue and the other executing some operations and updating a SharePoint field.
The first one function QueueFunction is working fine, the second one is triggering correctly but it is not getting changes from SharePoint list even if I just add one item.
I've tried to check GetChanges code to find why it is always returning no changes, but the code is the same of the one I used when I had only one function, so I can't understand why the behaviour is changed.
What's wrong with my approach? Is there something I could do to correct the second function?
According to the comments, just summarize the solution as below for other communities reference:
Use a function to save the message in a queue and then call an azure web job, the problem was caused by the the running time of the function may exceed 5 minutes.
By the way, the default timeout of azure function(with consumption plan) is 5 minutes, we can see all of the default timeout for different plan on this page (also shown as below screenshot).
If we want longer timeout, we can set the functionTimeout property in host.json of the function(but can not exceed the Maximum timeout). Or we can also use higher plan for the function app, such as Premium plan and App Service plan.

Error when trying to access Azure Function

I have an anonymous function on Azure, successfully deployed (.netstandard 2.0), using Microsoft.NET.Sdk.Functions (1.0.13), but for some reason suddenly it stopped working and when I call it the response is:
<ApiErrorModel xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Microsoft.Azure.WebJobs.Script.WebHost.Models">
<Arguments xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:nil="true"/>
<ErrorCode>0</ErrorCode>
<ErrorDetails i:nil="true"/>
<Id>91fab400-3447-4913-878f-715d9d4ab46b</Id>
<Message>
An error has occurred. For more information, please check the logs for error ID 91fab400-3447-4913-878f-715d9d4ab46b
</Message>
<RequestId>0fb00298-733d-4d88-9e73-c328d024e1bb</RequestId>
<StatusCode>InternalServerError</StatusCode>
</ApiErrorModel>
How to figure that out?
EDIT: When I start AF environment locally and run the function it works as expected, without any issues, although what i see in console is a message in red:
and searching for it, stumbled across this GitHub post:
https://github.com/Azure/azure-functions-host/issues/2765
where I noticed this part:
#m-demydiuk noticed that azure function works with this error in the console. So this red error doesn't break function on the local machine. But I am afraid it may cause any problems in other environments.
and it bothers me. Can it be the problem?
I use a lib with a version that do not match my target framework, but again locally works fine, and also it was working fine before on Azure
My host version is "Version=2.0.11651.0"
This is the entire function:
public static class Function1
{
[FunctionName("HTML2IMG")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequest req, TraceWriter log)
{
string url = req.Query["url"];
byte[] EncodedData = Convert.FromBase64String(url);
string DecodedURL = Encoding.UTF8.GetString(EncodedData);
string requestBody = new StreamReader(req.Body).ReadToEnd();
dynamic data = JsonConvert.DeserializeObject(requestBody);
DecodedURL = DecodedURL ?? data?.name;
var api = new HtmlToPdfOrImage.Api("9123314e-219c-342d-a763-0a3dsdf8ad21", "vmZ31vyg");
var ApiResult = api.Convert(new Uri($"{DecodedURL}"), new HtmlToPdfOrImage.GenerateSettings() { OutputType = HtmlToPdfOrImage.OutputType.Image });
string BlobName = Guid.NewGuid().ToString("n");
string ImageURL = await CreateBlob($"{BlobName}.png", (byte[])ApiResult.model, log);
var Result = new HttpResponseMessage(HttpStatusCode.OK);
var oJSON = new { url = ImageURL, hash = BlobName };
var jsonToReturn = JsonConvert.SerializeObject(oJSON);
Result.Content = new StringContent(jsonToReturn);
Result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return Result;
}
private async static Task<string> CreateBlob(string name, byte[] data, TraceWriter log)
{
string accessKey = "xxx";
string accountName = "xxx";
string connectionString = "DefaultEndpointsProtocol=https;AccountName=" + accountName + ";AccountKey=" + accessKey + ";EndpointSuffix=core.windows.net";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
CloudBlobClient client = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = client.GetContainerReference("images");
await container.CreateIfNotExistsAsync();
BlobContainerPermissions permissions = await container.GetPermissionsAsync();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
await container.SetPermissionsAsync(permissions);
CloudBlockBlob blob = container.GetBlockBlobReference(name);
blob.Properties.ContentType = "image/png";
using (Stream stream = new MemoryStream(data))
{
await blob.UploadFromStreamAsync(stream);
}
return blob.Uri.AbsoluteUri;
}
DOUBLE EDIT:
I created empty V2 .net core AF in VS and published it straight away -> i get the same error... I even updated the Microsoft.NET.Sdk.Function to the latest 1.0.14 instead of 1.0.13 and still get the same error. Obviously something in Azure or Visual Studio (15.7.5) is broken?!?!
Solution
On Azure portal, go to Function app settings check your Runtime Version. It is probably Runtime version: 1.0.11913.0 (~1) on your side. This is the problem. Change FUNCTIONS_EXTENSION_VERSION to beta in Application settings and your code should work on Azure.
Explanation
You create a v2 function as your local host version is 2.0.11651.0. So the function runtime should also be beta 2.x(latest is 2.0.11933.0) online.
When you published functions from VS before, you probably saw this prompt
You may have chosen No so that you got the error.
Note that if we publish through CI/CD like VSTS or Git, such notification is not available. So we need to make sure those configurations are set correctly.
Suggestions
As you can see your local host version is 2.0.11651, which is lower than 2.0.11933 on Azure. I do recommend you to update Azure Functions and Web Jobs Tools(on VS menus, Tools->Extensions and Updates) to latest(15.0.40617.0) for VS to consume latest function runtime.
As for your code, I recommend you to create images container and set its public access level manually on portal since this process only requires executing once.
Then we can use blob output bindings.
Add StorageConnection to Application settings with storage connection string. If your images container is in the storage account used by function app (AzureWebJobsStorge in Application settings), ignore this step and delete Connection parameter below, because bindings use that storage account by default.
Add blob output bindings
public static async Task<HttpResponseMessage> Run(...,TraceWriter log,
[Blob("images", FileAccess.Read, Connection = "StorageConnection")] CloudBlobContainer container)
Change CreateBlob method
private async static Task<string> CreateBlob(string name, byte[] data, TraceWriter log, CloudBlobContainer container)
{
CloudBlockBlob blob = container.GetBlockBlobReference(name);
blob.Properties.ContentType = "image/png";
using (Stream stream = new MemoryStream(data))
{
await blob.UploadFromStreamAsync(stream);
}
return blob.Uri.AbsoluteUri;
}

DocumentDB with Azure Functions

I'm trying to connect an Azure DocumentDB and save documents using Azure Functions but I don't know how to create the connection.
You can do it using the Azure Portal.
After you created the DocumentDB -
Create new Azure Function.
Go to the Integrate Tab.
You can choose Azure Document DB as an output for your function.
Choose your Document DB/Database Name/Collection you want to use.
Document parameter name is the Output of your function.
For example
using System;
public static void Run(string input, out object document, TraceWriter log)
{
log.Info($"C# manually triggered function called with input: {input}");
document = new {
text = $"I'm running in a C# function! {input}"
};
}
you need to provide out object which is the same as you defined in the output tab.
You can just use the document client directly:
var endpoint = "https://XXXXX.documents.azure.com:443/";
var authKey = "XXXXX";
using (var client = new DocumentClient(new Uri(endpoint), authKey))
{
var sqlCountQuery = "select value count(1) from c";
IDocumentQuery<dynamic> query = client.CreateDocumentQuery<dynamic>(UriFactory.CreateDocumentCollectionUri("YOUR_DB_ID", "YOUR_COLLECTON_ID"), sqlCountQuery).AsDocumentQuery();
....
}
Azure Functions supports Document DB (Cosmos DB) out-of-the-box. You can just simply add an environment variable called AzureWebJobsDocumentDBConnectionString in V1 or AzureWebJobsCosmosDBConnectionString in V2.
Then just use a CosmosDBTrigger binding attribute for input binding like (in C# for example):
public static class UpsertProductCosmosDbTrigger
{
[FunctionName("ProductUpsertCosmosDbTrigger")]
public static void Run(
[CosmosDBTrigger(
// Those names come from the application settings.
// Those names can come with both preceding % and trailing %.
databaseName: "CosmosDbDdatabaseName",
collectionName: "CosmosDbCollectionName",
LeaseDatabaseName = "CosmosDbDdatabaseName",
LeaseCollectionName = "CosmosDbLeaseCollectionName")]
IReadOnlyList<Document> input,
TraceWriter log)
...
For output binding use DocumentDB output binding attribute in V1 and CosmosDB in V2 like:
[FunctionName("ProductUpsertHttpTrigger")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "products")]
HttpRequestMessage req,
[DocumentDB(
databaseName: "%CosmosDbDdatabaseName%",
collectionName: "%CosmosDbCollectionName%")] IAsyncCollector<Product> collector,
TraceWriter log)
...
I've written a blog post about this: https://blog.mexia.com.au/cosmos-db-in-azure-functions-v1-and-v2
var EndpointUrl = "EndpointUrl";
var PrimaryKey = "PrimaryKeyValue"
this.client = new DocumentClient(new Uri(EndpointUrl), PrimaryKey);
Database database = await this.client.CreateDatabaseIfNotExistsAsync(new Database { Id = cosmoDbName });
you can get the End-point-URL and Primary-Key value from the azure portal in the keys section.
Assume C# has similar SDK like Java. The below is for Java
There are two ways you can connect to documentDB from an Azure function.
Using SDK
DocumentClient documentClient = new DocumentClient(
"SERVICE_ENDPOINT",
"MASTER_KEY",
ConnectionPolicy.GetDefault(),
ConsistencyLevel.Session);
Refer - [https://learn.microsoft.com/en-us/azure/cosmos-db/sql-api-java-samples][1]. This has .Net Samples too.
Binding
#FunctionName("CosmosDBStore")
#CosmosDBOutput(name = "database",
databaseName = "db_name",
collectionName = "col_name",
connectionStringSetting = "AzureCosmosDBConnection")
Please make sure you have a variable in the name of "AzureCosmosDBConnection" in your application settings and local.settings.json(if you want to test locally)
Refer - [https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-cosmosdb-v2][1]
The above link has C# example too.

Categories

Resources