Have you ever wanted to run Azure Functions in IIS? No? "Why would you want to run serverless functions in IIS," you ask.
I won't try to answer why, but I can tell you how. I recently needed to do this and found a void where info should be, so this post is to fill that void.
In Azure, functions are hosted in IIS. (Weird right? Like, I assumed it was something sophisticated and new, not just some duct tapey IIS plugin thing.) I want to find out how much of a function app we can get functioning on-prem with IIS. Yeah, we could just run azure function core tools, but what would we learn from following that well-documented process?
๐ช Basic IIS setup
Let's add a plain, empty site, and bind it to a really good domain.
Since we used a really good domain, we'll need to update our hosts file.
Here's quick test to prove that IIS is set up OK.
Cool so we have a site set up in IIS, and we can deploy a function app to it. Next we'll make a function app, give it a bunch of trigger types, just to see which triggers work in this janky setup.
๐งช A Guinea Pig Function App
Here's a link to the source code.
Pretty basic, there's are 4 triggers, and each one just logs. There's a timer, HTTP, queue, and blob trigger. It's logging to a file, so that when it's silently running in IIS, I can see the function app is doing stuff.
[FunctionName(nameof(TestHttp))]
public IActionResult TestHttp(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req)
{
logger.LogInformation("HttpTrigger ran");
return new OkObjectResult("Perfect! ๐");
}
[FunctionName(nameof(TestQueue))]
public void TestQueue([QueueTrigger("iis-q-test")]string item)
=> logger.LogInformation($"QueueTrigger ran value: {item}");
[FunctionName(nameof(TestStorage))]
public void TestStorage([BlobTrigger("iis-blob-test/{name}")]Stream blob, string name)
=> logger.LogInformation($"BlobTrigger ran file name: {name}, size: {blob.Length}");
[FunctionName(nameof(TestTimer))]
public void TestTimer([TimerTrigger("*/20 * * * * *")]TimerInfo timer)
=> logger.LogInformation($"TimerTrigger ran");
I have confirmed that, running from Visual Studio, the function app works as expected. All triggers work and log as configured.
Next from Visual Studio, I'll publish locally to the web site folder. ๐ฅ
Yeah, of course that doesn't work. I haven't configured IIS to know what to do with a function app.
๐คซ Azure Function IIS Secret Sauce
Check out this cool github page. Azure Functions Host has releases like this one, 3.0.BLAH which we can download and use with IIS.
Download and unzip the Functions.3.0.BLAH.zip somewhere. Next make a web.config file where your function app is published. In the web.config, configure IIS to run aspNetCore module for all paths and verbs, and set the processPath for aspNetCore to the path of Function Host's Microsoft.Azure.WebJobs.Script.WebHost.exe file.
Like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<remove name="aspNetCore" />
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="C:\hosting\Functions.3.0.14191\3.0.14191\64bit\Microsoft.Azure.WebJobs.Script.WebHost.exe" hostingModel="InProcess">
<environmentVariables>
<environmentVariable name="AzureWebJobsStorage" value="UseDevelopmentStorage=true" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</configuration>
Weird, right? It's that default page that you get in azure. What about when we hit the HttpTrigger route?
So HTTP works of course. What about the other triggers? The log says
2020-07-19 21:28:00.0158|INFO|IIS.FuncTest.Tests|TimerTrigger ran
2020-07-19 21:28:20.0162|INFO|IIS.FuncTest.Tests|TimerTrigger ran
2020-07-19 21:28:36.0969|INFO|IIS.FuncTest.Tests|QueueTrigger ran value: adsf
2020-07-19 21:28:40.0181|INFO|IIS.FuncTest.Tests|TimerTrigger ran
2020-07-19 21:28:43.7516|INFO|IIS.FuncTest.Tests|HttpTrigger ran
2020-07-19 21:28:44.1831|INFO|IIS.FuncTest.Tests|BlobTrigger ran file name: 2019_TaxReturn.pdf, size: 637435
2020-07-19 21:29:00.0530|INFO|IIS.FuncTest.Tests|TimerTrigger ran
2020-07-19 21:29:20.0069|INFO|IIS.FuncTest.Tests|TimerTrigger ran
๐ป Summary
Yeah, you can run azure functions in IIS and the vanilla triggers work just fine, and there's really just 2 steps to get it working.
- Download the functions runtime
- Point to it from your web.config
I'd love to see someone get durable functions working.
Top comments (20)
Building on your article, I went through this myself and ran into a bunch of issues. I tried to put it all together in this github GIST. Talks about what to install and common trooubleshooting issues
gist.github.com/icyfire0573/f1ad10...
Iโm pretty sure 90% of Azure is IIS awkwardly canvassed by disgruntled SharePoint devs.
So, after a long & costly โmove it all to app servicesโ experiment, Iโm going back to my VM and unadulterated IIS - but what to do with the darn functions was an open question, thanks for the info!
As I pull back from expensive & slow app service plans to a VM this is a godsend. Have my functions running in IIS without a hitch. I tried making them scheduled tasks at first (mostly timer based) but this is 100% easier especially in deployment. Deploying a local service or scheduled task required lots of extra work, but Devops IIS WebApp deployment is a treat.
Thanks for your great article.
I tried your setup and get the web.config error "The requested page cannot be accessed because the related configuration data for the page is invalid"
I pointed to correct path to Microsoft.Azure.WebJobs.Script.WebHost.exe
Do you have any idea for it?
Yes! You might need to install ASP.NET Core Runtime Hosting Bundle
Whenever I publish azure function its not generating IIS.deps.json config file for me. Correct me if I'm wrong, I believe my function app is not running due to missing of that config file. If I miss any configuration please guide me.
This is amazing, never ever thought of running an Azure function in IIS.
Great article. I used this tutorial to set up Azure functions on IIS.
However, now I'm unable to use them with my Blazor application, because CORS apparently isn't working. Did you encounter something like this or do you have any idea how to handle this in IIS?
What if a function app has Authorizationlevel set as Function. The call from postman will fail. Anyway to handle this.
Sorry if this question is weird, I am comparatively new to function app. I know that there needs to be a key to call function apps with Auth level other than Anonymous but don't know where to get and set that key to be able to work with IIS
Did you get any ways to handle this one with AuthorizationLevel.Function ?
Hello,
I followed the same steps and i am able to run the function app but when i create new function and run, i am not getting the results.
When i try to run the same from visual studio, i get the response. any idea if i am missing anything here ?
Can you host a new function app with the latest Azure Core tool in IIS Manager?
I followed your hosting procedure, but it didn't work. So can you please do with latest configurations.