azure-functions-core-tools: F# function based on azure-functions-templates doesn't start; "Host.json file in missing"

This is similar to #1734 . I created a new F♯ function from the templates in Azure/azure-functions-templates.

I also installed v3 of the core tools via chocolatey, and when I try to run the function from the project directory, this is the result:

image

Here’s the project file:

<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Program.fs" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
  <Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>

I’ve opened an issue over in the template repository, but there’s been no response yet, and I’m a bit at a loss for how to get this to work. https://github.com/Azure/azure-functions-templates/issues/945

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 4
  • Comments: 23 (8 by maintainers)

Commits related to this issue

Most upvoted comments

It looks like the problem is related to the F# project template.

Let’s take a look at the project file here: https://github.com/Azure/azure-functions-templates/blob/dev/Functions.Templates/ProjectTemplate/FSharp/Company.FunctionApp.fsproj#L11-L17

  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>

Both of these items are <None> with a “include type” of Update. What happens here is that when MSBuild runs it will update any reference to host.json and set it’s CopyToOutputDirectory to PreserveNewest. But, that file hasn’t been added to the MSBuild “file list” that it’s internally tracking and because it’s an “Update” not an “InsertOrUpdate”, it doesn’t have anything to update and thus it’s ignored.

If you change it to <None Include="host.json"> it will tell MSBuild that you want to explicitly include that file with the following metadata, which is why it then works.

So, if you look at the C# project template (https://github.com/Azure/azure-functions-templates/blob/dev/Functions.Templates/ProjectTemplate/CSharp/Company.FunctionApp.csproj#L11-L17) you might notice that it does the same as F# but doesn’t have the same problem and you as yourself “why is that?”, well, it’s because C# will include files by default, whereas F# is explicit includes (and that’s why you don’t need <Compile> items for all .cs files in SDK projects).

This is controlled by the file Microsoft.NET.Sdk.DefaultItems.targets - https://github.com/dotnet/sdk/blob/master/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.targets#L19 and this file is referenced implicitly when you use SDK project templates. F# on the other hand uses Microsoft.FSharp.NetSdk.props - https://github.com/dotnet/fsharp/blob/master/src/fsharp/FSharp.Build/Microsoft.FSharp.NetSdk.props#L34

Since the .props file is referenced first, it sets the value of EnableDefaultNoneItems to false and then when the Microsoft.NET.Sdk.DefaultItems.targets is used, the value is already set, so it won’t set it to true.

The result is that the host.json and local.settings.json aren’t included in the files MSBuild is tracking and thus output by MSBuild (either when you run dotnet build or func start).

TL;DR: Change <None Update="host.json"> to <None Include="host.json"> and I’ll open a PR.

(PS: Big thanks to @davidwengier for helping me to understand MSBuild better and for this video)

This seems to work for me without having to create stub files during the CI build.

.fsproj:

<ItemGroup>
  <None Include="host.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
  <None Include="local.settings.json" Condition="Exists('local.settings.json')">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <CopyToPublishDirectory>Never</CopyToPublishDirectory>
  </None>
</ItemGroup>

I also came across this issue. I created the function using: dotnet new func --language F# dotnet new timer --language F# --name Timer

@anthonychu The fsproj file has a reference to the Functions SDK:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="BackupTimer\Backup.fs" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.KeyVault" Version="3.0.5" />
    <PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.5.0" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.3" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

I used @aggieben 's workaround with the BeforeTargets hook to copy the files to the output directory which works for the time being. Thanks!

@isaacabraham I created a PR for the template to fix it: https://github.com/Azure/azure-functions-templates/pull/954 but as @cartermp points out, this is a related issue on the compiler/build (https://github.com/dotnet/fsharp/issues/8914), and as @vjraitila points out, changing the inclusion mode can result in it being published to Azure, which you don’t want.

I think using the Condition attribute of the None for inclusion is probably the quickest solution, but it’s not a perfect one.

Wow. I just fell for this as well. Just changing from Update to Include fixes it.

What I’ve done in my CD workflow is simply create a stub file before build—because <CopyToPublishDirectory>Never</CopyToPublishDirectory> is set it’ll never make it into the published output dir.

.fsproj:

<ItemGroup>
  <None Include="host.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
  <None Include="local.settings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <CopyToPublishDirectory>Never</CopyToPublishDirectory>
  </None>
</ItemGroup>

action:

- name: Build and publish
  run: |
    touch local.settings.json
    dotnet build -c Release
    dotnet publish -c Release -o ./output