Search code examples
c#azureazure-functionsazure-http-trigger

Azure HttpTriggers in referenced assembly are not detected by JobHost


Current

I have a growing library of Function Apps (currently 14) that create different 3D models but by design each one has the same identical HttpTriggers so that the central system can call/trigger them to build and return their models.

e.g. HttpTriggers such as:

[FunctionName("Register")]
[FunctionName("Awake")]
[FunctionName("Restart")]
[FunctionName("GetAppDetails")]
[FunctionName("Version")]
[FunctionName("GetThumbnail")]
[FunctionName("GetDefaultObject")]
[FunctionName("GetObject")]

etc..

I am running on Azure Function runtime v4.x using the C#6 In Process model. All the Function apps work fine and have done so for a couple of years or more.

However, each 3D model Function App has its own VS solution (so that anyone may independently develop one) and EACH AND EVERY project includes the identical boilerplate code for the HttpTriggers so that it can interop with the platform. This seems inefficient and causes unwanted code duplication.

Desired

I would like to amend their Visual Studio template projects such that the boilerplate source code for the common HttpTriggers is hidden in a referenced dll/nuget package thereby keeping the VS template nice and simple for new developers to develop their 3D model business logic without needing to be concerned (and also to prevent tinkering) with the HttpTrigger boilerplate code that communicates with the platform.

So far I have been unsuccessful in achieving this because when i move the HttpTrigger source code to a referenced assembly the Function Apps JobHost no longer detects them. Here is the message reported from the JobHost when any of them start up...

Azure Functions Core Tools
Core Tools Version:       4.0.5198 Commit hash: N/A  (64-bit)
Function Runtime Version: 4.21.1.20667

[2023-08-02T16:12:34.160Z] Found C:\Users\ocon5376\source\repos\_DO\_Assets\AccessCover\src\AccessCover.csproj. Using for user secrets file configuration.
[2023-08-02T16:12:40.651Z] No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
For detailed output, run func with --verbose flag.
[2023-08-02T16:12:45.220Z] Host lock lease acquired by instance ID '000000000000000000000000C3B350B9'.

This post talks about a similar issue and in an endeavour to follow its guidance and force my referenced assembly to be loaded in time I have tried making the class containing the HttpTriggers the StartUp class and confirmed that execution arrived in the public override void Configure(IFunctionsHostBuilder builder) method where I added *AppDomain.CurrentDomain.Load(xxx)* -- However this did not cause the HttpTriggers to be detected so I guess the JobHost is too far progressed by the time that the StartUp class is processed.

I have not found any directly similar posts to this on SO so far. Does anyone know if it is possible to do this or an alternative strategy to achieve my goals of hiding and avoiding duplicating the HttpTrigger boilerplate code?

--EDIT -- I also tried adding a static constructor with the [ModuleInitializer] attribute as follows:

[ModuleInitializer]
public static void Init()
{            
    AppDomain.CurrentDomain.Load("Atkins.DynamicObjects.AssetCore"); // manually load into the current domain
}

However, this strategy was unsuccessful because it doesn't get called when the assembly loads but only when it is first accessed. -Debugging confirmed that execution didn't arrive in this block until after the JobHost had loaded and scanned the assembly - so it was no good.

Another idea i wondered about was to use the assemblyload event but unless I am mistaken the eventhandler would need to be added in the source code of the JobHost - and therefore it is upstream of my own code and not an option for me.


Solution

  • There is a FunctionsInDependencies property available in the MSBuild Task used to build functions which should help you achieve this.