(Preview) Creating Azure Functions using .NET 5

Published Feb 22 2021 12:21 PM 6,274 Views
Regular Visitor

Group

 

 

Azure Functions recently released preview support for .NET 5. Let's take a look at how to upgrade our  existing Azure Functions to use it!

 

Note: This is a preview experience for .NET 5 support in Azure Functions. The Azure Functions teams notes that the ".NET 5 experience will improve in the coming weeks".

 

Why is it more complicated than last time?

 

You might be wondering "Why can't I just change `netcoreapp3.1` to `net5.0`?"

 

Historically, Azure Functions has always been tightly coupled with .NET, specifically Long Term Support (LTS) .NET releases. This meant that we couldn't use a newer version of .NET until the Azure Functions team also updated their Azure Functions .NET Runtime.

 

This is the first release that moves .NET to an "out-of-process model", allowing us to run our Azure Functions using any version of .NET!

 

Walkthrough

 

In this walkthrough, I'll be providing snippets from the Azure Functions I use for my app GitTrends. GitTrends is an open-source app available in the iOS and Android App Stores, built in C# using Xamarin, that uses Azure Functions for its backend.

 

You can find the completed solution in the `Move-Azure-Functions-to-net5.0` branch on the GitTrends repository, here: https://github.com/brminnick/GitTrends/tree/Move-Azure-Functions-to-net5.0/GitTrends.Functions

 

1. Update .NET

 

Let's update to .NET 5!

 

First, download the .NET 5 SDK and install it on your development machine.

 

Then, in your Functions' CSPROJ, set the following values for `TargetFramework`, `LangVersion`, `AzureFunctionsVersion`,` OutputType` and `_FunctionsSkipCleanOutput`:

 

(Here is a completed working example)

 

 

 

 

 

 

<PropertyGroup>
	<TargetFramework>net5.0</TargetFramework>
	<LangVersion>preview</LangVersion>
	<AzureFunctionsVersion>v3</AzureFunctionsVersion>
	<OutputType>Exe</OutputType>
	<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
</PropertyGroup>

 

 

 

 

 

 

2. Update NuGet Packages

 

Now let's add the necessary NuGet Packages.

 

In your Functions' CSPROJ, ensure the following `PackageReference`s have been added:

 

(Here is a completed example)

 

Note: For `Microsoft.Azure.Functions.Worker.Sdk`, add `OutputItemType="Analyzer"`

 

 

 

 

 

<ItemGroup>
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.0.0-preview3" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.0.0-preview3" OutputItemType="Analyzer" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions" Version="4.0.1" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Http" Version="3.0.12" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="4.0.3" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.2.1" />
    <PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
</ItemGroup>

 

 

 

 

 

3. Add Non-Windows Workaround

 

We need to include a workaround to ensure this new out-of-process worker works properly on non-Windows machines.

 

In your Functions CSPROJ, add the following `Target`:

 

(Here is a completed working example)

 

 

 

 

 

<Target Name="CopyRuntimes" AfterTargets="AfterBuild" Condition=" '$(OS)' == 'UNIX' ">
	<!-- To workaround a bug where the files aren't copied correctly for non-Windows platforms -->
	<Exec Command="rm -rf $(OutDir)bin/runtimes/* &amp;&amp; mkdir -p $(OutDir)bin/runtimes &amp;&amp; cp -R $(OutDir)runtimes/* $(OutDir)bin/runtimes/" />
</Target>

 

 

 

 

 

4. Update local.settings.json

 

To run our Functions locally, we'll need to tell the Azure Functions Host to use the isolated dotnet runtime in `local.settings.json` by by setting `FUNCTIONS_WORKER_RUNTIME` to `dotnet-isolated`, like so:

 

(Here is a working completed example)

 

 

 

 

 

 

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "AzureWebJobsDashboard": "UseDevelopmentStorage=true"
  }
}

 

 

 

 

 

Then, in the Functions' CSPROJ, ensure it is being copied to the output directory using `CopyToOutputDirectory` like so:

 

(Here is a working completed example)

 

 

 

 

 

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

 

 

 

 

 

5. Update Initialization & Dependency Injection

 

The way we initialize Azure Functions, including Dependency Injection, for .NET 5 has improved.

 

Old Initialization & Dependency Injection (pre .NET 5.0)

 

The old way to use Dependency Injection with Azure Functions was to add the `[assembly: FunctionsStartup]` attribute and inherit from `FunctionsStartup`.

 

Here is an example of how we used to initialize Dependency Injection in Azure Functions:

 

(Here is a completed working example)

 

 

 

 

 

//Note: This is the old (pre-.NET 5) way of using Dependency Injection with Azure Functions

[assembly: FunctionsStartup(typeof(Startup))]
namespace GitTrends.Functions
{
    public class Startup : FunctionsStartup
    {
        readonly static string _storageConnectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage") ?? string.Empty;

        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddHttpClient();();
            builder.Services.AddSingleton<BlobStorageService>();
            builder.Services.AddSingleton<CloudBlobClient>(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient());
        }
    }
}

//Note: This is the old (pre-.NET 5) way of using Dependency Injection with Azure Functions

 

 

 

 

 

New Initialization & Dependency Injection

 

The new way is to initialize Azure Functions in .NET 5 is more similar to ASP.NET. It uses to `Microsoft.Extensions.Hosting.HostBuilder`, like so:

 

(Here is a competed working example)

 

 

 

 

 

namespace GitTrends.Functions
{
    class Program
    {
        readonly static string _storageConnectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage") ?? string.Empty;

        static Task Main(string[] args)
        {
            var host = new HostBuilder()
                .ConfigureAppConfiguration(configurationBuilder =>
                {
                    configurationBuilder.AddCommandLine(args);
                })
                .ConfigureFunctionsWorker((hostBuilderContext, workerApplicationBuilder) =>
                {
                    workerApplicationBuilder.UseFunctionExecutionMiddleware();
                })
                .ConfigureServices(services =>
                {
                    services.AddHttpClient();
                    services.AddSingleton<BlobStorageService>();
                    services.AddSingleton<CloudBlobClient>(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient());
                })
                .Build();

            return host.RunAsync();
        }
    }

 

 

 

 

 

6. Update HttpTrigger Functions

 

To update an existing HttpTrigger Function, we replace the following method parameters:

  • `HttpRequest` -> `HttpRequestData`
  • `ILogger` -> `FunctionExecutionContext`

Note: `ILogger` can now be found in `FunctionExecutionContext.Logger`

 

Old HttpTrigger (pre .NET 5.0)

 

Here is an example of the old (pre .NET 5) way of creating an `HttpTrigger`:

 

(Here is a completed working example)

 

 

 

 

 

//Note: This is the old (pre-.NET 5) way of creating an HttpTrigger with Azure Functions

public static class GetGitHubClientId
{
	readonly static string _clientId = Environment.GetEnvironmentVariable("GitTrendsClientId") ?? string.Empty;

	[FunctionName(nameof(GetGitHubClientId))]
	public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest request, ILogger log)
	{
		log.LogInformation("Retrieving Client Id");

		if (string.IsNullOrWhiteSpace(_clientId))
			return new NotFoundObjectResult("Client ID Not Found");

		return new OkObjectResult(new GetGitHubClientIdDTO(_clientId));
	}
}
//Note: This is the old (pre-.NET 5) way of creating an HttpTrigger with Azure Functions

 

 

 

 

 

New HttpTrigger

 

The new `HttpTrigger` syntax is nearly identical; only `HttpRequestData` and `FunctionExecutionContext` are now being used as its method parameters:

 

(Here is a completed working example)

 

 

 

 

 

public static class GetGitHubClientId
{
	readonly static string _clientId = Environment.GetEnvironmentVariable("GitTrendsClientId") ?? string.Empty;

	[FunctionName(nameof(GetGitHubClientId))]
	public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req, FunctionExecutionContext executionContext)
	{
		var logger = executionContext.Logger;
		logger.LogInformation("Retrieving Client Id");

		if (string.IsNullOrWhiteSpace(_clientId))
			return new NotFoundObjectResult("Client ID Not Found");

		return new OkObjectResult(new GetGitHubClientIdDTO(_clientId));
	}
}

 

 

 

 

 

7. Update TimerTrigger Functions

 

To update an existing TimerTrigger Function, we must do the following:

  • Create `TimerInfo.cs`
  • `ILogger` -> `FunctionExecutionContext`

 

Create TimerInfo.cs

 

The out-of-process worker doesn't yet include the `TimerInfo` class, but we can create it ourselves with the same properties and its values will injected at runtime:

 

(Here is a completed working example)

 

 

 

 

 

using System;
namespace GitTrends.Functions
{
    public class TimerInfo
    {
        public ScheduleStatus? ScheduleStatus { get; set; }

        /// <summary>
        /// Gets a value indicating whether this timer invocation
        /// is due to a missed schedule occurrence.
        /// </summary>
        public bool IsPastDue { get; set; }
    }

    public class ScheduleStatus
    {
        /// <summary>
        /// Gets or sets the last recorded schedule occurrence.
        /// </summary>
        public DateTime Last { get; set; }

        /// <summary>
        /// Gets or sets the expected next schedule occurrence.
        /// </summary>
        public DateTime Next { get; set; }

        /// <summary>
        /// Gets or sets the last time this record was updated. This is used to re-calculate Next
        /// with the current Schedule after a host restart.
        /// </summary>
        public DateTime LastUpdated { get; set; }
    }
}

 

 

 

 

 

Old TimerTrigger (pre .NET 5.0)

 

Here is an example of a TimerTrigger Function before updating it to .NET 5.0:

 

(Here is a working completed example)

 

 

 

 

 

//Note: This is the old (pre-.NET 5) way of creating an TimerTrigger with Azure Functions

public class SendSilentPushNotification
{
	const string _runEveryHourCron = "0 0 * * * *";
    
	readonly static string _notificationHubFullConnectionString = Environment.GetEnvironmentVariable("NotificationHubFullConnectionString") ?? string.Empty;
        
	readonly static Lazy<NotificationHubClient> _clientHolder = new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString, GetNotificationHubInformation.NotificationHubName));

	static NotificationHubClient Client => _clientHolder.Value;

	[FunctionName(nameof(SendSilentPushNotification))]
	public static Task Run([TimerTrigger(_runEveryHourCron)] TimerInfo myTimer, ILogger log) => Task.WhenAll(TrySendAppleSilentNotification(Client, log), TrySendFcmSilentNotification(Client, log));
}

//Note: This is the old (pre-.NET 5) way of creating an TimerTrigger with Azure Functions

 

 

 

 

 

New TimerTrigger

 

In the new TimerTrigger, in the its method parameters, we remove `ILogger`, replacing it with `FunctionExecutionContext`:

 

(Here is a working completed example)

 

 

 

 

 

public class SendSilentPushNotification
{
	const string _runEveryHourCron = "0 0 * * * *";
    
	readonly static string _notificationHubFullConnectionString = Environment.GetEnvironmentVariable("NotificationHubFullConnectionString") ?? string.Empty;
        
