Does config.GetSection not work in Azure Functions? And what is the recommended alternative? - json

Azure Function with a complex (List of objects) configuration type is working locally (with that complex type in local.settings.json) but fails to read / create list of objects in Azure (with that complex type in Azure Function configuration settings). I'm looking for the recommended / optimal way to support that across both platforms / methods of access.
This works great in my local.settings.json where I use the configuration builder and pull data out like
var myList = config.GetSection("ConfigurationList").Get<List<MyType>>();
however this doesn't seem to work in Azure Functions?? Now I think that is because in local.settings.json it is a json file and looks like
"ConfigurationList" : [ { "Name": "A", "Value": 2 }, { "Name": "B", "Value": 3 }]
while in Azure Functions it is a setting "ConfigurationList" with the value
[ { "Name": "A", "Value": 2 }, { "Name": "B", "Value": 3 }]
(so there isn't really a "section" in Azure Functions?)
It seems like the "easy" solution to this is to just change the .json to be a quoted string and deserialize the string (and then it would work the same in both places); but that doesn't seem like it would be the "best" (or "recommended" solution)
i.e. something like
"ConfigurationList" : "[ { \"Name\": \"A\", \"Value\": 2 }, { \"Name\": \"B\", \"Value\": 3 }]"
var myList = (List<MyType>)JsonConvert.DeserializeObject(config["ConfigurationList"], typeof(List<MyType>));
Which isn't the worst; but makes the json a bit "not as nice" and doesn't "flow" across the two platforms ... if it is what I have to do, fine; but hoping for a more standard approach / recommendation

As I metioned in the comment, on local you can process local.settings.json as a json file, but when on azure, the value in configuration settings is environment variable. There is no section, it just string.
Please notice that only string values are allowed, and that anything nested will break. Learn how to use nest settings on azure web app(azure functon is based on azure app service sandbox, so it is the same.):
https://learn.microsoft.com/en-us/archive/blogs/waws/asp-net-core-settings-for-azure-app-service
For example, if this is the json structure:
{
"Parent": {
"ChildOne": "C1 from secrets.json",
"ChildTwo": "C2 from secrets.json"
}
}
Then in web app, you should save it like this:
(source: windows.net)

Not sure if you are looking something like this , it seems a list but if it is a simple JObject like
"ConfigurationList" : {
"Name": "A",
"Value": 2
}
Then you can declare ConfigurationList:Name , ConfigurationList:Value in the configuration settings of function app

Related

How to pass a list as an environment variable to an AWS Lambda function from a JSON config file?

I have a JSON file that is going to contain a number of different lists per client that I am deploying for. These lists are going to serve as container overrides for an ECS task that my Lambda function will be invoking. The JSON config file would look something like this:
{
"clientName": {
"environment": [
{
"name": "name1",
"value": "value1"
}
]
}
}
And my serverless.yml would look something like this:
environment:
CONTAINER_ENVIRONMENT: ${file(serverlessConfig.json):${env:CLIENT_NAME}.environment}
Which results in the following error:
Could not resolve "CONTAINER_ENVIRONMENT" environment variable: Unsupported environment variable format:
[
{
"name": "name1",
"value": "value1"
}
]
I've tried using CloudFormation intrinsic functions such as Fn::Join and Fn::ToJsonString. These both threw an error when trying to run locally using sls invoke local (the errors were the same as the above). After some digging it seems that these functions aren't compatible with the serverless environment property.
The only thing that has worked so far is storing the list as a string in a .env file, but that's not really ideal since these configs could take a number of different environment objects.
Is there any way to get this to work with the setup that I have going?

How do I modify parameters in a Container Overrides section of a Step Functions machine?

I have a Step Functions Machine the definition file of which looks as such:
"ContainerOverrides": [
{
"Name": "Foo",
"Environment": [
{
"Name": "Foo"
"Value": "Bar"
},
],
"Command.$": "States.Array($.Foo,$.Foo,$.Bar,$.Bar,$.Bar)"
}
]
},
that I am trying to rewrite into Typescript (CDK). I've gotten the following few lines.
containerOverrides: [{
containerDefinition: Foo,
environment: [
{ name: 'Foo', value: 'Bar'},
],
command: ['States.Array($.Foo,$.Foo,$.Bar,$.Bar,$.Bar)'],
}],
I'm a bit confused about how to go about this.
When I deploy the above CDK code, I get as output:
"Command": [
"States.Array($.Foo,$.Foo,$.Bar,$.Bar,$.Bar)"
],
My confusion is in regards to the following: The ContainerOverrides method doesn't accept parameters, but I need to modify a parameter (Command.$), so how can I possibly do that? I came across this post where somebody seems to have a similar issue, but when I try to apply the proposed solution, of simply writing
command: JsonPath.arrayAt('States.Array($.Foo,$.Foo,$.Bar,$.Bar,$.Bar)'
I get told that ''Cannot use JsonPath fields in an array, they must be used in objects''
TL;DR The current implementation of EcsRunTask doesn't permit this. The general-purpose CallAwsService construct does.
The EcsRunTask construct is the CDK's implementation of the ECS optimised integration. The construct only accepts an array of strings as override commands. It cannot produce substitutable output like "Command.$": "$.commands" that's needed to read the override command from the execution input. This is a limitation of the CDK implementation, not of the ECS optimized integration itself.
The cleanest solution is to use the CallAwsService construct, which implements the SDK service integration. It requires manual configuration. The API-specific config goes in the parameters prop. The prop is loosely typed as { [string]: any }. It's flexible, but it's your job to provide the expected syntax for the ecs:RunTask SDK call. Here is the relevant bit for your question:
parameters {
Overrides: {
ContainerOverrides: [
{ Command: sfn.JsonPath.array("sh", "-c", sfn.JsonPath.stringAt("$.cmd")), },
],
},
}
It produces the expected command override in the Step Functions task definition:
"Command.$": "States.Array('sh', '-c', $.cmd)"

WebApp ARM template with variable number of AppSettings

How can you create an ARM template for a web app that can take a varied number of App Settings in a parameters.json file?
I have tried using this approach:
{
"name": "[concat(variables('web_app_name'), '/appsettings')]",
"type": "Microsoft.Web/sites/config",
"apiVersion": "2018-11-01",
"properties": {
"appSetting1": "value1",
"AppSetting2": "value2"
},
"dependsOn": [
"[resourceId('Microsoft.Web/sites/', variables('web_app_name'))]"
]
}
But this wipes my default properties on a WebApp such as APPINSIGHTS_INSTRUMENTATIONKEY, ApplicationInsightsAgent_EXTENSION_VERSION etc. as this doesn't merge with the already existing app settings but overwrites them. There is an issue reported on GitHub: https://github.com/Azure/azure-cli/issues/11718
Then there is some mentioning of using this method: https://kalcik.net/2019/11/21/merge-azure-app-service-app-settings-in-arm-template/
[union(
variables('appServiceBaseConfig'),
variables('appService1'),
json(
concat(
'{\"APPINSIGHTS_INSTRUMENTATIONKEY\":\"',
reference(concat('microsoft.insights/components/', variables('applicationInsightsName')), '2015-05-01').InstrumentationKey,
'\"}')
)
)
]
but this makes my eyes bleed and doesn't even support line breaks and az deployment group validate pukes on it stating that it is not valid json if it is not on one line, which makes this useless.
Any smart work arounds?

Loading JsonObject model in manifest.json - sapui5

I'm trying to set a data model inside my manifest.json within my webapp.
Im using sapui5 and I'm quite new to it.
the resource I'm getting from my api is a jsonObject but somehow the model is not initiated properly. I checked the model with console.log() and it's empty.
when I do the same with an jsonArray it is working.
I should mention that I use a mockserver.js
Here is the code I'm using.
manifest.json:
"sap.app": {
...
"dataSources": {
"invoiceRemote": {
"uri": "https://services.odata.org/V2/Northwind/Northwind.svc/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/metadata.xml"
}
}
}
}
...
"sap.ui5": {
...
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "MyInboxUI5.i18n.i18n"
}
},
"invoice": {
"dataSource": "invoiceRemote"
}
...
and with JsonObject I mean a .json of this style:
{
"field1": value1,
"field2": value2,
"field3": [
{
"field4": value4,
"field5": value5
},
{
"field6": value6,
"field7": value7
} ]
}
(that's the one not working)
and with JsonArray I meant
[
{
"field4": value4,
"field5": value5
},
{
"field6": value6,
"field7": value7
}
]
(This one is working)
To check my model I used the simple console.log()
Component.js (part of it)
init: function() {
console.log(this.getModel("invoice"));
UIComponent.prototype.init.apply(this, arguments);
this.getRouter().initialize();
}
I did not post the mockserver.js or metadata.xml because I'm not sure it's that relevant and they take a lot of space.
So does anyone know if there is a way to load the model of a JsonObject inside the manifest.json?
I'm aware that there are other possibilities to load the model that do work, but I'm only interestet in that specific case.
Without having additional information about what you actually try to achieve it's hard to point you into the right direction.
The important information is that you are using an ODataModel + a mockserver. Thanks to the mockserver you can easily mock your data for the entities of your OData service - actually you can even mock much more...
Basically, the mock data files need to contain flat lists. In other words, you have always an array of flat objects. The mockserver gets the data (i.e. entities by id) from exactly from these files. The mockserver can only find the files if they have the correct name (see walkthrough tutorial for details). As a rule of thumb "1 file contains data for one entity/entityset".
There is no way to model JsonObjects inside the manifest. What you can do is mocking your mockserver (i.e. by reading json files manually), that works perfectly (the explored app has some examples). However, don't forget we are talking about OData!
Hint: your data looks like a tree, so I guess you want to model a tree structure. If you check the explored app there are a few examples for OData Tree binding and there I'm using the mockserver as well. Maybe that helps...

Node.js SOAP client parameter formatting

I'm having trouble properly formatting one particular soap parameter using the node-soap module for node.js as a client, to a 3rd-party SOAP service.
The client.describe() for this method says this particular input should be in the shape of:
params: { 'param[]': {} }
I have tried a bunch of different JSON notations to try to fit my data to that shape.
Examples of formats that do NOT work:
"params": { "param": [ {"myParameterName": "myParameterValue"} ] }
"params": [ "param": { "name": "myParameterName", "_": "myParameterValue"} ]
"params": { "param" : [ {"name": "myParameterName", "_": "myParameterValue"} ] }
"params": { "param[]": {"myParameterName": "myParameterValue" } }
"params": { "param[myParameterName]": {"_": "myParameterValue" } }
I must be overlooking something, and I suspect I'm going to feel like Captain Obvious when some nice person points out what I'm doing wrong.
Here is what DOES work, using other soap clients, and how they handle the "named parameter with a value"
soapUI for this method successfully accepts this particular input via XML in the shape of:
<ns:params>
<ns:param name="myParameterName">myParameterValue</ns:param>
</ns:params>
Also, using PHP, I can successfully make the call by creating a stdClass of arrays like so:
$parms = new stdClass;
$parms->param = array(
array(
"name"=>"myParameterName","_"=>"myParameterValue"
)
);
and then eventually passing
'params' => $parms
to the PHP soap client
Many thanks!
To get a better look at what XML was being generated by node-soap, I added a console.log(message) statement to the node_modules/soap/lib/client.js after the object-to-XML encoding. I then began experimenting with various JSON structures to figure out empirically how they were mapping to XML structures.
I found a JSON structure for node-soap to generate the XML in my 3rd-party's required named-parameter-with-value format. I was completely unaware of the "$value" special keyword. Looks like this may have been added in the 0.4.6 release from mid-June 2014. See the change history
"params": [
{
"param": {
"attributes": {
"name": "myParameterName"
},
$value: "myParameterValue"
}
}
]
(note the outer array, which gives me the luxury of specifying multiple "param" entries, which is sometimes needed by this particular 3rd-party API)
generates this XML:
<tns:params>
<tns:param name="myParameterName">myParameterValue</tns:param>
</tns:params>
which perfectly matches the structure in soapUI (which I already knew worked) of:
<ns:params>
<ns:param name="myParameterName">myParameterValue</ns:param>
</ns:params>