0
votes

I have an existing function app to which that I need to deploy a serviceBusTrigger function after user action in the application. To do this, I have been using the following post Deploy Azure function from code (c#).

Azure function version 2.0 for this function app

I am currently creating a zip containing /function.json that is being posted to the api/zip endpoint using the following method

public void CreateAzureFunctionToMonitorQueue(string functionName, string serviceBusQueueName, string path)
    {
        // create zip of new function
        // ZipFile.CreateFromDirectory will create a zip with the directory's name containing the directory's contents
        // so CreateZipOfFunc creates a structure <functionName>/<functionName>/function.json
        // so that the zip contains <functionName>/function.json 
        // which is the required input for api/zip/ from kudu api
        var zipFile = CreateZipOfFunc(functionName, serviceBusQueueName, path);
        var file = File.ReadAllBytes(zipFile);

        MemoryStream stream = new MemoryStream(file);

        using (var client = new HttpClient())
        {
            // deploy zip using Kudu REST api
            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;
        }
        // remove files
        Directory.Delete($"{path}{functionName}", true);
        File.Delete($"{path}{functionName}.zip");
        // deployment using Kudu REST api requires the function triggers to be manually synced
        SyncTriggers();
    }

At the end, I run SyncTriggers which manually syncs the function app's trigger because I read that deploying this way requires this for all trigger except http, found here https://docs.microsoft.com/en-us/azure/azure-functions/functions-deployment-technologies. I am using the second method of manually syncing triggers. Below is the method

public void SyncTriggers()
    {
        using (var client = new HttpClient())
        {
            var requestUrl = $"https://{_webFunctionAppName}.azurewebsites.net/admin/host/synctriggers?code={_MASTER_KEY}";
            var httpContent = new StringContent("");
            var response = client.PostAsync(requestUrl, httpContent).Result;
        }
    }

The result of both requests is successful, and when I look in the azure portal, the new function is there with a function.json file that matches a working serviceBusTrigger when deployed using Visual Studio webdeploy.

For testing this, I first disable the working azure function, run the above code and then push a new message to the monitored queue; however, nothing happens when the message becomes active.

If I enable the function deployed using VS that already existed, that function will fire and handle the message.

Existing function's function.json file looks like the following

{
  "generatedBy": "Microsoft.NET.Sdk.Functions-1.0.26",
  "configurationSource": "attributes",
  "bindings": [
    {
      "type": "serviceBusTrigger",
      "connection": "ServiceBusConnection",
      "queueName": "myqueue",
      "name": "queueItem"
    }
  ],
  "disabled": false,
  "scriptFile": "../bin/MyProject.MyLibrary.dll",
  "entryPoint": "MyProject.MyLibrary.MyClass.RunAsync"
}

The function deployed using the above method has a function.json like the following

{
  "generatedBy": "Microsoft.NET.Sdk.Functions - 1.0.26",
  "configurationSource": "attributes",
  "bindings": [
    {
      "type": "serviceBusTrigger",
      "connection": "ServiceBusConnection",
      "queueName": "myqueue",
      "name": "queueItem"
    }
  ],
  "disabled": false,
  "scriptFile": "../bin/MyProject.MyLibrary.dll",
  "entryPoint": "MyProject.MyLibrary.MyClass.RunAsync"
}

Am I missing something? My use case for this is, after I create a new queue, I want to create a monitoring azure function to listen to it. Creating the queue using NameSpaceManager works fine and pushing messages to it works fine as well. I just can't seem to get this test case working where I am creating a function to monitor an existing queue.

Possibly the function is not register and properly setup when I am calling SyncTrigger??

Thanks

Edit: I just saw this post https://blogs.msdn.microsoft.com/benjaminperkins/2018/08/07/why-does-my-azure-function-sometimes-stop-being-triggered/ which says:

Your endpoint must trigger/bind to only one Azure Function

Does that mean that I can only have one function registered to a function in my uploaded dll? Should I instead upload a copy of the entrypoint method I want with a different name as a .csx with the function.json file?

Edit2: That seems to just be related to az fns to binding resource, does not seem to help

Edit3: After a lot of research, it seems that the configurationSource for my generated function.json should not be "attributes" but instead "config". Going to test this now.

Edit4: The issue was fixed by removing generatedBy and changing configurationSource to "config" in the function.json file I am generating.

Edit5: removed misleading questions

1

1 Answers

0
votes

The issue is that functions deployed using VS have the two properties in function.json

"generatedBy": "Microsoft.NET.Sdk.Functions - 1.0.26",
"configurationSource": "attributes",

which really just tell azure from where the function was generated and to use the attributes of the method that is the function's entrypoint as the configuration source. Removing generatedBy allows one to edit the function in azure portal and changing configurationSource to "config" tells the azure function runtime to use the function.json file for binding configuration and what not.

However, in the azure portal, I am getting a message

Error:

Function (MyFunction) Error: Configuration error: all functions in D:\home\site\wwwroot\bin\MyProject.MyLibrary.dll must have the same value for 'configurationSource'.
Session Id: MY_SESSION_ID

Timestamp: 2019-06-30T21:04:22.709Z

My function that I deployed still worked, and other existing functions that have http bindings that the deployed function calls still work (they have function.json files that have generatedBy Skd.Functions and configurationSource: "attributes", so this does not seem to be a make or break error at the moment; however, I will be changing my deployment so that all have configurationSource: "config"

so changing the output function.json to be

{
  "configurationSource": "config",
  "bindings": [
    {
      "type": "serviceBusTrigger",
      "connection": "ServiceBusConnection",
      "queueName": "myqueue",
      "name": "queueItem"
    }
  ],
  "disabled": false,
  "scriptFile": "../bin/MyProject.MyLibrary.dll",
  "entryPoint": "MyProject.MyLibrary.MyClass.RunAsync"
}

resolved my issue