How to Disable the Azure Function, even without Infrastructure setup? - c#

I am using Azure Queue Trigger for my Function. But the Infrastructure (e.g., Queue, Blob storage) for that Function is not in place. So, the Azure storage connection string will also be empty. But while running the Function App, it is expecting the connection string and throwing an exception at runtime. Even though I disabled the Function using the [Disable("MY_TIMER_DISABLED")] attribute.
Exception
System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString')
The reason I found is that while running the Function App, the Startup is invoking all the Functions, and then it is reading the properties associated with those Functions. So, at the initial invoke, it is expecting the Queue, Connection String, etc., even though the function is Disabled.
public class UserDataRetryFunction()
{
[FunctionName(UserDataRetryFunction)]
[Disable("AzureWebJobs.UserDataRetryFunction.Disabled")]
public async Task RetryData([QueueTrigger("%RetryQueueName%", Connection = "%ConnectionStrings:StorageConnectionString%")])
{
// Process the Queue Message
}
}
appsetings.json
{
"IsEncrypted": false,
"RetryQueueName" : "retry-response-queue",
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"AzureWebJobs.UserDataRetryFunction.Disabled": "true"
},
"ConnectionStrings": {
"StorageConnectionString" : "",
}
}
I have tried many documents and sites, but could not able to find the solution.
Some of the links I’ve evaluated are stated below.
https://learn.microsoft.com/en-us/azure/azure-functions/disable-function?tabs=portal
https://forums.asp.net/t/2165324.aspx?Value+cannot+be+null+Parameter+connectionString+
Value cannot be null. Parameter name: connectionString appsettings.json in starter

The behaviour you're setting is expected. In Azure disabling a function only means disabling the trigger as you have done and as detailed in the link you referenced. This disables the trigger but doesn't stop the entire function.
If you wish to stop the entire function you can do so in the Azure Portal.
You can also use the AZ CLI as follows:
az functionapp stop --name MyFunctionApp --resource-group MyResourceGroup
With PowerShell you can stop a function with the following command:
Stop-AzFunctionApp -Name MyAppName -ResourceGroupName MyResourceGroupName

Related

Azure Function .NET5 (isolated) throws when using [EventGridTrigger] EventGridEvent as parameter