	readonly static Lazy<NotificationHubClient> _clientHolder = new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString, GetNotificationHubInformation.NotificationHubName));

	static NotificationHubClient Client => _clientHolder.Value;

	[FunctionName(nameof(SendSilentPushNotification))]
	public static Task Run([TimerTrigger(_runEveryHourCron)] TimerInfo myTimer, FunctionExecutionContext executionContext)
	{
		var logger = executionContext.Logger;

		return Task.WhenAll(TrySendAppleSilentNotification(Client, logger), TrySendFcmSilentNotification(Client, logger));
	}
}

 

 

 

 

 

8. Run .NET 5 Azure Functions Locally

 

Currently, the only way to run our .NET 5 Azure Functions locally is to use the command line.

 

Note: Visual Studio and Visual Studio for Mac have not yet been updated to run .NET 5 Azure Functions. If you try to run this code using Visual Studio, it will throw a `System.UriFormatException`: "Invalid URI: The hostname could not be parsed."

 

1. Install Azure Functions Core Tools v3.0.3160

  • On macOS: Open the Terminal and run the following command:
    • `brew tap azure/functions; brew install azure-functions-core-tools@3`
  • On Windows: Open the Command Prompt and run the following command:
    • `npm i -g azure-functions-core-tools@3 --unsafe-perm true`

2. On the command line, navigate to the folder containing your Azure Functions CSPROJ

3. On the command line, enter the following command:

  • `func host start --verbose`

 

Note: This command is slightly different from the command you may already be familiar with, `func start`

 

9. Publish .NET 5 Azure Functions to Azure

 

Currently, the only way to publish our .NET 5 Azure Functions to Azure is to use the command line.

 

Note: Deployment to Azure is currently limited to Windows plans. Note that some optimizations are not in place in the consumption plan and you may experience longer cold starts

 

1. Install Azure Functions Core Tools v3.0.3160

  • On macOS: Open the Terminal and run the following command:
    • `brew tap azure/functions; brew install azure-functions-core-tools@3`
  • On Windows: Open the Command Prompt and run the following command:
    • `npm i -g azure-functions-core-tools@3 --unsafe-perm true`

2. On the command line, navigate to the folder containing your Azure Functions CSPROJ

3. On the command line, enter the following command:

  • `dotnet publish -c Release`

4. On the command line, navigate to the publish artifacts by entering the following command:

  • `cd ./bin/Release/net5.0/publish`

5. On the command line, publish the Function App to Azure using the following command:

  • `func azure functionapp publish <APP_NAME>`

 

Conclusion

 

The Azure Functions team is doing a ton of work to create out-of-process workers that allow us to use .NET 5.0 in Azure Functions.

 

Their work is still on going, and I highly recommend Watching & Staring the azure-functions-core-tools GitHub Repo: https://github.com/Azure/azure-functions-core-tools

 

 

2 Comments
New Contributor

When will the Azure Functions Project templates be available with .NET 5 out of the box on Visual Studio 2019?

New Contributor

@Tony Henrique May 25? :) -> https://mybuild.microsoft.com

@bminnick how to run this today in VS 2019?

