To explain in detail how to reference a file in an Azure function some background information on the basics of Azure functions is necessary. To complete the story it will all be explained for C# script based function as well as C# compiled functions.
Azure functions
Azure functions can be built in the Azure portal, C# script based, or by using Visual Studio by using the Azure Function Tools for Visual Studio 2017 extension.
The Azure function tools provides a set of benefits:
- Functions can be edited, built and run from your local development computer
- Visual Studio can be used for development
- The Azure Functions project can be published directly to Azure
- Pre-compiled C# functions are deployed instead of C# script based functions which benefit from a performance perspective
Let’s take a look at some practical differences for both options.
Both are examples of a simple C# HttpTrigger.
Method signatures
C# function
[FunctionName("Function1")] public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
C# script function
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
It can be seen that the C# function uses attributes where the C# script function uses the settings which can be adjusted in the portal or can be maintained in a separate function.json file.
Project output structure
A C# function developed and compiled in Visual Studio and deployed to Azure has a slightly different output structure than a C# script function created in the Azure portal.
Figure 1 – C# function output created in VS and deployed to Azure
This is a copy of the directory below ‘\release(or debug)\net461’ on the local file system. As you can see there is a bin folder which contains the output assembly of the project as well as all the referenced assemblies. The function.json contains the bindings generated by the Azure Function tools from the C# code attributes defined.
Figure 2 – C# script output created in Azure Portal
Bindings are defined in function.json, where the actual C# script code is listed in run.csx, un-compiled and readable in the browser.
How to reference a file in the project within the function
How hard can it be, I hear you thinking… Yeah, my thoughts also..
What is the current working directory in the function code?
There are several options for getting a path in .NET
Assembly.GetExecutingAssembly().CodeBase – Gets the location of the assembly as specified originally; the place where the file is found.
Assembly.GetExecutingAssembly().Location – Gets the full path or UNC location of the loaded file that contains the manifest.
Environment.CurrentDirectory – Gets the current directory path of the project.
AppDomain.CurrentDomain.BaseDirectory – Gets the path of the entrypoint of the application or where the current AppDomain is created.
The output for the C# function, locally and published to Azure, as well as the output for the C# script function are displayed in the following figures.
Figure 3 – C# function code output when running locally
Figure 4 – C# function output when published to Azure
Figure 5 – C# script function output running in Azure portal
In all three situations the different possibilities result in a different location returned and none of them are usable in all three situations.
For example the Codebase can be used when using a C# function, but when developing a C# script function this path is totally unusable.
To get information about the function or directory one has to dive into the Azure WebJobs SDK. After all Azure functions are based on WebJobs.
It seems that the method signature can take an additional parameter of type ExecutionContext.
Just add it and it’s ok, like this in a C# function:
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log, ExecutionContext executionContext)
Or a C# script function:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, ExecutionContext executionContext)
Calling the property FunctionDirectory of this context in Visual Studio results in the actual local function directory:
Figure 6 – FunctionDirectory result running locally
So get the parent of this path to get the project directory.
When deployed to Azure it results in D:\home\site\wwwroot\Function1
Figure 7 – FunctionDirectory result deployed to Azure
And using an C# script function this results in ‘D:\home\site\wwwroot\HttpTriggerCSharp1’ which is the function directory over there.
Figure 8 – FunctionDirectory result running C# script function
When adding files and folders to the project in Visual Studio and deploy it to Azure, they are present in the structure:
Now the working directory is a known fact, referencing these files in the project is easy.
log.Info(executionContext.FunctionDirectory);
log.Info($”{Directory.GetParent(executionContext.FunctionDirectory).FullName}\\files\\afile.json”);
Summary
To get the project or function directory in an Azure function in Visual Studio or in the portal isn’t rocket science, but it took me some digging around in the SDK to get it.
nice article Anita, really helped me out.
Really helpful, thanks
Thank you
Thanks, this was useful. Saved me digging out all the information myself.
Thanks Anita, this was a very useful article!
Thank you! Note that there is also FunctionAppDirectory in ExecutionContext, which gives the root folder with the exes.
Thanks a ton, very handy!