I'm not a tease so here it is, tested with what's currently available as of this post. Following the previous post, you now have Kudu so it's time to use it!
Go ahead and create a new app in kudu-admin.
Notice that the Application URL isn't bound to localhost on a port, I removed the binding but remember the port as we'll need it later.
Now to get the Azure Functions host/runtime, naming things is hard so we'll assume FunctionsInProc8.4.839.400.zip
means In-Process v4 using .NET 8 LTS. I also tested the non-in-proc version and it did work, note all my testing was x64.
Extract the zip file as we'll be using the contents of the 64Bit folder.
First we need to set some user environment variables.
Who is the user? Your app is the user. Remember everything runs in the context of your application pool.
Go to your app's Service/Kudu/SCM url, using the Kudu debug console run the following in the command prompt.
setx AZURE_FUNCTIONS_ENVIRONMENT Development
setx FUNCTIONS_WORKER_RUNTIME dotnet
setx AzureWebJobsScriptRoot %home%\site\wwwroot
Then stop & start your app's application pool.
I won't be explaining everything about Web Jobs, better docs exist.
We just need to create one continous job which requires 2 files, that will start our Azure Functions host.
settings.job
{
"is_in_place": true,
"is_singleton": true
}
run.cmd
call .\Microsoft.Azure.WebJobs.Script.WebHost.exe --urls "http://localhost:{Application URL ORIGINAL PORT we unbound}"
Your app's site dir should have a structure like below, I redacted the other files but don't remove them.
C:\kudu\apps\wtfunc\site
├───deployments
├───jobs
│ └───continuous
│ └───FunctionsInProc8.4.839.400
│ │ Microsoft.Azure.WebJobs.Script.WebHost.exe
│ │ run.cmd
│ │ settings.job
├───locks
└───wwwroot
│ hostingstart.html
Kudu will pick up the job & start the Azure Functions host.
You can now go to http://localhost:{Application URL ORIGINAL PORT}
but we still need to point the new Application URL hostname to the Azure Functions host.
To do this, we'll be using the IIS URL Rewrite Module with a simple web.config to act as a reverse proxy.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<location path="" allowOverride="false">
<system.webServer>
<handlers>
<clear />
</handlers>
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{CACHE_URL}" pattern="^(https?)://" />
</conditions>
<action type="Rewrite" url="http://localhost:YOUR_HOST_POST/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</location>
</configuration>
Note the clearing of the handlers. The Azure Functions host should be executing binaries not your app's site. You can also create a new app pool for your app's site aspect with the .NET CLR version set to No Managed code
You can remove hostingstart.html
from wwwroot
so that web.config
is the only file. Deployment is the same as Azure, you'll have a structure like below.
C:\kudu\apps\wtfunc\site\wwwroot
│ host.json
│ web.config
└───TestHttp
function.json
run.csx
or
C:\kudu\apps\wtfunc\site\wwwroot
│ extensions.csproj
│ host.json
│ web.config
├───bin
│ Aliencube.AzureFunctions.Extensions.Configuration.AppSettings.dll
│ Aliencube.AzureFunctions.Extensions.OpenApi.Core.dll
│ Aliencube.AzureFunctions.Extensions.OpenApi.dll
├───HelloWorld
│ function.json
│ function.proj
│ project.assets.json
│ run.csx
│
├───RenderSwaggerUI
│ function.json
│ function.proj
│ project.assets.json
│ run.csx
│
├───Shared
│ IOpenApiHttpTriggerContext.csx
│ JsonContentResult.csx
│ SwaggerGen.csx
│ SwaggerLoad.csx
│
└───Swagger
function.json
function.proj
project.assets.json
run.csx
That's it, your're good to go! My code examples are on GitHub. If you have issues, logs are in the data dir i.e. C:\kudu\apps\wtfunc\data
.
Lastly my soapbox diatribe.
I wish MS invested 1/10th of what they did for co-pilot into C# scripting, csx is a different form of expression that allows you to be creative when solving dynamic problems.
Functions + csx align with the words of Dijkstra "The purpose of abstracting is not to be vague, but to create a new semantic level in which one can be absolutely precise."