%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E2.%20Update%20NuGet%20Packages%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ENow%20let's%20add%20the%20necessary%20NuGet%20Packages.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions'%20CSPROJ%2C%20ensure%20the%20following%20PackageReferences%20have%20been%20added%3A%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L16-L30%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20For%20Microsoft.Azure.Functions.Worker.Sdk%2C%20add%20%60OutputItemType%3D%22Analyzer%22%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker%22%20version%3D%221.0.0-preview3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker.Sdk%22%20version%3D%221.0.0-preview3%22%20outputitemtype%3D%22Analyzer%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions%22%20version%3D%224.0.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Http%22%20version%3D%223.0.12%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Storage%22%20version%3D%224.0.3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator%22%20version%3D%221.2.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22System.Net.NameResolution%22%20version%3D%224.3.0%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E3.%20Add%20Non-Windows%20Workaround%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EWe%20need%20to%20include%20a%20workaround%20to%20ensure%20this%20new%20out-of-process%20worker%20works%20properly%20on%20non-Windows%20machines.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions%20CSPROJ%2C%20add%20the%20following%20Target%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L12-L15%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CTARGET%20name%3D%22CopyRuntimes%22%20aftertargets%3D%22AfterBuild%22%20condition%3D%22%20'%24(OS)'%20%3D%3D%20'UNIX'%20%22%3E%0A%20%3C!--%20To%20workaround%20a%20bug%20where%20the%20files%20aren't%20copied%20correctly%20for%20non-Windows%20platforms%20--%3E%0A%20%3CEXEC%20command%3D%22rm%20-rf%20%24(OutDir)bin%2Fruntimes%2F*%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20mkdir%20-p%20%24(OutDir)bin%2Fruntimes%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20cp%20-R%20%24(OutDir)runtimes%2F*%20%24(OutDir)bin%2Fruntimes%2F%22%3E%3C%2FEXEC%3E%0A%3C%2FTARGET%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E4.%20Update%20local.settings.json%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20run%20our%20Functions%20locally%2C%20we'll%20need%20to%20tell%20the%20Azure%20Functions%20Host%20to%20use%20the%20isolated%20dotnet%20runtime%20in%20local.settings.json%20by%20by%20setting%20FUNCTIONS_WORKER_RUNTIME%20to%20dotnet-isolated%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2Flocal.settings.json%23L1-L8%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-json%22%3E%3CCODE%3E%7B%0A%20%20%22IsEncrypted%22%3A%20false%2C%0A%20%20%22Values%22%3A%20%7B%0A%20%20%20%20%22FUNCTIONS_WORKER_RUNTIME%22%3A%20%22dotnet-isolated%22%2C%0A%20%20%20%20%22AzureWebJobsStorage%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%2C%0A%20%20%20%20%22AzureWebJobsDashboard%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%0A%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThen%2C%20in%20the%20Functions'%20CSPROJ%2C%20ensure%20it%20is%20being%20copied%20to%20the%20output%20directory%20using%20CopyToOutputDirectory%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L35-L37%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%3CNONE%20update%3D%22local.settings.json%22%3E%0A%20%20%3CCOPYTOOUTPUTDIRECTORY%3EPreserveNewest%3C%2FCOPYTOOUTPUTDIRECTORY%3E%0A%20%3C%2FNONE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E5.%20Update%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20way%20we%20initialize%20Azure%20Functions%2C%20including%20Dependency%20Injection%2C%20for%20.NET%205%20has%20improved.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20Initialization%20%26amp%3B%20Dependency%20Injection%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20old%20way%20to%20use%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fazure-functions%2Ffunctions-dotnet-dependency-injection%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EDependency%20Injection%20with%20Azure%20Functions%3C%2FA%3E%20was%20to%20add%20the%20%5Bassembly%3A%20FunctionsStartup%5Dattribute%20and%20inherit%20from%20FunctionsStartup.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20how%20we%20%3CEM%3Eused%20to%3C%2FEM%3E%20initialize%20Dependency%20Injection%20in%20Azure%20Functions%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FStartup.cs%23L15-L57%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%0A%0A%5Bassembly%3A%20FunctionsStartup(typeof(Startup))%5D%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20Startup%20%3A%20FunctionsStartup%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20public%20override%20void%20Configure(IFunctionsHostBuilder%20builder)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddHttpClient()%3B()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20way%20is%20to%20initialize%20Azure%20Functions%20in%20.NET%205%20is%20more%20similar%20to%20ASP.NET.%20It%20uses%20to%20Microsoft.Extensions.Hosting.HostBuilder%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FProgram.cs%23L15-L67%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20competed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Enamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20class%20Program%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20static%20Task%20Main(string%5B%5D%20args)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20host%20%3D%20new%20HostBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureAppConfiguration(configurationBuilder%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20configurationBuilder.AddCommandLine(args)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureFunctionsWorker((hostBuilderContext%2C%20workerApplicationBuilder)%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20workerApplicationBuilder.UseFunctionExecutionMiddleware()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureServices(services%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddHttpClient()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.Build()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20host.RunAsync()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E6.%20Update%20HttpTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20HttpTrigger%20Function%2C%20we%20replace%20the%20following%20method%20parameters%3A%3C%2FP%3E%3CUL%3E%3CLI%3EHttpRequest%20-%26gt%3B%20HttpRequestData%3C%2FLI%3E%3CLI%3EILogger%20-%26gt%3B%20FunctionExecutionContext%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20ILogger%20can%20now%20be%20found%20in%20FunctionExecutionContext.Logger%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20HttpTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20the%20old%20(pre%20.NET%205)%20way%20of%20creating%20an%20HttpTrigger%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L11-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%0A%0Apublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequest%20request%2C%20ILogger%20log)%0A%20%7B%0A%20%20log.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20HttpTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20HttpTrigger%20syntax%20is%20%3CEM%3Enearly%3C%2FEM%3E%20identical%3B%20only%20HttpRequestData%20and%20FunctionExecutionContext%20are%20now%20being%20used%20as%20its%20method%20parameters%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L12-L27%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequestData%20req%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%20%20logger.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E7.%20Update%20TimerTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20TimerTrigger%20Function%2C%20we%20must%20do%20the%20following%3A%3C%2FP%3E%3CUL%3E%3CLI%3ECreate%20TimerInfo.cs%3C%2FLI%3E%3CLI%3EILogger%20-%26gt%3B%20FunctionExecutionContext%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ECreate%20TimerInfo.cs%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20out-of-process%20worker%20doesn't%20yet%20include%20the%20TimerInfo%20class%2C%20but%20we%20can%20create%20it%20ourselves%20with%20the%20same%20properties%20and%20its%20values%20will%20injected%20at%20runtime%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2FMove-Azure-Functions-to-net5.0%2FGitTrends.Functions%2FTimerInfo.cs%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Eusing%20System%3B%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20TimerInfo%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20public%20ScheduleStatus%3F%20ScheduleStatus%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20a%20value%20indicating%20whether%20this%20timer%20invocation%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20is%20due%20to%20a%20missed%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20bool%20IsPastDue%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20class%20ScheduleStatus%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20recorded%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Last%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20expected%20next%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Next%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20time%20this%20record%20was%20updated.%20This%20is%20used%20to%20re-calculate%20Next%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20with%20the%20current%20Schedule%20after%20a%20host%20restart.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20LastUpdated%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3EOld%20TimerTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20a%20TimerTrigger%20Function%20before%20updating%20it%20to%20.NET%205.0%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L24-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%0A%0Apublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20ILogger%20log)%20%3D%26gt%3B%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20log)%2C%20TrySendFcmSilentNotification(Client%2C%20log))%3B%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20TimerTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20the%20new%20TimerTrigger%2C%20in%20the%20its%20method%20parameters%2C%20we%20remove%20ILogger%2C%20replacing%20it%20with%20FunctionExecutionContext%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L25-L31%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%0A%20%20return%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20logger)%2C%20TrySendFcmSilentNotification(Client%2C%20logger))%3B%0A%20%7D%0A%7D%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E8.%20Run%20.NET%205%20Azure%20Functions%20Locally%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20run%20our%20.NET%205%20Azure%20Functions%20locally%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20Visual%20Studio%20and%20Visual%20Studio%20for%20Mac%20have%20not%20yet%20been%20updated%20to%20run%20.NET%205%20Azure%20Functions.%20If%20you%20try%20to%20run%20this%20code%20using%20Visual%20Studio%2C%20it%20will%20throw%20a%20System.UriFormatException%3A%20%22Invalid%20URI%3A%20The%20hostname%20could%20not%20be%20parsed.%22%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20host%20start%20--verbose%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EThis%20command%20is%20slightly%20different%20from%20the%20command%20you%20may%20already%20be%20familiar%20with%2C%20func%20start%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E9.%20Publish%20.NET%205%20Azure%20Functions%20to%20Azure%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20publish%20our%20.NET%205%20Azure%20Functions%20to%20Azure%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EDeployment%20to%20Azure%20is%20currently%20limited%20to%20Windows%20plans.%20Note%20that%20some%20optimizations%20are%20not%20in%20place%20in%20the%20consumption%20plan%20and%20you%20may%20experience%20longer%20cold%20starts%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60dotnet%20publish%20-c%20Release%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E4.%20On%20the%20command%20line%2C%20navigate%20to%20the%20publish%20artifacts%20by%20entering%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60cd%20.%2Fbin%2FRelease%2Fnet5.0%2Fpublish%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E5.%20On%20the%20command%20line%2C%20publish%20the%20Function%20App%20to%20Azure%20using%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20azure%20functionapp%20publish%20%3CAPP_NAME%3E%60%3C%2FAPP_NAME%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3EConclusion%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20Azure%20Functions%20team%20is%20doing%20a%20ton%20of%20work%20to%20create%20out-of-process%20workers%20that%20allow%20us%20to%20use%20.NET%205.0%20in%20Azure%20Functions.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETheir%20work%20is%20still%20on%20going%2C%20and%20I%20highly%20recommend%20Watching%20%26amp%3B%20Staring%20the%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Eazure-functions-core-tools%3C%2FA%3E%20GitHub%20Repo%3A%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%3C%2FA%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E2.%20Update%20NuGet%20Packages%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ENow%20let's%20add%20the%20necessary%20NuGet%20Packages.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions'%20CSPROJ%2C%20ensure%20the%20following%20%60PackageReference%60s%20have%20been%20added%3A%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L16-L30%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20For%20%60Microsoft.Azure.Functions.Worker.Sdk%60%2C%20add%20%60OutputItemType%3D%22Analyzer%22%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker%22%20version%3D%221.0.0-preview3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker.Sdk%22%20version%3D%221.0.0-preview3%22%20outputitemtype%3D%22Analyzer%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions%22%20version%3D%224.0.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Http%22%20version%3D%223.0.12%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Storage%22%20version%3D%224.0.3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator%22%20version%3D%221.2.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22System.Net.NameResolution%22%20version%3D%224.3.0%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E3.%20Add%20Non-Windows%20Workaround%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EWe%20need%20to%20include%20a%20workaround%20to%20ensure%20this%20new%20out-of-process%20worker%20works%20properly%20on%20non-Windows%20machines.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions%20CSPROJ%2C%20add%20the%20following%20%60Target%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L12-L15%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CTARGET%20name%3D%22CopyRuntimes%22%20aftertargets%3D%22AfterBuild%22%20condition%3D%22%20'%24(OS)'%20%3D%3D%20'UNIX'%20%22%3E%0A%20%3C!--%20To%20workaround%20a%20bug%20where%20the%20files%20aren't%20copied%20correctly%20for%20non-Windows%20platforms%20--%3E%0A%20%3CEXEC%20command%3D%22rm%20-rf%20%24(OutDir)bin%2Fruntimes%2F*%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20mkdir%20-p%20%24(OutDir)bin%2Fruntimes%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20cp%20-R%20%24(OutDir)runtimes%2F*%20%24(OutDir)bin%2Fruntimes%2F%22%3E%3C%2FEXEC%3E%0A%3C%2FTARGET%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E4.%20Update%20local.settings.json%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20run%20our%20Functions%20locally%2C%20we'll%20need%20to%20tell%20the%20Azure%20Functions%20Host%20to%20use%20the%20isolated%20dotnet%20runtime%20in%20%60local.settings.json%60%20by%20by%20setting%20%60FUNCTIONS_WORKER_RUNTIME%60%20to%20%60dotnet-isolated%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2Flocal.settings.json%23L1-L8%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-json%22%3E%3CCODE%3E%7B%0A%20%20%22IsEncrypted%22%3A%20false%2C%0A%20%20%22Values%22%3A%20%7B%0A%20%20%20%20%22FUNCTIONS_WORKER_RUNTIME%22%3A%20%22dotnet-isolated%22%2C%0A%20%20%20%20%22AzureWebJobsStorage%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%2C%0A%20%20%20%20%22AzureWebJobsDashboard%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%0A%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThen%2C%20in%20the%20Functions'%20CSPROJ%2C%20ensure%20it%20is%20being%20copied%20to%20the%20output%20directory%20using%20%60CopyToOutputDirectory%60%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L35-L37%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%3CNONE%20update%3D%22local.settings.json%22%3E%0A%20%20%3CCOPYTOOUTPUTDIRECTORY%3EPreserveNewest%3C%2FCOPYTOOUTPUTDIRECTORY%3E%0A%20%3C%2FNONE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E5.%20Update%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20way%20we%20initialize%20Azure%20Functions%2C%20including%20Dependency%20Injection%2C%20for%20.NET%205%20has%20improved.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20Initialization%20%26amp%3B%20Dependency%20Injection%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20old%20way%20to%20use%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fazure-functions%2Ffunctions-dotnet-dependency-injection%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EDependency%20Injection%20with%20Azure%20Functions%3C%2FA%3E%20was%20to%20add%20the%20%60%5Bassembly%3A%20FunctionsStartup%5D%60%20attribute%20and%20inherit%20from%20%60FunctionsStartup%60.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20how%20we%20%3CEM%3Eused%20to%3C%2FEM%3E%20initialize%20Dependency%20Injection%20in%20Azure%20Functions%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FStartup.cs%23L15-L57%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%0A%0A%5Bassembly%3A%20FunctionsStartup(typeof(Startup))%5D%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20Startup%20%3A%20FunctionsStartup%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20public%20override%20void%20Configure(IFunctionsHostBuilder%20builder)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddHttpClient()%3B()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20way%20is%20to%20initialize%20Azure%20Functions%20in%20.NET%205%20is%20more%20similar%20to%20ASP.NET.%20It%20uses%20to%20%60Microsoft.Extensions.Hosting.HostBuilder%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FProgram.cs%23L15-L67%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20competed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Enamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20class%20Program%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20static%20Task%20Main(string%5B%5D%20args)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20host%20%3D%20new%20HostBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureAppConfiguration(configurationBuilder%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20configurationBuilder.AddCommandLine(args)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureFunctionsWorker((hostBuilderContext%2C%20workerApplicationBuilder)%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20workerApplicationBuilder.UseFunctionExecutionMiddleware()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureServices(services%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddHttpClient()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.Build()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20host.RunAsync()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E6.%20Update%20HttpTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20HttpTrigger%20Function%2C%20we%20replace%20the%20following%20method%20parameters%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60HttpRequest%60%20-%26gt%3B%20%60HttpRequestData%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20%60ILogger%60%20can%20now%20be%20found%20in%20%60FunctionExecutionContext.Logger%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20HttpTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20the%20old%20(pre%20.NET%205)%20way%20of%20creating%20an%20%60HttpTrigger%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L11-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%0A%0Apublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequest%20request%2C%20ILogger%20log)%0A%20%7B%0A%20%20log.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20HttpTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20%60HttpTrigger%60%20syntax%20is%20%3CEM%3Enearly%3C%2FEM%3E%20identical%3B%20only%20%60HttpRequestData%60%20and%20%60FunctionExecutionContext%60%20are%20now%20being%20used%20as%20its%20method%20parameters%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L12-L27%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequestData%20req%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%20%20logger.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E7.%20Update%20TimerTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20TimerTrigger%20Function%2C%20we%20must%20do%20the%20following%3A%3C%2FP%3E%3CUL%3E%3CLI%3ECreate%20%60TimerInfo.cs%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ECreate%20TimerInfo.cs%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20out-of-process%20worker%20doesn't%20yet%20include%20the%20%60TimerInfo%60%20class%2C%20but%20we%20can%20create%20it%20ourselves%20with%20the%20same%20properties%20and%20its%20values%20will%20injected%20at%20runtime%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2FMove-Azure-Functions-to-net5.0%2FGitTrends.Functions%2FTimerInfo.cs%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Eusing%20System%3B%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20TimerInfo%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20public%20ScheduleStatus%3F%20ScheduleStatus%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20a%20value%20indicating%20whether%20this%20timer%20invocation%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20is%20due%20to%20a%20missed%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20bool%20IsPastDue%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20class%20ScheduleStatus%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20recorded%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Last%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20expected%20next%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Next%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20time%20this%20record%20was%20updated.%20This%20is%20used%20to%20re-calculate%20Next%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20with%20the%20current%20Schedule%20after%20a%20host%20restart.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20LastUpdated%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3EOld%20TimerTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20a%20TimerTrigger%20Function%20before%20updating%20it%20to%20.NET%205.0%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L24-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%0A%0Apublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20ILogger%20log)%20%3D%26gt%3B%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20log)%2C%20TrySendFcmSilentNotification(Client%2C%20log))%3B%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20TimerTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20the%20new%20TimerTrigger%2C%20in%20the%20its%20method%20parameters%2C%20we%20remove%20%60ILogger%60%2C%20replacing%20it%20with%20%60FunctionExecutionContext%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L25-L31%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%0A%20%20return%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20logger)%2C%20TrySendFcmSilentNotification(Client%2C%20logger))%3B%0A%20%7D%0A%7D%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E8.%20Run%20.NET%205%20Azure%20Functions%20Locally%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20run%20our%20.NET%205%20Azure%20Functions%20locally%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20Visual%20Studio%20and%20Visual%20Studio%20for%20Mac%20have%20not%20yet%20been%20updated%20to%20run%20.NET%205%20Azure%20Functions.%20If%20you%20try%20to%20run%20this%20code%20using%20Visual%20Studio%2C%20it%20will%20throw%20a%20%60System.UriFormatException%60%3A%20%22Invalid%20URI%3A%20The%20hostname%20could%20not%20be%20parsed.%22%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20host%20start%20--verbose%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EThis%20command%20is%20slightly%20different%20from%20the%20command%20you%20may%20already%20be%20familiar%20with%2C%20%60func%20start%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E9.%20Publish%20.NET%205%20Azure%20Functions%20to%20Azure%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20publish%20our%20.NET%205%20Azure%20Functions%20to%20Azure%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EDeployment%20to%20Azure%20is%20currently%20limited%20to%20Windows%20plans.%20Note%20that%20some%20optimizations%20are%20not%20in%20place%20in%20the%20consumption%20plan%20and%20you%20may%20experience%20longer%20cold%20starts%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60dotnet%20publish%20-c%20Release%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E4.%20On%20the%20command%20line%2C%20navigate%20to%20the%20publish%20artifacts%20by%20entering%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60cd%20.%2Fbin%2FRelease%2Fnet5.0%2Fpublish%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E5.%20On%20the%20command%20line%2C%20publish%20the%20Function%20App%20to%20Azure%20using%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20azure%20functionapp%20publish%20%3CAPP_NAME%3E%60%3C%2FAPP_NAME%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3EConclusion%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20Azure%20Functions%20team%20is%20doing%20a%20ton%20of%20work%20to%20create%20out-of-process%20workers%20that%20allow%20us%20to%20use%20.NET%205.0%20in%20Azure%20Functions.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETheir%20work%20is%20still%20on%20going%2C%20and%20I%20highly%20recommend%20Watching%20%26amp%3B%20Staring%20the%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Eazure-functions-core-tools%3C%2FA%3E%20GitHub%20Repo%3A%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%3C%2FA%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E2.%20Update%20NuGet%20Packages%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ENow%20let's%20add%20the%20necessary%20NuGet%20Packages.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions'%20CSPROJ%2C%20ensure%20the%20following%20%60PackageReference%60s%20have%20been%20added%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L16-L30%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20For%20%60Microsoft.Azure.Functions.Worker.Sdk%60%2C%20add%20%60OutputItemType%3D%22Analyzer%22%60%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker%22%20version%3D%221.0.0-preview3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker.Sdk%22%20version%3D%221.0.0-preview3%22%20outputitemtype%3D%22Analyzer%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions%22%20version%3D%224.0.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Http%22%20version%3D%223.0.12%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Storage%22%20version%3D%224.0.3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator%22%20version%3D%221.2.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22System.Net.NameResolution%22%20version%3D%224.3.0%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E3.%20Add%20Non-Windows%20Workaround%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EWe%20need%20to%20include%20a%20workaround%20to%20ensure%20this%20new%20out-of-process%20worker%20works%20properly%20on%20non-Windows%20machines.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions%20CSPROJ%2C%20add%20the%20following%20%60Target%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L12-L15%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CTARGET%20name%3D%22CopyRuntimes%22%20aftertargets%3D%22AfterBuild%22%20condition%3D%22%20'%24(OS)'%20%3D%3D%20'UNIX'%20%22%3E%0A%20%3C!--%20To%20workaround%20a%20bug%20where%20the%20files%20aren't%20copied%20correctly%20for%20non-Windows%20platforms%20--%3E%0A%20%3CEXEC%20command%3D%22rm%20-rf%20%24(OutDir)bin%2Fruntimes%2F*%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20mkdir%20-p%20%24(OutDir)bin%2Fruntimes%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20cp%20-R%20%24(OutDir)runtimes%2F*%20%24(OutDir)bin%2Fruntimes%2F%22%3E%3C%2FEXEC%3E%0A%3C%2FTARGET%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E4.%20Update%20local.settings.json%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20run%20our%20Functions%20locally%2C%20we'll%20need%20to%20tell%20the%20Azure%20Functions%20Host%20to%20use%20the%20isolated%20dotnet%20runtime%20in%20%60local.settings.json%60%20by%20by%20setting%20%60FUNCTIONS_WORKER_RUNTIME%60%20to%20%60dotnet-isolated%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2Flocal.settings.json%23L1-L8%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-json%22%3E%3CCODE%3E%7B%0A%20%20%22IsEncrypted%22%3A%20false%2C%0A%20%20%22Values%22%3A%20%7B%0A%20%20%20%20%22FUNCTIONS_WORKER_RUNTIME%22%3A%20%22dotnet-isolated%22%2C%0A%20%20%20%20%22AzureWebJobsStorage%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%2C%0A%20%20%20%20%22AzureWebJobsDashboard%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%0A%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThen%2C%20in%20the%20Functions'%20CSPROJ%2C%20ensure%20it%20is%20being%20copied%20to%20the%20output%20directory%20using%20%60CopyToOutputDirectory%60%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L35-L37%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%3CNONE%20update%3D%22local.settings.json%22%3E%0A%20%20%3CCOPYTOOUTPUTDIRECTORY%3EPreserveNewest%3C%2FCOPYTOOUTPUTDIRECTORY%3E%0A%20%3C%2FNONE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E5.%20Update%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20way%20we%20initialize%20Azure%20Functions%2C%20including%20Dependency%20Injection%2C%20for%20.NET%205%20has%20improved.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20Initialization%20%26amp%3B%20Dependency%20Injection%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20old%20way%20to%20use%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fazure-functions%2Ffunctions-dotnet-dependency-injection%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EDependency%20Injection%20with%20Azure%20Functions%3C%2FA%3E%20was%20to%20add%20the%20%60%5Bassembly%3A%20FunctionsStartup%5D%60%20attribute%20and%20inherit%20from%20%60FunctionsStartup%60.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20how%20we%20%3CEM%3Eused%20to%3C%2FEM%3E%20initialize%20Dependency%20Injection%20in%20Azure%20Functions%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FStartup.cs%23L15-L57%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%0A%0A%5Bassembly%3A%20FunctionsStartup(typeof(Startup))%5D%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20Startup%20%3A%20FunctionsStartup%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20public%20override%20void%20Configure(IFunctionsHostBuilder%20builder)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddHttpClient()%3B()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20way%20is%20to%20initialize%20Azure%20Functions%20in%20.NET%205%20is%20more%20similar%20to%20ASP.NET.%20It%20uses%20to%20%60Microsoft.Extensions.Hosting.HostBuilder%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FProgram.cs%23L15-L67%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20competed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Enamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20class%20Program%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20static%20Task%20Main(string%5B%5D%20args)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20host%20%3D%20new%20HostBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureAppConfiguration(configurationBuilder%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20configurationBuilder.AddCommandLine(args)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureFunctionsWorker((hostBuilderContext%2C%20workerApplicationBuilder)%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20workerApplicationBuilder.UseFunctionExecutionMiddleware()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureServices(services%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddHttpClient()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.Build()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20host.RunAsync()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E6.%20Update%20HttpTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20HttpTrigger%20Function%2C%20we%20replace%20the%20following%20method%20parameters%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60HttpRequest%60%20-%26gt%3B%20%60HttpRequestData%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20%60ILogger%60%20can%20now%20be%20found%20in%20%60FunctionExecutionContext.Logger%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20HttpTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20the%20old%20(pre%20.NET%205)%20way%20of%20creating%20an%20%60HttpTrigger%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L11-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%0A%0Apublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequest%20request%2C%20ILogger%20log)%0A%20%7B%0A%20%20log.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20HttpTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20%60HttpTrigger%60%20syntax%20is%20%3CEM%3Enearly%3C%2FEM%3E%20identical%3B%20only%20%60HttpRequestData%60%20and%20%60FunctionExecutionContext%60%20are%20now%20being%20used%20as%20its%20method%20parameters%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L12-L27%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequestData%20req%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%20%20logger.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E7.%20Update%20TimerTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20TimerTrigger%20Function%2C%20we%20must%20do%20the%20following%3A%3C%2FP%3E%3CUL%3E%3CLI%3ECreate%20%60TimerInfo.cs%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ECreate%20TimerInfo.cs%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20out-of-process%20worker%20doesn't%20yet%20include%20the%20%60TimerInfo%60%20class%2C%20but%20we%20can%20create%20it%20ourselves%20with%20the%20same%20properties%20and%20its%20values%20will%20injected%20at%20runtime%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2FMove-Azure-Functions-to-net5.0%2FGitTrends.Functions%2FTimerInfo.cs%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Eusing%20System%3B%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20TimerInfo%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20public%20ScheduleStatus%3F%20ScheduleStatus%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20a%20value%20indicating%20whether%20this%20timer%20invocation%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20is%20due%20to%20a%20missed%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20bool%20IsPastDue%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20class%20ScheduleStatus%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20recorded%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Last%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20expected%20next%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Next%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20time%20this%20record%20was%20updated.%20This%20is%20used%20to%20re-calculate%20Next%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20with%20the%20current%20Schedule%20after%20a%20host%20restart.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20LastUpdated%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3EOld%20TimerTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20a%20TimerTrigger%20Function%20before%20updating%20it%20to%20.NET%205.0%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L24-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%0A%0Apublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20ILogger%20log)%20%3D%26gt%3B%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20log)%2C%20TrySendFcmSilentNotification(Client%2C%20log))%3B%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20TimerTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20the%20new%20TimerTrigger%2C%20in%20the%20its%20method%20parameters%2C%20we%20remove%20%60ILogger%60%2C%20replacing%20it%20with%20%60FunctionExecutionContext%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L25-L31%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%0A%20%20return%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20logger)%2C%20TrySendFcmSilentNotification(Client%2C%20logger))%3B%0A%20%7D%0A%7D%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E8.%20Run%20.NET%205%20Azure%20Functions%20Locally%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20run%20our%20.NET%205%20Azure%20Functions%20locally%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20Visual%20Studio%20and%20Visual%20Studio%20for%20Mac%20have%20not%20yet%20been%20updated%20to%20run%20.NET%205%20Azure%20Functions.%20If%20you%20try%20to%20run%20this%20code%20using%20Visual%20Studio%2C%20it%20will%20throw%20a%20%60System.UriFormatException%60%3A%20%22Invalid%20URI%3A%20The%20hostname%20could%20not%20be%20parsed.%22%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20host%20start%20--verbose%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EThis%20command%20is%20slightly%20different%20from%20the%20command%20you%20may%20already%20be%20familiar%20with%2C%20%60func%20start%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E9.%20Publish%20.NET%205%20Azure%20Functions%20to%20Azure%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20publish%20our%20.NET%205%20Azure%20Functions%20to%20Azure%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EDeployment%20to%20Azure%20is%20currently%20limited%20to%20Windows%20plans.%20Note%20that%20some%20optimizations%20are%20not%20in%20place%20in%20the%20consumption%20plan%20and%20you%20may%20experience%20longer%20cold%20starts%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60dotnet%20publish%20-c%20Release%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E4.%20On%20the%20command%20line%2C%20navigate%20to%20the%20publish%20artifacts%20by%20entering%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60cd%20.%2Fbin%2FRelease%2Fnet5.0%2Fpublish%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E5.%20On%20the%20command%20line%2C%20publish%20the%20Function%20App%20to%20Azure%20using%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20azure%20functionapp%20publish%20%3CAPP_NAME%3E%60%3C%2FAPP_NAME%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3EConclusion%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20Azure%20Functions%20team%20is%20doing%20a%20ton%20of%20work%20to%20create%20out-of-process%20workers%20that%20allow%20us%20to%20use%20.NET%205.0%20in%20Azure%20Functions.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETheir%20work%20is%20still%20on%20going%2C%20and%20I%20highly%20recommend%20Watching%20%26amp%3B%20Staring%20the%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Eazure-functions-core-tools%3C%2FA%3E%20GitHub%20Repo%3A%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%3C%2FA%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E2.%20Update%20NuGet%20Packages%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ENow%20let's%20add%20the%20necessary%20NuGet%20Packages.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions'%20CSPROJ%2C%20ensure%20the%20following%20%60PackageReference%60s%20have%20been%20added%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L16-L30%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20For%20%60Microsoft.Azure.Functions.Worker.Sdk%60%2C%20add%20%60OutputItemType%3D%22Analyzer%22%60%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker%22%20version%3D%221.0.0-preview3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker.Sdk%22%20version%3D%221.0.0-preview3%22%20outputitemtype%3D%22Analyzer%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions%22%20version%3D%224.0.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Http%22%20version%3D%223.0.12%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Storage%22%20version%3D%224.0.3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator%22%20version%3D%221.2.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22System.Net.NameResolution%22%20version%3D%224.3.0%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E3.%20Add%20Non-Windows%20Workaround%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EWe%20need%20to%20include%20a%20workaround%20to%20ensure%20this%20new%20out-of-process%20worker%20works%20properly%20on%20non-Windows%20machines.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions%20CSPROJ%2C%20add%20the%20following%20%60Target%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L12-L15%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CTARGET%20name%3D%22CopyRuntimes%22%20aftertargets%3D%22AfterBuild%22%20condition%3D%22%20'%24(OS)'%20%3D%3D%20'UNIX'%20%22%3E%0A%20%3C!--%20To%20workaround%20a%20bug%20where%20the%20files%20aren't%20copied%20correctly%20for%20non-Windows%20platforms%20--%3E%0A%20%3CEXEC%20command%3D%22rm%20-rf%20%24(OutDir)bin%2Fruntimes%2F*%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20mkdir%20-p%20%24(OutDir)bin%2Fruntimes%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20cp%20-R%20%24(OutDir)runtimes%2F*%20%24(OutDir)bin%2Fruntimes%2F%22%3E%3C%2FEXEC%3E%0A%3C%2FTARGET%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E4.%20Update%20local.settings.json%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20run%20our%20Functions%20locally%2C%20we'll%20need%20to%20tell%20the%20Azure%20Functions%20Host%20to%20use%20the%20isolated%20dotnet%20runtime%20in%20%60local.settings.json%60%20by%20by%20setting%20%60FUNCTIONS_WORKER_RUNTIME%60%20to%20%60dotnet-isolated%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2Flocal.settings.json%23L1-L8%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-json%22%3E%3CCODE%3E%7B%0A%20%20%22IsEncrypted%22%3A%20false%2C%0A%20%20%22Values%22%3A%20%7B%0A%20%20%20%20%22FUNCTIONS_WORKER_RUNTIME%22%3A%20%22dotnet-isolated%22%2C%0A%20%20%20%20%22AzureWebJobsStorage%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%2C%0A%20%20%20%20%22AzureWebJobsDashboard%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%0A%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThen%2C%20in%20the%20Functions'%20CSPROJ%2C%20ensure%20it%20is%20being%20copied%20to%20the%20output%20directory%20using%20%60CopyToOutputDirectory%60%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L35-L37%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%3CNONE%20update%3D%22local.settings.json%22%3E%0A%20%20%3CCOPYTOOUTPUTDIRECTORY%3EPreserveNewest%3C%2FCOPYTOOUTPUTDIRECTORY%3E%0A%20%3C%2FNONE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E5.%20Update%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20way%20we%20initialize%20Azure%20Functions%2C%20including%20Dependency%20Injection%2C%20for%20.NET%205%20has%20improved.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20Initialization%20%26amp%3B%20Dependency%20Injection%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20old%20way%20to%20use%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fazure-functions%2Ffunctions-dotnet-dependency-injection%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EDependency%20Injection%20with%20Azure%20Functions%3C%2FA%3E%20was%20to%20add%20the%20%60%5Bassembly%3A%20FunctionsStartup%5D%60%20attribute%20and%20inherit%20from%20%60FunctionsStartup%60.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20how%20we%20%3CEM%3Eused%20to%3C%2FEM%3E%20initialize%20Dependency%20Injection%20in%20Azure%20Functions%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FStartup.cs%23L15-L57%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%0A%0A%5Bassembly%3A%20FunctionsStartup(typeof(Startup))%5D%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20Startup%20%3A%20FunctionsStartup%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20public%20override%20void%20Configure(IFunctionsHostBuilder%20builder)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddHttpClient()%3B()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20way%20is%20to%20initialize%20Azure%20Functions%20in%20.NET%205%20is%20more%20similar%20to%20ASP.NET.%20It%20uses%20to%20%60Microsoft.Extensions.Hosting.HostBuilder%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FProgram.cs%23L15-L67%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20competed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Enamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20class%20Program%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20static%20Task%20Main(string%5B%5D%20args)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20host%20%3D%20new%20HostBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureAppConfiguration(configurationBuilder%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20configurationBuilder.AddCommandLine(args)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureFunctionsWorker((hostBuilderContext%2C%20workerApplicationBuilder)%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20workerApplicationBuilder.UseFunctionExecutionMiddleware()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureServices(services%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddHttpClient()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.Build()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20host.RunAsync()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E6.%20Update%20HttpTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20HttpTrigger%20Function%2C%20we%20replace%20the%20following%20method%20parameters%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60HttpRequest%60%20-%26gt%3B%20%60HttpRequestData%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20%60ILogger%60%20can%20now%20be%20found%20in%20%60FunctionExecutionContext.Logger%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20HttpTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20the%20old%20(pre%20.NET%205)%20way%20of%20creating%20an%20%60HttpTrigger%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L11-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%0A%0Apublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequest%20request%2C%20ILogger%20log)%0A%20%7B%0A%20%20log.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20HttpTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20%60HttpTrigger%60%20syntax%20is%20%3CEM%3Enearly%3C%2FEM%3E%20identical%3B%20only%20%60HttpRequestData%60%20and%20%60FunctionExecutionContext%60%20are%20now%20being%20used%20as%20its%20method%20parameters%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L12-L27%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequestData%20req%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%20%20logger.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E7.%20Update%20TimerTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20TimerTrigger%20Function%2C%20we%20must%20do%20the%20following%3A%3C%2FP%3E%3CUL%3E%3CLI%3ECreate%20%60TimerInfo.cs%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ECreate%20TimerInfo.cs%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20out-of-process%20worker%20doesn't%20yet%20include%20the%20%60TimerInfo%60%20class%2C%20but%20we%20can%20create%20it%20ourselves%20with%20the%20same%20properties%20and%20its%20values%20will%20injected%20at%20runtime%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2FMove-Azure-Functions-to-net5.0%2FGitTrends.Functions%2FTimerInfo.cs%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Eusing%20System%3B%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20TimerInfo%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20public%20ScheduleStatus%3F%20ScheduleStatus%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20a%20value%20indicating%20whether%20this%20timer%20invocation%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20is%20due%20to%20a%20missed%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20bool%20IsPastDue%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20class%20ScheduleStatus%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20recorded%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Last%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20expected%20next%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Next%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20time%20this%20record%20was%20updated.%20This%20is%20used%20to%20re-calculate%20Next%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20with%20the%20current%20Schedule%20after%20a%20host%20restart.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20LastUpdated%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3EOld%20TimerTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20a%20TimerTrigger%20Function%20before%20updating%20it%20to%20.NET%205.0%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L24-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%0A%0Apublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20ILogger%20log)%20%3D%26gt%3B%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20log)%2C%20TrySendFcmSilentNotification(Client%2C%20log))%3B%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20TimerTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20the%20new%20TimerTrigger%2C%20in%20the%20its%20method%20parameters%2C%20we%20remove%20%60ILogger%60%2C%20replacing%20it%20with%20%60FunctionExecutionContext%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L25-L31%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%0A%20%20return%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20logger)%2C%20TrySendFcmSilentNotification(Client%2C%20logger))%3B%0A%20%7D%0A%7D%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E8.%20Run%20.NET%205%20Azure%20Functions%20Locally%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20run%20our%20.NET%205%20Azure%20Functions%20locally%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20Visual%20Studio%20and%20Visual%20Studio%20for%20Mac%20have%20not%20yet%20been%20updated%20to%20run%20.NET%205%20Azure%20Functions.%20If%20you%20try%20to%20run%20this%20code%20using%20Visual%20Studio%2C%20it%20will%20throw%20a%20%60System.UriFormatException%60%3A%20%22Invalid%20URI%3A%20The%20hostname%20could%20not%20be%20parsed.%22%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20host%20start%20--verbose%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EThis%20command%20is%20slightly%20different%20from%20the%20command%20you%20may%20already%20be%20familiar%20with%2C%20%60func%20start%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E9.%20Publish%20.NET%205%20Azure%20Functions%20to%20Azure%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20publish%20our%20.NET%205%20Azure%20Functions%20to%20Azure%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EDeployment%20to%20Azure%20is%20currently%20limited%20to%20Windows%20plans.%20Note%20that%20some%20optimizations%20are%20not%20in%20place%20in%20the%20consumption%20plan%20and%20you%20may%20experience%20longer%20cold%20starts%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60dotnet%20publish%20-c%20Release%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E4.%20On%20the%20command%20line%2C%20navigate%20to%20the%20publish%20artifacts%20by%20entering%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60cd%20.%2Fbin%2FRelease%2Fnet5.0%2Fpublish%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E5.%20On%20the%20command%20line%2C%20publish%20the%20Function%20App%20to%20Azure%20using%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20azure%20functionapp%20publish%20%3CAPP_NAME%3E%60%3C%2FAPP_NAME%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3EConclusion%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20Azure%20Functions%20team%20is%20doing%20a%20ton%20of%20work%20to%20create%20out-of-process%20workers%20that%20allow%20us%20to%20use%20.NET%205.0%20in%20Azure%20Functions.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETheir%20work%20is%20still%20on%20going%2C%20and%20I%20highly%20recommend%20Watching%20%26amp%3B%20Staring%20the%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Eazure-functions-core-tools%3C%2FA%3E%20GitHub%20Repo%3A%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%3C%2FA%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2157272%22%20slang%3D%22en-US%22%3ERe%3A%20Creating%20Azure%20Functions%20using%20.NET%205%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2157272%22%20slang%3D%22en-US%22%3E%3CP%3EWhen%20will%20the%20Azure%20Functions%20Project%20templates%20be%20available%20with%20.NET%205%20out%20of%20the%20box%20on%20Visual%20Studio%202019%3F%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E2.%20Update%20NuGet%20Packages%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ENow%20let's%20add%20the%20necessary%20NuGet%20Packages.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions'%20CSPROJ%2C%20ensure%20the%20following%20%60PackageReference%60s%20have%20been%20added%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L16-L30%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20For%20%60Microsoft.Azure.Functions.Worker.Sdk%60%2C%20add%20%60OutputItemType%3D%22Analyzer%22%60%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker%22%20version%3D%221.0.0-preview3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker.Sdk%22%20version%3D%221.0.0-preview3%22%20outputitemtype%3D%22Analyzer%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions%22%20version%3D%224.0.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Http%22%20version%3D%223.0.12%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Storage%22%20version%3D%224.0.3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator%22%20version%3D%221.2.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22System.Net.NameResolution%22%20version%3D%224.3.0%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E3.%20Add%20Non-Windows%20Workaround%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EWe%20need%20to%20include%20a%20workaround%20to%20ensure%20this%20new%20out-of-process%20worker%20works%20properly%20on%20non-Windows%20machines.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions%20CSPROJ%2C%20add%20the%20following%20%60Target%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L12-L15%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CTARGET%20name%3D%22CopyRuntimes%22%20aftertargets%3D%22AfterBuild%22%20condition%3D%22%20'%24(OS)'%20%3D%3D%20'UNIX'%20%22%3E%0A%20%3C!--%20To%20workaround%20a%20bug%20where%20the%20files%20aren't%20copied%20correctly%20for%20non-Windows%20platforms%20--%3E%0A%20%3CEXEC%20command%3D%22rm%20-rf%20%24(OutDir)bin%2Fruntimes%2F*%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20mkdir%20-p%20%24(OutDir)bin%2Fruntimes%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20cp%20-R%20%24(OutDir)runtimes%2F*%20%24(OutDir)bin%2Fruntimes%2F%22%3E%3C%2FEXEC%3E%0A%3C%2FTARGET%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E4.%20Update%20local.settings.json%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20run%20our%20Functions%20locally%2C%20we'll%20need%20to%20tell%20the%20Azure%20Functions%20Host%20to%20use%20the%20isolated%20dotnet%20runtime%20in%20%60local.settings.json%60%20by%20by%20setting%20%60FUNCTIONS_WORKER_RUNTIME%60%20to%20%60dotnet-isolated%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2Flocal.settings.json%23L1-L8%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-json%22%3E%3CCODE%3E%7B%0A%20%20%22IsEncrypted%22%3A%20false%2C%0A%20%20%22Values%22%3A%20%7B%0A%20%20%20%20%22FUNCTIONS_WORKER_RUNTIME%22%3A%20%22dotnet-isolated%22%2C%0A%20%20%20%20%22AzureWebJobsStorage%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%2C%0A%20%20%20%20%22AzureWebJobsDashboard%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%0A%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThen%2C%20in%20the%20Functions'%20CSPROJ%2C%20ensure%20it%20is%20being%20copied%20to%20the%20output%20directory%20using%20%60CopyToOutputDirectory%60%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L35-L37%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%3CNONE%20update%3D%22local.settings.json%22%3E%0A%20%20%3CCOPYTOOUTPUTDIRECTORY%3EPreserveNewest%3C%2FCOPYTOOUTPUTDIRECTORY%3E%0A%20%3C%2FNONE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E5.%20Update%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20way%20we%20initialize%20Azure%20Functions%2C%20including%20Dependency%20Injection%2C%20for%20.NET%205%20has%20improved.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20Initialization%20%26amp%3B%20Dependency%20Injection%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20old%20way%20to%20use%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fazure-functions%2Ffunctions-dotnet-dependency-injection%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EDependency%20Injection%20with%20Azure%20Functions%3C%2FA%3E%20was%20to%20add%20the%20%60%5Bassembly%3A%20FunctionsStartup%5D%60%20attribute%20and%20inherit%20from%20%60FunctionsStartup%60.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20how%20we%20%3CEM%3Eused%20to%3C%2FEM%3E%20initialize%20Dependency%20Injection%20in%20Azure%20Functions%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FStartup.cs%23L15-L57%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%0A%0A%5Bassembly%3A%20FunctionsStartup(typeof(Startup))%5D%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20Startup%20%3A%20FunctionsStartup%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20public%20override%20void%20Configure(IFunctionsHostBuilder%20builder)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddHttpClient()%3B()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20way%20is%20to%20initialize%20Azure%20Functions%20in%20.NET%205%20is%20more%20similar%20to%20ASP.NET.%20It%20uses%20to%20%60Microsoft.Extensions.Hosting.HostBuilder%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FProgram.cs%23L15-L67%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20competed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Enamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20class%20Program%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20static%20Task%20Main(string%5B%5D%20args)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20host%20%3D%20new%20HostBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureAppConfiguration(configurationBuilder%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20configurationBuilder.AddCommandLine(args)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureFunctionsWorker((hostBuilderContext%2C%20workerApplicationBuilder)%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20workerApplicationBuilder.UseFunctionExecutionMiddleware()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureServices(services%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddHttpClient()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.Build()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20host.RunAsync()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E6.%20Update%20HttpTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20HttpTrigger%20Function%2C%20we%20replace%20the%20following%20method%20parameters%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60HttpRequest%60%20-%26gt%3B%20%60HttpRequestData%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20%60ILogger%60%20can%20now%20be%20found%20in%20%60FunctionExecutionContext.Logger%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20HttpTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20the%20old%20(pre%20.NET%205)%20way%20of%20creating%20an%20%60HttpTrigger%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L11-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%0A%0Apublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequest%20request%2C%20ILogger%20log)%0A%20%7B%0A%20%20log.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20HttpTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20%60HttpTrigger%60%20syntax%20is%20%3CEM%3Enearly%3C%2FEM%3E%20identical%3B%20only%20%60HttpRequestData%60%20and%20%60FunctionExecutionContext%60%20are%20now%20being%20used%20as%20its%20method%20parameters%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L12-L27%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequestData%20req%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%20%20logger.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E7.%20Update%20TimerTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20TimerTrigger%20Function%2C%20we%20must%20do%20the%20following%3A%3C%2FP%3E%3CUL%3E%3CLI%3ECreate%20%60TimerInfo.cs%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ECreate%20TimerInfo.cs%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20out-of-process%20worker%20doesn't%20yet%20include%20the%20%60TimerInfo%60%20class%2C%20but%20we%20can%20create%20it%20ourselves%20with%20the%20same%20properties%20and%20its%20values%20will%20injected%20at%20runtime%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2FMove-Azure-Functions-to-net5.0%2FGitTrends.Functions%2FTimerInfo.cs%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Eusing%20System%3B%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20TimerInfo%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20public%20ScheduleStatus%3F%20ScheduleStatus%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20a%20value%20indicating%20whether%20this%20timer%20invocation%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20is%20due%20to%20a%20missed%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20bool%20IsPastDue%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20class%20ScheduleStatus%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20recorded%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Last%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20expected%20next%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Next%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20time%20this%20record%20was%20updated.%20This%20is%20used%20to%20re-calculate%20Next%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20with%20the%20current%20Schedule%20after%20a%20host%20restart.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20LastUpdated%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3EOld%20TimerTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20a%20TimerTrigger%20Function%20before%20updating%20it%20to%20.NET%205.0%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L24-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%0A%0Apublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20ILogger%20log)%20%3D%26gt%3B%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20log)%2C%20TrySendFcmSilentNotification(Client%2C%20log))%3B%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20TimerTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20the%20new%20TimerTrigger%2C%20in%20the%20its%20method%20parameters%2C%20we%20remove%20%60ILogger%60%2C%20replacing%20it%20with%20%60FunctionExecutionContext%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L25-L31%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%0A%20%20return%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20logger)%2C%20TrySendFcmSilentNotification(Client%2C%20logger))%3B%0A%20%7D%0A%7D%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E8.%20Run%20.NET%205%20Azure%20Functions%20Locally%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20run%20our%20.NET%205%20Azure%20Functions%20locally%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20Visual%20Studio%20and%20Visual%20Studio%20for%20Mac%20have%20not%20yet%20been%20updated%20to%20run%20.NET%205%20Azure%20Functions.%20If%20you%20try%20to%20run%20this%20code%20using%20Visual%20Studio%2C%20it%20will%20throw%20a%20%60System.UriFormatException%60%3A%20%22Invalid%20URI%3A%20The%20hostname%20could%20not%20be%20parsed.%22%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20host%20start%20--verbose%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EThis%20command%20is%20slightly%20different%20from%20the%20command%20you%20may%20already%20be%20familiar%20with%2C%20%60func%20start%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E9.%20Publish%20.NET%205%20Azure%20Functions%20to%20Azure%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20publish%20our%20.NET%205%20Azure%20Functions%20to%20Azure%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EDeployment%20to%20Azure%20is%20currently%20limited%20to%20Windows%20plans.%20Note%20that%20some%20optimizations%20are%20not%20in%20place%20in%20the%20consumption%20plan%20and%20you%20may%20experience%20longer%20cold%20starts%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60dotnet%20publish%20-c%20Release%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E4.%20On%20the%20command%20line%2C%20navigate%20to%20the%20publish%20artifacts%20by%20entering%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60cd%20.%2Fbin%2FRelease%2Fnet5.0%2Fpublish%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E5.%20On%20the%20command%20line%2C%20publish%20the%20Function%20App%20to%20Azure%20using%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20azure%20functionapp%20publish%20%3CAPP_NAME%3E%60%3C%2FAPP_NAME%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3EConclusion%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20Azure%20Functions%20team%20is%20doing%20a%20ton%20of%20work%20to%20create%20out-of-process%20workers%20that%20allow%20us%20to%20use%20.NET%205.0%20in%20Azure%20Functions.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETheir%20work%20is%20still%20on%20going%2C%20and%20I%20highly%20recommend%20Watching%20%26amp%3B%20Staring%20the%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Eazure-functions-core-tools%3C%2FA%3E%20GitHub%20Repo%3A%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%3C%2FA%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2156846%22%20slang%3D%22en-US%22%3E(Preview)%20Creating%20Azure%20Functions%20using%20.NET%205%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2156846%22%20slang%3D%22en-US%22%3E%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-center%22%20image-alt%3D%22Group%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F256790i74DF672FB8D16C61%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20role%3D%22button%22%20title%3D%22Group%22%20alt%3D%22Group%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EAzure%20Functions%20%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fapps-on-azure%2Fnet-5-support-on-azure-functions%2Fba-p%2F1973055%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%3Erecently%20released%20preview%20support%20for%20.NET%205%3C%2FA%3E.%20Let's%20take%20a%20look%20at%20how%20to%20upgrade%20our%20%26nbsp%3Bexisting%20Azure%20Functions%20to%20use%20it!%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3A%3C%2FSTRONG%3E%20This%20is%20a%20preview%20experience%20for%20.NET%205%20support%20in%20Azure%20Functions.%20The%20Azure%20Functions%20teams%20notes%20that%20the%20%3CA%20href%3D%22https%3A%2F%2Ftwitter.com%2FnthonyChu%2Fstatus%2F1360702930572042242%3Fs%3D20%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3E%22.NET%205%20experience%20will%20improve%20in%20the%20coming%20weeks%22%3C%2FA%3E.%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3EWhy%20is%20it%20more%20complicated%20than%20last%20time%3F%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EYou%20might%20be%20wondering%20%22Why%20can't%20I%20just%20change%20%60netcoreapp3.1%60%20to%20%60net5.0%60%3F%22%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHistorically%2C%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fazure-functions%2Fcreate-first-function-vs-code-csharp%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%3C%2FA%3E%20has%20always%20been%20tightly%20coupled%20with%20.NET%2C%20specifically%20Long%20Term%20Support%20(LTS)%20.NET%20releases.%20This%20meant%20that%20we%20couldn't%20use%20a%20newer%20version%20of%20.NET%20until%20the%20Azure%20Functions%20team%20also%20updated%20their%20Azure%20Functions%20.NET%20Runtime.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThis%20is%20the%20first%20release%20that%20moves%20.NET%20to%20an%20%22%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fapps-on-azure%2Fnet-5-support-on-azure-functions%2Fba-p%2F1973055%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%3Eout-of-process%20model%3C%2FA%3E%22%2C%20allowing%20us%20to%20run%20our%20Azure%20Functions%20using%20any%20version%20of%20.NET!%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%227%22%3E%3CSTRONG%3EWalkthrough%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20this%20walkthrough%2C%20I'll%20be%20providing%20snippets%20from%20the%20Azure%20Functions%20I%20use%20for%20my%20app%20%3CA%20href%3D%22https%3A%2F%2Fgittrends.com%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3EGitTrends%3C%2FA%3E.%20GitTrends%20is%20an%20open-source%20app%20available%20in%20the%20%3CA%20href%3D%22https%3A%2F%2Fapps.apple.com%2Fapp%2Fgittrends-github-insights%2Fid1500300399%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3EiOS%3C%2FA%3E%20and%20%3CA%20href%3D%22https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dcom.minnick.gittrends%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3EAndroid%3C%2FA%3E%20App%20Stores%2C%20built%20in%20C%23%20using%20Xamarin%2C%20that%20uses%20Azure%20Functions%20for%20its%20backend.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EYou%20can%20find%20the%20completed%20solution%20in%20the%20%60Move-Azure-Functions-to-net5.0%60%20branch%20on%20the%20GitTrends%20repository%2C%20here%3A%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Ftree%2FMove-Azure-Functions-to-net5.0%2FGitTrends.Functions%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Ftree%2FMove-Azure-Functions-to-net5.0%2FGitTrends.Functions%3C%2FA%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E1.%20Update%20.NET%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ELet's%20update%20to%20.NET%205!%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EFirst%2C%20%3CA%20href%3D%22https%3A%2F%2Fdotnet.microsoft.com%2Fdownload%2Fdotnet%2F5.0%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Edownload%20the%20.NET%205%20SDK%3C%2FA%3E%20and%20install%20it%20on%20your%20development%20machine.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThen%2C%20in%20your%20Functions'%20CSPROJ%2C%20set%20the%20following%20values%20for%20%60TargetFramework%60%2C%20%60LangVersion%60%2C%20%60AzureFunctionsVersion%60%2C%60%20OutputType%60%20and%20%60_FunctionsSkipCleanOutput%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L3-L11%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CPROPERTYGROUP%3E%0A%20%3CTARGETFRAMEWORK%3Enet5.0%3C%2FTARGETFRAMEWORK%3E%0A%20%3CLANGVERSION%3Epreview%3C%2FLANGVERSION%3E%0A%20%3CAZUREFUNCTIONSVERSION%3Ev3%3C%2FAZUREFUNCTIONSVERSION%3E%0A%20%3COUTPUTTYPE%3EExe%3C%2FOUTPUTTYPE%3E%0A%20%26lt%3B_FunctionsSkipCleanOutput%26gt%3Btrue%3C%2FPROPERTYGROUP%3E%0A%3C%2FCODE%3E%3C%2FPRE%3E%3C%2FLINGO-BODY%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E2.%20Update%20NuGet%20Packages%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ENow%20let's%20add%20the%20necessary%20NuGet%20Packages.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions'%20CSPROJ%2C%20ensure%20the%20following%20%60PackageReference%60s%20have%20been%20added%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L16-L30%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20For%20%60Microsoft.Azure.Functions.Worker.Sdk%60%2C%20add%20%60OutputItemType%3D%22Analyzer%22%60%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker%22%20version%3D%221.0.0-preview3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.Functions.Worker.Sdk%22%20version%3D%221.0.0-preview3%22%20outputitemtype%3D%22Analyzer%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions%22%20version%3D%224.0.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Http%22%20version%3D%223.0.12%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Extensions.Storage%22%20version%3D%224.0.3%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator%22%20version%3D%221.2.1%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%20%20%20%20%3CPACKAGEREFERENCE%20include%3D%22System.Net.NameResolution%22%20version%3D%224.3.0%22%3E%3C%2FPACKAGEREFERENCE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E3.%20Add%20Non-Windows%20Workaround%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EWe%20need%20to%20include%20a%20workaround%20to%20ensure%20this%20new%20out-of-process%20worker%20works%20properly%20on%20non-Windows%20machines.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20your%20Functions%20CSPROJ%2C%20add%20the%20following%20%60Target%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L12-L15%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CTARGET%20name%3D%22CopyRuntimes%22%20aftertargets%3D%22AfterBuild%22%20condition%3D%22%20'%24(OS)'%20%3D%3D%20'UNIX'%20%22%3E%0A%20%3C!--%20To%20workaround%20a%20bug%20where%20the%20files%20aren't%20copied%20correctly%20for%20non-Windows%20platforms%20--%3E%0A%20%3CEXEC%20command%3D%22rm%20-rf%20%24(OutDir)bin%2Fruntimes%2F*%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20mkdir%20-p%20%24(OutDir)bin%2Fruntimes%20%26amp%3Bamp%3B%26amp%3Bamp%3B%20cp%20-R%20%24(OutDir)runtimes%2F*%20%24(OutDir)bin%2Fruntimes%2F%22%3E%3C%2FEXEC%3E%0A%3C%2FTARGET%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E4.%20Update%20local.settings.json%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20run%20our%20Functions%20locally%2C%20we'll%20need%20to%20tell%20the%20Azure%20Functions%20Host%20to%20use%20the%20isolated%20dotnet%20runtime%20in%20%60local.settings.json%60%20by%20by%20setting%20%60FUNCTIONS_WORKER_RUNTIME%60%20to%20%60dotnet-isolated%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2Flocal.settings.json%23L1-L8%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-json%22%3E%3CCODE%3E%7B%0A%20%20%22IsEncrypted%22%3A%20false%2C%0A%20%20%22Values%22%3A%20%7B%0A%20%20%20%20%22FUNCTIONS_WORKER_RUNTIME%22%3A%20%22dotnet-isolated%22%2C%0A%20%20%20%20%22AzureWebJobsStorage%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%2C%0A%20%20%20%20%22AzureWebJobsDashboard%22%3A%20%22UseDevelopmentStorage%3Dtrue%22%0A%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThen%2C%20in%20the%20Functions'%20CSPROJ%2C%20ensure%20it%20is%20being%20copied%20to%20the%20output%20directory%20using%20%60CopyToOutputDirectory%60%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FGitTrends.Functions.csproj%23L35-L37%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-html%22%3E%3CCODE%3E%3CITEMGROUP%3E%0A%20%3CNONE%20update%3D%22local.settings.json%22%3E%0A%20%20%3CCOPYTOOUTPUTDIRECTORY%3EPreserveNewest%3C%2FCOPYTOOUTPUTDIRECTORY%3E%0A%20%3C%2FNONE%3E%0A%3C%2FITEMGROUP%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E5.%20Update%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20way%20we%20initialize%20Azure%20Functions%2C%20including%20Dependency%20Injection%2C%20for%20.NET%205%20has%20improved.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20Initialization%20%26amp%3B%20Dependency%20Injection%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20old%20way%20to%20use%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fazure%2Fazure-functions%2Ffunctions-dotnet-dependency-injection%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EDependency%20Injection%20with%20Azure%20Functions%3C%2FA%3E%20was%20to%20add%20the%20%60%5Bassembly%3A%20FunctionsStartup%5D%60%20attribute%20and%20inherit%20from%20%60FunctionsStartup%60.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20how%20we%20%3CEM%3Eused%20to%3C%2FEM%3E%20initialize%20Dependency%20Injection%20in%20Azure%20Functions%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FStartup.cs%23L15-L57%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%0A%0A%5Bassembly%3A%20FunctionsStartup(typeof(Startup))%5D%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20Startup%20%3A%20FunctionsStartup%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20public%20override%20void%20Configure(IFunctionsHostBuilder%20builder)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddHttpClient()%3B()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20builder.Services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20using%20Dependency%20Injection%20with%20Azure%20Functions%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20Initialization%20%26amp%3B%20Dependency%20Injection%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20way%20is%20to%20initialize%20Azure%20Functions%20in%20.NET%205%20is%20more%20similar%20to%20ASP.NET.%20It%20uses%20to%20%60Microsoft.Extensions.Hosting.HostBuilder%60%2C%20like%20so%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FProgram.cs%23L15-L67%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20competed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Enamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20class%20Program%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20readonly%20static%20string%20_storageConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22AzureWebJobsStorage%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%20%20%20%20%20%20%20static%20Task%20Main(string%5B%5D%20args)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20host%20%3D%20new%20HostBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureAppConfiguration(configurationBuilder%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20configurationBuilder.AddCommandLine(args)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureFunctionsWorker((hostBuilderContext%2C%20workerApplicationBuilder)%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20workerApplicationBuilder.UseFunctionExecutionMiddleware()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.ConfigureServices(services%20%3D%26gt%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddHttpClient()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CBLOBSTORAGESERVICE%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20services.AddSingleton%3CCLOUDBLOBCLIENT%3E(CloudStorageAccount.Parse(_storageConnectionString).CreateCloudBlobClient())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.Build()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20host.RunAsync()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3C%2FCLOUDBLOBCLIENT%3E%3C%2FBLOBSTORAGESERVICE%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E6.%20Update%20HttpTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20HttpTrigger%20Function%2C%20we%20replace%20the%20following%20method%20parameters%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60HttpRequest%60%20-%26gt%3B%20%60HttpRequestData%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20%60ILogger%60%20can%20now%20be%20found%20in%20%60FunctionExecutionContext.Logger%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3EOld%20HttpTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20the%20old%20(pre%20.NET%205)%20way%20of%20creating%20an%20%60HttpTrigger%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L11-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%0A%0Apublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequest%20request%2C%20ILogger%20log)%0A%20%7B%0A%20%20log.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20HttpTrigger%20with%20Azure%20Functions%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20HttpTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20new%20%60HttpTrigger%60%20syntax%20is%20%3CEM%3Enearly%3C%2FEM%3E%20identical%3B%20only%20%60HttpRequestData%60%20and%20%60FunctionExecutionContext%60%20are%20now%20being%20used%20as%20its%20method%20parameters%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FGetGitHubClientId.cs%23L12-L27%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20static%20class%20GetGitHubClientId%0A%7B%0A%20readonly%20static%20string%20_clientId%20%3D%20Environment.GetEnvironmentVariable(%22GitTrendsClientId%22)%20%3F%3F%20string.Empty%3B%0A%0A%20%5BFunctionName(nameof(GetGitHubClientId))%5D%0A%20public%20static%20IActionResult%20Run(%5BHttpTrigger(AuthorizationLevel.Anonymous%2C%20%22get%22)%5D%20HttpRequestData%20req%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%20%20logger.LogInformation(%22Retrieving%20Client%20Id%22)%3B%0A%0A%20%20if%20(string.IsNullOrWhiteSpace(_clientId))%0A%20%20%20return%20new%20NotFoundObjectResult(%22Client%20ID%20Not%20Found%22)%3B%0A%0A%20%20return%20new%20OkObjectResult(new%20GetGitHubClientIdDTO(_clientId))%3B%0A%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E7.%20Update%20TimerTrigger%20Functions%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETo%20update%20an%20existing%20TimerTrigger%20Function%2C%20we%20must%20do%20the%20following%3A%3C%2FP%3E%3CUL%3E%3CLI%3ECreate%20%60TimerInfo.cs%60%3C%2FLI%3E%3CLI%3E%60ILogger%60%20-%26gt%3B%20%60FunctionExecutionContext%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ECreate%20TimerInfo.cs%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20out-of-process%20worker%20doesn't%20yet%20include%20the%20%60TimerInfo%60%20class%2C%20but%20we%20can%20create%20it%20ourselves%20with%20the%20same%20properties%20and%20its%20values%20will%20injected%20at%20runtime%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2FMove-Azure-Functions-to-net5.0%2FGitTrends.Functions%2FTimerInfo.cs%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20completed%20working%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Eusing%20System%3B%0Anamespace%20GitTrends.Functions%0A%7B%0A%20%20%20%20public%20class%20TimerInfo%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20public%20ScheduleStatus%3F%20ScheduleStatus%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20a%20value%20indicating%20whether%20this%20timer%20invocation%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20is%20due%20to%20a%20missed%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20bool%20IsPastDue%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20class%20ScheduleStatus%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20recorded%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Last%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20expected%20next%20schedule%20occurrence.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20Next%20%7B%20get%3B%20set%3B%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3CSUMMARY%3E%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20Gets%20or%20sets%20the%20last%20time%20this%20record%20was%20updated.%20This%20is%20used%20to%20re-calculate%20Next%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20with%20the%20current%20Schedule%20after%20a%20host%20restart.%0A%20%20%20%20%20%20%20%20%2F%2F%2F%20%3C%2FSUMMARY%3E%0A%20%20%20%20%20%20%20%20public%20DateTime%20LastUpdated%20%7B%20get%3B%20set%3B%20%7D%0A%20%20%20%20%7D%0A%7D%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3EOld%20TimerTrigger%20(pre%20.NET%205.0)%3C%2FSTRONG%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EHere%20is%20an%20example%20of%20a%20TimerTrigger%20Function%20before%20updating%20it%20to%20.NET%205.0%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2F12b18d54373106cd13c0b0a523740afcf15a2fde%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L24-L25%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3E%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%0A%0Apublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20ILogger%20log)%20%3D%26gt%3B%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20log)%2C%20TrySendFcmSilentNotification(Client%2C%20log))%3B%0A%7D%0A%0A%2F%2FNote%3A%20This%20is%20the%20old%20(pre-.NET%205)%20way%20of%20creating%20an%20TimerTrigger%20with%20Azure%20Functions%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%224%22%3E%3CSTRONG%3ENew%20TimerTrigger%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EIn%20the%20new%20TimerTrigger%2C%20in%20the%20its%20method%20parameters%2C%20we%20remove%20%60ILogger%60%2C%20replacing%20it%20with%20%60FunctionExecutionContext%60%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E(%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2Fbrminnick%2FGitTrends%2Fblob%2Fcec71347be100d5d1ab4a3c5b8fd2a5ca0bdf906%2FGitTrends.Functions%2FFunctions%2FSendSilentPushNotification.cs%23L25-L31%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EHere%20is%20a%20working%20completed%20example%3C%2FA%3E)%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-csharp%22%3E%3CCODE%3Epublic%20class%20SendSilentPushNotification%0A%7B%0A%20const%20string%20_runEveryHourCron%20%3D%20%220%200%20*%20*%20*%20*%22%3B%0A%20%20%20%20%0A%20readonly%20static%20string%20_notificationHubFullConnectionString%20%3D%20Environment.GetEnvironmentVariable(%22NotificationHubFullConnectionString%22)%20%3F%3F%20string.Empty%3B%0A%20%20%20%20%20%20%20%20%0A%20readonly%20static%20Lazy%3CNOTIFICATIONHUBCLIENT%3E%20_clientHolder%20%3D%20new(NotificationHubClient.CreateClientFromConnectionString(_notificationHubFullConnectionString%2C%20GetNotificationHubInformation.NotificationHubName))%3B%0A%0A%20static%20NotificationHubClient%20Client%20%3D%26gt%3B%20_clientHolder.Value%3B%0A%0A%20%5BFunctionName(nameof(SendSilentPushNotification))%5D%0A%20public%20static%20Task%20Run(%5BTimerTrigger(_runEveryHourCron)%5D%20TimerInfo%20myTimer%2C%20FunctionExecutionContext%20executionContext)%0A%20%7B%0A%20%20var%20logger%20%3D%20executionContext.Logger%3B%0A%0A%20%20return%20Task.WhenAll(TrySendAppleSilentNotification(Client%2C%20logger)%2C%20TrySendFcmSilentNotification(Client%2C%20logger))%3B%0A%20%7D%0A%7D%3C%2FNOTIFICATIONHUBCLIENT%3E%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E8.%20Run%20.NET%205%20Azure%20Functions%20Locally%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20run%20our%20.NET%205%20Azure%20Functions%20locally%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3C%2FSTRONG%3E%3A%20Visual%20Studio%20and%20Visual%20Studio%20for%20Mac%20have%20not%20yet%20been%20updated%20to%20run%20.NET%205%20Azure%20Functions.%20If%20you%20try%20to%20run%20this%20code%20using%20Visual%20Studio%2C%20it%20will%20throw%20a%20%60System.UriFormatException%60%3A%20%22Invalid%20URI%3A%20The%20hostname%20could%20not%20be%20parsed.%22%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20host%20start%20--verbose%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EThis%20command%20is%20slightly%20different%20from%20the%20command%20you%20may%20already%20be%20familiar%20with%2C%20%60func%20start%60%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3E9.%20Publish%20.NET%205%20Azure%20Functions%20to%20Azure%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ECurrently%2C%20the%20only%20way%20to%20publish%20our%20.NET%205%20Azure%20Functions%20to%20Azure%20is%20to%20use%20the%20command%20line.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CBLOCKQUOTE%3E%3CSTRONG%3ENote%3A%20%3C%2FSTRONG%3EDeployment%20to%20Azure%20is%20currently%20limited%20to%20Windows%20plans.%20Note%20that%20some%20optimizations%20are%20not%20in%20place%20in%20the%20consumption%20plan%20and%20you%20may%20experience%20longer%20cold%20starts%3C%2FBLOCKQUOTE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E1.%20Install%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3EAzure%20Functions%20Core%20Tools%20v3.0.3160%3C%2FA%3E%3C%2FP%3E%3CUL%3E%3CLI%3EOn%20macOS%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fmacpaw.com%2Fhow-to%2Fuse-terminal-on-mac%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ETerminal%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60brew%20tap%20azure%2Ffunctions%3B%20brew%20install%20azure-functions-core-tools%403%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3CLI%3EOn%20Windows%3A%20Open%20the%20%3CA%20href%3D%22https%3A%2F%2Fwww.howtogeek.com%2F235101%2F10-ways-to-open-the-command-prompt-in-windows-10%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20nofollow%20noreferrer%22%3ECommand%20Prompt%3C%2FA%3E%20and%20run%20the%20following%20command%3A%3CUL%3E%3CLI%3E%60npm%20i%20-g%20azure-functions-core-tools%403%20--unsafe-perm%20true%60%3C%2FLI%3E%3C%2FUL%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E2.%20On%20the%20command%20line%2C%20navigate%20to%20the%20folder%20containing%20your%20Azure%20Functions%20CSPROJ%3C%2FP%3E%3CP%3E3.%20On%20the%20command%20line%2C%20enter%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60dotnet%20publish%20-c%20Release%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E4.%20On%20the%20command%20line%2C%20navigate%20to%20the%20publish%20artifacts%20by%20entering%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60cd%20.%2Fbin%2FRelease%2Fnet5.0%2Fpublish%60%3C%2FLI%3E%3C%2FUL%3E%3CP%3E5.%20On%20the%20command%20line%2C%20publish%20the%20Function%20App%20to%20Azure%20using%20the%20following%20command%3A%3C%2FP%3E%3CUL%3E%3CLI%3E%60func%20azure%20functionapp%20publish%20%3CAPP_NAME%3E%60%3C%2FAPP_NAME%3E%3C%2FLI%3E%3C%2FUL%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CFONT%20size%3D%225%22%3E%3CSTRONG%3EConclusion%3C%2FSTRONG%3E%3C%2FFONT%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EThe%20Azure%20Functions%20team%20is%20doing%20a%20ton%20of%20work%20to%20create%20out-of-process%20workers%20that%20allow%20us%20to%20use%20.NET%205.0%20in%20Azure%20Functions.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ETheir%20work%20is%20still%20on%20going%2C%20and%20I%20highly%20recommend%20Watching%20%26amp%3B%20Staring%20the%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Eazure-functions-core-tools%3C%2FA%3E%20GitHub%20Repo%3A%20%3CA%20href%3D%22https%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgithub.com%2FAzure%2Fazure-functions-core-tools%3C%2FA%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-2156846%22%20slang%3D%22en-US%22%3E%3CP%3EAzure%20Functions%20%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fapps-on-azure%2Fnet-5-support-on-azure-functions%2Fba-p%2F1973055%3FWT.mc_id%3Ddotnet-13135-bramin%22%20target%3D%22_blank%22%3Erecently%20released%20preview%20support%20for%20.NET%205%3C%2FA%3E.%20Let's%20take%20a%20look%20at%20how%20to%20upgrade%20our%20%26nbsp%3Bexisting%20Azure%20Functions%20to%20use%20it!%3C%2FP%3E%3C%2FLINGO-TEASER%3E%3CLINGO-LABS%20id%3D%22lingo-labs-2156846%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3E.NET%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EAzure%20Functions%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EMobile%20Apps%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EServerless%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E%3CLINGO-SUB%20id%3D%22lingo-sub-2258984%22%20slang%3D%22en-US%22%3ERe%3A%20(Preview)%20Creating%20Azure%20Functions%20using%20.NET%205%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2258984%22%20slang%3D%22en-US%22%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F144917%22%20target%3D%22_blank%22%3E%40Tony%20Henrique%3C%2FA%3E%26nbsp%3BMay%2025%3F%20%3A)%3C%2Fimg%3E%20-%26gt%3B%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fmybuild.microsoft.com%2F%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fmybuild.microsoft.com%3C%2FA%3E%3C%2FP%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F714639%22%20target%3D%22_blank%22%3E%40bminnick%3C%2FA%3E%26nbsp%3Bhow%20to%20run%20this%20today%20in%20VS%202019%3F%3C%2FP%3E%3C%2FLINGO-BODY%3E
Co-Authors
Version history
Last update:
‎Feb 23 2021 01:10 PM
Updated by: