Rustem Mustafin
Rustem Mustafin

Reputation: 957

Deploy Azure function from code (c#)

How to deploy azure function (executed on schedule) with code as string (in c#) to given azure functions app?

I am going to use ARM template to deploy azure fund app (+ all it needs) https://github.com/Azure/azure-quickstart-templates/tree/master/101-function-app-create-dynamic, which can be deployed via code;

But I don't see ways to deploy function to function app via code.

+ A little more context: deployment is going to happen from an app service, so it's preferred not to have any dependencies beyond NuGet. E.g. I don't like the idea to call azure cli from c#.

Upvotes: 1

Views: 2392

Answers (2)

Tom Sun
Tom Sun

Reputation: 24529

As Jesse Carter mentioned that we could use Kudu Zip Api to do that. I do a demo for that. It works correctly on my side. The following is my detail steps:

Preparation:

Registry an AD application and assign role to applcation, more details please refer to Azure official tutorials. After that we can get tenantId, appId, secretKey from the Azure Portal.

1.Prepare an authentication file, we could get more information from github document.

subscription=########-####-####-####-############
client=########-####-####-####-############
tenant=########-####-####-####-############
managementURI=https\://management.core.windows.net/
baseURL=https\://management.azure.com/
authURL=https\://login.windows.net/
graphURL=https\://graph.windows.net/

2.Zip the need to be published file

Steps:

1.Create a C# console project

2.Reference the Microsoft.Azure.Management.ResourceManager.Fluent and Microsoft.Azure.Management.AppService.Fluent, more detail info please refer to the packages.config file section.

3.Add the following code in the Program.cs file

   var credentials = SdkContext.AzureCredentialsFactory.FromFile(@"authentication file path");
   var azure = Azure
                .Configure()
                .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
                .Authenticate(credentials)
                .WithDefaultSubscription();
   var webFunctionAppName = "azure function name";
   var webFunctionApp = azure.AppServices.FunctionApps.List().Where(x => x.Name.Equals(webFunctionAppName))?.First();
   var ftpUsername = azure.AppServices.FunctionApps.GetById(webFunctionApp.Id).GetPublishingProfile().FtpUsername;
   var username = ftpUsername.Split('\\').ToList()[1];
   var password = azure.AppServices.FunctionApps.GetById(webFunctionApp.Id).GetPublishingProfile().FtpPassword;
   var base64Auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
   var file = File.ReadAllBytes(@"zip file path");
   MemoryStream stream = new MemoryStream(file);

    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Add("Authorization", "Basic " + base64Auth);
        var baseUrl = new Uri($"https://{webFunctionAppName}.scm.azurewebsites.net/");
        var requestURl = baseUrl+ "api/zip/site/wwwroot";
        var httpContent = new StreamContent(stream);
        var response = client.PutAsync(requestURl, httpContent).Result;
     }

4.Test from the local

enter image description here

5.Check the published result from the Azure kudu tool(https://yourazurefunctionanme.scm.azurewebsites.net/)

enter image description here

packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.Azure.Management.AppService.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Batch.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Cdn.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Compute.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.ContainerRegistry.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Dns.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.DocumentDB.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Graph.RBAC.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.KeyVault.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Network.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Redis.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.ResourceManager.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.ServiceBus.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Sql.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Storage.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.TrafficManager.Fluent" version="1.1.3" targetFramework="net452" />
  <package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.28.3" targetFramework="net452" />
  <package id="Microsoft.Rest.ClientRuntime" version="2.3.8" targetFramework="net452" />
  <package id="Microsoft.Rest.ClientRuntime.Azure" version="3.3.8" targetFramework="net452" />
  <package id="Microsoft.Rest.ClientRuntime.Azure.Authentication" version="2.3.0" targetFramework="net452" />
  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
</packages>

Upvotes: 9

Jesse Carter
Jesse Carter

Reputation: 21147

If you're going to deploy the function itself directly from code as opposed to using a CI/CD pipeline then your best bet is to use the Kudu REST APIs to upload the function code as a zip to the running function app. You should be able to make do using HttpClient or any of the other .NET REST libraries.

Upvotes: 1

Related Questions