Azure-functions-host: Referenced nuget pkgs are not loaded by custom assemblies in root sharedbin folder

Created on 20 Feb 2017  路  7Comments  路  Source: Azure/azure-functions-host

Original discussion thread from StackOverflow with @fabiocav: (http://stackoverflow.com/questions/42281084/getting-null-terms-when-accesing-termcollection-from-sharepoint-online-via-csom).

When a custom assembly, which references a nuget package, is published into the wwwroot/sharedbin folder, the runtime cannot acccess the referenced nuget packages which are declared as dependencies of a child function in its project.json file.

Repro steps

  1. Create an HTTP triggered C# function with a project.json referencing the SharePoint CSOM nuget package as a dependency (see gist link below).

  2. Add 3 app settings to the function's app service settings (SPOSiteUrl, SPOUserName, SPOPassword), with valid credentials and URL to connect to an existing SharePoint Online tenant site.

  3. Build a custom assembly, from a class library project which references the same SharePoint CSOM nuget package as the Azure function. Place the custom DLL into wwwroot/sharedbin using Kudu. (see gist link below for complete example files)

  4. Run the Azure function

Expected behavior

Function should invoke the code from the custom assembly within sharedbin folder, which logs into a SharePoint Online tenant with credentials, then connects to the default Taxonomy store, and retrieves all terms for a specified TermSet Guid, and returns the term data as a POCO view model. The function should return the view model data to the HTTP response as JSON.

Actual behavior

The Azure Functions runtime host throws an exception when invoking the custom assembly code, as it tries to find the Microsoft.SharePoint.Client.dll. It is not loaded into process, and it cannot find the assembly to load it.

Known workarounds

Instead of referencing the nuget package from the function's project.json file, we need to download the nuget package locally, then extract the package's DLLs and include them in the wwwrootsharedbin folder along with the custom assembly, in order for all assemblies to be loaded by the process.

Related information

Gist containing all related files for repro:
Gist

question

All 7 comments

another side-effect we identified while discussing this issue is that when the custom assembly is deployed to the function's bin folder, instead of a higher level sharedbin folder, it could not deserialize and load the collection of SharePoint Taxonomy Term objects - it resulted in a collection of null objects (though of the correct count of items). As @fabiocav mentioned on the linked StackOverflow thread, it may have something to do with the load context of the private assemblies within a function bin, vs. when the assembly is loaded from the higher level sharedbin folder.

@tafs7 finally had a chance to look at one aspect of this issue today and and I did mislead you a bit in some of the previous comments. The shared assemblies behavior in regards to nuget package references is indeed by design. With that model, you'd need to deploy the output of your project (the compilation output, including dependencies) as the shared scope also means they apply to multiple function contexts and not a single one (which is how package references are scoped).

This would work as you expect with private assemblies, as they can and will load package reference dependencies, but that seemed to cause the original issue you had (still open).

An alternative is to create a NuGet package for your custom reference and define its package dependencies there. This leads to a cleaner approach in the shared model as you don't have to specify those dependencies in each function and they're ultimately managed where they belong, where they're needed.
The runtime will restore the entire dependency graph and add the appropriate references. Would this option work for you?

@fabiocav Thanks for looking into this further and clarifying. As of now, I've got it working with the output of my project (custom dll and nuget DLLs) deployed to the shared bin folder.

When you mention that I should create a nuget package, do you mean that I should create the nuspec, etc., and then deploy it publicly, so that it can be pulled from the functions runtime? If so, I'm not sure I'd want to do that, since we're building internal solutions for our corporate portal. If not, please help me understand your suggestion. Thanks!

I didn't get into the details, but no; the usual recommendation is to either use a private (and authenticated, if desired) package repository or deploy the package to the file system and set either of those options as a custom package source using Nuget.config

@fabiocav If I use a private nuget repo, or file system on my corporate net, how will the cloud runtime restore those nuget packages? Pardon my ignorance, if I am missing something, but I thought the functions runtime would only be able to access resources on the public web, so a private nuget feed would not be accessible to it, correct?

Also, would I need to have create a packages.json file at the parent wwwroot folder, above my functions (same level as the shared bin folder) to enable package restore for shared assemblies?

@tafs7 apologies for the delay on this. Missed some notifications and this fell off the radar.

Yes, for the runtime to be able to restore the packages, the package source/repository does need to be at least accessible. They could be authenticated and managed using the standard nuget.config mechanism.

A wwwroot project.json would not be used in the shared assemblies scenario. As mentioned above, that model does expect dependencies to be deployed with the assemblies (similar to how you'd deploy a standard app.)

Was this page helpful?
0 / 5 - 0 ratings