3

My question is pretty specific but I hope someone here will be able to help me...

Okay long story short

I'm developing an Azure Function in C# (with .NET Core 3.1) which outputs PowerPoint slideshows using data fetched from SharePoint lists, and a slideshow template also stored on said SharePoint. To achieve this, I'm using a ConfigurationBuilder to load the configuration in the local.settings.json file.
This file pretty much looks like this :

"IsEncrypted": false,
"Values": {
  "AzureWebJobsStorage": "UseDevelopmentStorage=true",
  "FUNCTIONS_WORKER_RUNTIME": "dotnet"
},
"TokenEndpoint": "https://login.microsoftonline.com/common/oauth2/token",
"User": "!! put this line filled with the email of the account in your secrets.json !!",
"Password": "!! put this line filled with the password of the account in your secrets.json !!",
"AzureAppId": "some guid",
"SharePointSite": "https://something.sharepoint.com/sites/something_else",
"TemplatesConfig": {
  "Path": "Shared%20files/",
  "FirstTemplateName": "FirstTemplate.pptx",
  "SecondeTemplateName": "SecondTemplate.pptx"
}

To connect to SharePoint, we're using the email and password stored in this file, but to avoid any problems with the credentials leaking, I'm using user secrets that I'm "adding" in the configuration builder to replace the placeholder credentials with actual ones.
Then, I'm going into the TemplatesConfig items and read the Path, FirstTemplateName and SecondTemplateName properties to know where to search the template files, and the names of the first and second template.
I can run the function locally, everything works as intended. Good.

Where the problems begin

Now, I want to publish the function to the cloud to use it. The function app is created and pretty much set up. I can publish it, but can't run it... And the problem comes from the fact that the configuration builder couldn't read the TemplatesConfig as it's not defined.

Reading the docs and searching for answers on some forums here and there, I find that the configuration file local.settings.json is, obviously, only used when executing the function locally and you can't use it when published like I'm trying to. Instead, the key values in this file needs to be input on Azure, in the application settings : Screenshot of Azure where I'm entering the application settings and connection strings Thing is that the keys entered in the application settings are the keys you could enter in the Values item of the configuration JSON, and that's not where my configuration data is... Furthermore, it looks like you can only store key - value associations, but I'm storing a whole item containing these...

According to the documentation, there are multiple sections possible in local.settings.json, and two of them seem to be linked to the two sections of the page I'm showing you in the screenshot above (Application Settings and Connection Strings), so I think this is the right place to search for answers, but it feels more like I'm going to have to remake my credentials and templates data storing system from the ground up...
It's the first time I'm making an Azure function. In fact, someone else started the job and then passed it on to me when the whole "base" was built (which includes this part of the program which bugs me out because I'm having a hard time understanding it).

So what's my question then ?

Do you have an idea of what I should do to properly store the information about the template, but also the credentials to connect to SharePoint ? Is the current solution correct, or have I completely missed another mechanism I should be using instead to store it ? Should I redo my authentication method completely and use Connection Strings to connect to SharePoint instead of storing the credentials as keys ?

Thank you so much for your time reading me, and thank you in advance for your replies.

Anchorwave
  • 66
  • 1
  • 6
  • 1
    A couple of details about Azure Function config here (https://stackoverflow.com/questions/62960764/how-to-modify-iconfiguration-natively-injected-in-azure-functions/63124002#63124002). Values and ConnectionStrings are loaded by default by the runtime into IConfiguration. You can then set it to the proper IOptions which is best practice. You can add nested objects to the Values by separating them by colon (:). If you chose to use Azure App config, here's some info (https://stackoverflow.com/questions/68023186/net-core-able-to-connect-to-azure-app-config-but-cant-return-any-config-valu/) – lopezbertoni Jul 09 '21 at 22:04

3 Answers3

2

If I understood correctly you could not simply set your settings like below?

"IsEncrypted": false,
"Values": {
  "AzureWebJobsStorage": "UseDevelopmentStorage=true",
  "FUNCTIONS_WORKER_RUNTIME": "dotnet",
  "TemplatesConfig:Path": "Shared%20files/",
  "TemplatesConfig:FirstTemplateName": "FirstTemplate.pptx",
  "TemplatesConfig:SecondeTemplateName": "SecondTemplate.pptx"
},
"TokenEndpoint": "https://login.microsoftonline.com/common/oauth2/token",
"User": "!! put this line filled with the email of the account in your secrets.json !!",
"Password": "!! put this line filled with the password of the account in your secrets.json !!",
"AzureAppId": "some guid",
"SharePointSite": "https://something.sharepoint.com/sites/something_else"    

And your applicationsettings

Name: TemplatesConfig:Path
Value: Shared%20files/ Name: TemplatesConfig:FirstTemplateName
Value: FirstTemplateName

...

Teta
  • 129
  • 9
1

I would suspect a problem with your credentials.

If I remember correctly, when you publish, the user secrets are not. It is only used in developpement.

You should not use app secrets in production, as stated here in the title : https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-5.0&tabs=windows

You should instead use environment variables : https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0

Try it and complement your question with further details on the problem, so we can assist you further more.

0

Okay so I'm back with a solution I found with you guys' help along my colleagues' one.

What I did was to put everything that was in the local.settings.json file in the Values object, like that :

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "SharePointSite": "https://something.sharepoint.com/sites/something_else",
    "User": "!! put this line filled with the email of the account in your secrets.json !!",
    "Password": "!! put this line filled with the password of the account in your secrets.json !!",
    "TemplatesConfig:Path": "Shared%20files/",
    "TemplatesConfig:FirstTemplateName": "FirstTemplate.pptx",
    "TemplatesConfig:SecondTemplateName": "SecondTemplate.pptx"
  },
  "TokenEndpoint": "https://login.microsoftonline.com/common/oauth2/token",
  "AzureAppId": "some guid"
}

I've understood that Azure was only working with environment variables, and that Visual Studio was getting them in this file's Values object to "emulate" environment variables while developing.

In my configurations loading code, I just had to add a line with Microsoft.Extensions.Configuration.ConfigurationBuilder.AddEnvironmentVariables() to get them from Azure when the function is running online (after being published). Now, it's running fine locally, and most importantly, online.

As for the credentials, in my secret.json file, I just had to put the two lines for e-mail and password also inside a Values JSON object, just like in local.settings.json, and voilà, it does the job while developing and online too.

For more info, I checked the links people here replied with, and also this doc : Best place to store environment variables for Azure Function

Thank you for your help, everyone !

Anchorwave
  • 66
  • 1
  • 6