After upgrade to .NET5 for Azure Function this signature throws the exception below.
I've implemented it according to the documentation here https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-event-grid-trigger?tabs=csharp%2Cbash
[Function(nameof(CustomerCreated))]
public async Task CustomerCreated([EventGridTrigger] EventGridEvent eventGridEvent, FunctionContext functionContext)
{
// My implementation
}
System.NotSupportedException: 'Deserialization of types without a
parameterless constructor, a singular parameterized constructor, or a
parameterized constructor annotated with 'JsonConstructorAttribute' is
not supported. Type 'Azure.Messaging.EventGrid.EventGridEvent'. Path:
$ | LineNumber: 0 | BytePositionInLine: 1.'
How can I receive the event from EventGrid?
The new way of doing this seems to be CloudEvent from the Azure.Messaging namespace.
(A side note is that the data properties are case-sensitive, I'm not sure if they were before.)
public async Task CustomerCreated([EventGridTrigger] CloudEvent eventGridEvent, FunctionContext functionContext)
{
// [...]
}
UPDATE:
This breaks when deploying to Azure and receiving events from a real event grid with an Azure Function as endpoints. But works fine when testing locally using ngrok and webhook. Back to square one.
After endless googling with outdated examples I found a note in this document, pointing to this example showing that you need to create a custom type (looking just like the EventGridEvent).
After testing I found that this actually works:
Pass a string instead of EventGridEvent and parse the actual event with the utility function from EventGridEvent.
[Function(nameof(CustomerCreated))]
public async Task CustomerCreated([EventGridTrigger] string data, FunctionContext functionContext)
{
var eventGridEvent = EventGridEvent.Parse(BinaryData.FromString(data));
// Rest of code
}
Another related caveat is that you can't create the function from the portal but need to run it from the command line like:
az eventgrid event-subscription create --name customer-created \
--source-resource-id <event-grid-topic-resource-id> \
--endpoint <azure-func-resource-id> --endpoint-type azurefunction
(The resource id:s can be found at http://resources.azure.com/)
Hello Microsoft;
Running Azure Functions on .NET5 doesn't feel very GA with this approach. I really hope to be able to pass typed objects like EventGridEvent from other Azure services with official libraries.
I really think that the EventGridEvent on .NET5/dotnet-isolated should be compatible with Azure Functions at the same level as on previous .NET versions and as in the public examples.

Invalid cache key parameter specified when enabling caching for a path parameter in AWS API Gateway

I have a serverless web API (API Gateway + Lambda) that I have built in C# and deployed via Visual Studio. This is achieved via a serverless.yml file that auto-creates a CloudFormation template, then that template is applied to create the API stack.
Once my stack is deployed, I have gone into the AWS Console to enable caching on one of the path parameters, but get this error:
!https://ibb.co/B4wmRRj
I'm aware of this post https://forums.aws.amazon.com/thread.jspa?messageID=711315&#711315 which details a similar but different issue where the user can't uncheck caching. My issue is I can't enable it to begin with. I also don't understand the steps provided to resolve the issue within that post. There is mention of using the AWS CLI, but not what commands to use, or what to do exactly. I have also done some reading on how to enable caching through the serverless.yml template itself, or cloud formation, but the examples I find online don't seem to match up in any way to the structure of my serverless file or resulting CF template. (I can provide examples if required). I just want to be able to enable caching on path parameters. I have been able to enable caching globally on the API stage, but that won't help me unless I can get the caching to be sensitive to different path parameters.
serverless.yml
"GetTableResponse" : {
"Type" : "AWS::Serverless::Function",
"Properties": {
"Handler": "AWSServerlessInSiteDataGw::AWSServerlessInSiteDataGw.Functions::GetTableResponse",
"Runtime": "dotnetcore2.0",
"CodeUri": "",
"MemorySize": 256,
"Timeout": 30,
"Role": null,
"Policies": [ "AWSLambdaBasicExecutionRole","AWSLambdaVPCAccessExecutionRole","AmazonSSMFullAccess"],
"Events": {
"PutResource": {
"Type": "Api",
"Properties": {
"Path": "kata/table/get/{tableid}",
"Method": "GET"
}
}
}
}
}
},
"Outputs" : {
"ApiURL" : {
"Description" : "API endpoint URL for Prod environment",
"Value" : { "Fn::Sub" : "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" }
}
}
--Update Start--
The reason, you are getting Invalid cache key parameter specified error because you did not explicitly highlighted the path parameters section.
This is because, although the UI somehow extrapolated that there is a
path parameter, it has not been explicitly called out in the API
Gateway configuration.
I tested with below and was able to replicate the behavior on console. To resolve this, follow my Point 1 section full answer.
functions:
katatable:
handler: handler.katatable
events:
- http:
method: get
path: kata/table/get/{tableid}
--Update End--
Here you go. I still don't have your exact serverless.yml so I created a sample of mine similar to yours and tested it.
serverless.yml
functions:
katatable:
handler: handler.katatable
events:
- http:
method: get
path: kata/table/get/{tableid}
request:
parameters:
paths:
tableid: true
resources:
Resources:
ApiGatewayMethodKataTableGetTableidVarGet:
Properties:
Integration:
CacheKeyParameters:
- method.request.path.tableid
Above should make tableid path parameter is cached.
Explanation:
Point 1. You have to make sure in your events after your method and path, below section is created otherwise next resources section of CacheKeyParameters will fail. Note - boolean true means path parameter is required. Once you explicitly highlight path parameter, you should be able to enable caching via console as well without resources section.
request:
parameters:
paths:
tableid: true
Point 2. The resources section tells API Gateway to enable caching on tableid path parameter. This is nothing but serverless interpretation of CloudFormation template syntax. How did I get that I have to use ApiGatewayMethodKataTableGetTableidVarGet to make it working?. Just read below guidelines and tip to get the name.
https://serverless.com/framework/docs/providers/aws/guide/resources/
Tip: If you are unsure how a resource is named, that you want to
reference from your custom resources, you can issue a serverless
package. This will create the CloudFormation template for your service
in the .serverless folder (it is named
cloudformation-template-update-stack.json). Just open the file and
check for the generated resource name.
What does above mean? - First run serverless package without resources section and find .serverless folder in directory and open above mentioned json file. Look for AWS::ApiGateway::Method. you will get exact normalized name(ApiGatewayMethodKataTableGetTableidVarGet) syntax you can use in resources section.
Here are some references I used.
https://medium.com/#dougmoscrop/i-set-up-api-gateway-caching-here-are-some-things-that-surprised-me-7526d954fbe6
https://serverless.com/framework/docs/providers/aws/events/apigateway#request-parameters
PS - If you still need CLI steps to enable it, let me know.

Values from local.settings.json in Azure Functions

I've created an Azure function that looks like this (actually, the Microsoft template did most of the work!):
[FunctionName("Function1")]
public static void Run([ServiceBusTrigger("%queue-name%", AccessRights.Listen)]string myQueueItem, TraceWriter log)
{
log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
}
My local.settings.json looks like this:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "..",
"AzureWebJobsDashboard": "..",
"AzureWebJobsServiceBus": "..",
"queue-name": "testqueue"
}
}
I then deployed this function. This is a strange SO question, because my problem is that this worked immediately, but I didn't expect it to. The function.json is here:
{
"generatedBy": "Microsoft.NET.Sdk.Functions-1.0.0.0",
"configurationSource": "attributes",
"bindings": [
{
"type": "serviceBusTrigger",
"queueName": "%queue-name%",
"accessRights": "listen",
"name": "myQueueItem"
}
],
"disabled": false,
"scriptFile": "..\\bin\\FunctionApp8.dll",
"entryPoint": "FunctionApp8.Function1.Run"
}
Clearly, the values in local.settings.json have been copied into the function settings, but i can't see them in the portal. My question is: where are these settings now stored (queue-name and AzureWebJobsServiceBus)?
EDIT:
My Application Settings for the function:
They'll be under the "Application settings" tab of the published function app in the Azure Portal (see picture).
There's a bit of documentation here! Note that most app settings are not published automatically, and require a bit of configuration either at the publish step or after publishing.
UPDATE: If two functions are listening for an event on the same queue, only one function will be fired. This can cause seemingly buggy behavior, as a function will appear to fire/not fire when expected.
In this case, the unexpected behavior came from a competing functions and not an unexpected connection string.
In Azure the function settings are taken from Application settings tab, which is the same as in App Service.
You probably published them too, go check in the portal UI.

How to make startup Azure Function

I have a Azure Function like that
[FunctionName("Function1")]
public static void Run([ServiceBusTrigger("myqueue", AccessRights.Manage, Connection = "AzureWebJobsServiceBus")]string myQueueItem, TraceWriter log)
{
log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
}
I want to dynamic bind myqueue and AzureWebJobServiceBus connection string in a startup or OnInit of app without as method's parameter above. I mean, I want to a method run first of all like Program.cs in WebJob to binding or start up global variables. Can I do that in Azure Function and how to do it?
Many thanks
The attributes here are compiled into a function.jsonfile before deployment that has the info on what the binding talks to. Often things like the connection string reference app settings. Neither of these can be modified within the code itself (so a Program.cs couldn’t modify the function.json binding).
Can you share any more on your scenario? If you have multiple queues you want to listen to could you deploy a function per queue? Given the serverless nature of Functions there isn’t a downside to having extra functions deployed. Let me know - happy to see if we can help with what you need.
Edit
The suggestion below doesn't work for a Trigger, only for a Binding.
We have to wait for the team to support Key Vault endpoints in Azure Functions, see this GitHub issue.
I think what you are looking for is something called Imperative Bindings.
I've discovered them myself just yesterday and had a question about them also. With these type of bindings you can just dynamically set up the bindings you want, so you can retrieve data from somewhere else (like a global variable, or some initialization code) and use it in the binding.
The thing I have used it for is retrieving some values from Azure Key Vault, but you can also retrieve data from somewhere else of course. Some sample code.
// Retrieving the secret from Azure Key Vault via a helper class
var connectionString = await secret.Get("CosmosConnectionStringSecret");
// Setting the AppSetting run-time with the secret value, because the Binder needs it
ConfigurationManager.AppSettings["CosmosConnectionString"] = connectionString;
// Creating an output binding
var output = await binder.BindAsync<IAsyncCollector<MinifiedUrl>>(new DocumentDBAttribute("TablesDB", "minified-urls")
{
CreateIfNotExists = true,
// Specify the AppSetting key which contains the actual connection string information
ConnectionStringSetting = "CosmosConnectionString",
});
// Create the MinifiedUrl object
var create = new CreateUrlHandler();
var minifiedUrl = create.Execute(data);
// Adding the newly created object to Cosmos DB
await output.AddAsync(minifiedUrl);
There are also some other attributes you can use with imperative binding, I'm sure you'll see this in the docs (first link).
Instead of using Imperative Bindings, you can also use your application settings.
As a best practice, secrets and connection strings should be managed using app settings, rather than configuration files. This limits access to these secrets and makes it safe to store function.json in a public source control repository.
App settings are also useful whenever you want to change configuration based on the environment. For example, in a test environment, you may want to monitor a different queue or blob storage container.
App settings are resolved whenever a value is enclosed in percent signs, such as %MyAppSetting%. Note that the connection property of triggers and bindings is a special case and automatically resolves values as app settings.
The following example is an Azure Queue Storage trigger that uses an app setting %input-queue-name% to define the queue to trigger on.
{
"bindings": [
{
"name": "order",
"type": "queueTrigger",
"direction": "in",
"queueName": "%input-queue-name%",
"connection": "MY_STORAGE_ACCT_APP_SETTING"
}
]
}

Disable Property of Azure Functions not working in Visual Studio 2017

I have Azure function with timer trigger.
public static void Run([TimerTrigger("0 */15 * * * *"), Disable("True")]TimerInfo myTimer, TraceWriter log)
Here the Disable("true") is not working. it generates the function.json as
"disabled": "True", which is not correct. It should be "disabled": True,
Disable only accepts string value.
Is there any way to change this? or any other way to disable function?
Disable properties default values is true.
Use Disable() instead of Disable("true").
So the code will look like
public static void Run([TimerTrigger("0 */15 * * * *"), Disable()]TimerInfo myTimer, TraceWriter log) .
If you want to enable the function use Disable("False").
Functions 2.x can be disabled individually via local.settings.json in the following manner
{
"IsEncrypted": false,
"Values": {
"AzureWebJobs.MyFunctionNameOne.Disabled": "true",
"AzureWebJobs.MyFunctionNameTwo.Disabled": "true",
...
}
}
Ref: https://learn.microsoft.com/en-us/azure/azure-functions/disable-function#functions-2x---all-languages
I wanted to add this answer, as I have been searching for it as well and I believe I found a good way to disable functions for debugging/development purposes (and to avoid these local changes get into the deployment pipelines/source control).
I combine the #if DEBUG statements with the Disable(string SettingsName) attribute:
The following piece of code shows different things at work:
The Disable attribute is not using the parameter to indicate True or False as a value, but it refers to an appsetting (that you can put in the local.settings.json file). See the second snippet in this post. So, just by changing that settings in the appsettings file, I can enable and disable triggers easily, without impacting my git repo or deployment pipelines.
The other interesting thing is the RunOnStartup = true parameter when using a TimerTrigger. This one (which I only enable with the DEBUG compiler directives), will allow me to trigger the timer function immediately, without waiting for the next CRON cycle to happen. (an alternative would be to do a post to your local functions endpoint, as described in this stackoverflow post). So again, when assuming you run your production workloads in the RELEASE configuration, this is only impacting your local development environment and not your development team or releases.
1st snippet (attributes)
#if DEBUG
[Disable("disable-transactioncrawler")]
#endif
[FunctionName("TransactionCrawler")]
public async Task Run([TimerTrigger("50 */10 * * * *"
#if DEBUG
, RunOnStartup = true
#endif
)]TimerInfo myTimer, ILogger log)
{
// Logic comes here
}
2nd snippet (local.appsettings.json)
{
"Values":
{
"disable-transactioncrawler": false
}
}
The following 'solutions' typically impact your production code, which can lead to issues:
Just using Disable() is not allowing you to configure/change it afterwards
Updating the host.json file to only include the triggers you want to run is also risking to have this change arriving in production.
Have you tried modifying the host.json inside your solution? It has the following properties for you to specify which functions to load on runtime.
// Array of functions to load. Only functions in this list will be enabled.
// If not specified, all functions are enabled.
"functions": ["QueueProcessor", "GitHubWebHook"]
Note that if you have multiple Function App projects in your solution, you will also need to make to change to their corresponding host.json (i.e. each project has their own host.json)
Documentation: https://github.com/Azure/azure-webjobs-sdk-script/wiki/host.json
The string typed value - "disabled": "true" also could disable the function. Please see the test result as following.
Here is my function definition.
public static void Run([TimerTrigger("0 */5 * * * *"),Disable("true")]TimerInfo myTimer, TraceWriter log)
Here is the published function on Azure portal.
I tried disabling using local.settings.json, and when debugging locally the emulator window actually says that the named function is disabled, but calls it anyway! This is the same in VS2017 and 2019.
The workaround I'm currently using is to test for this app setting as the first line in my function and return immediately:
if(ConfigurationManager.AppSettings["AzureWebJobs.TimerTriggeredFunction.Disabled"] == "true") return;

Categories

Resources