Azure / azure-webjobs-sdk

Azure WebJobs SDK
MIT License
733 stars 355 forks source link

FileNotFoundException when compiling a Function (v2) referencing a (local) custom binding #1633

Open brandonh-msft opened 6 years ago

brandonh-msft commented 6 years ago

I've created a local custom binding in a separate .Net Standard 2.0 assembly. This binding exposes & implements all the necessary types & interfaces. However, when I build my Functions v2 project which uses the binding in the Function signature (via an Attribute), the build system errors out with a FileNotFoundException which doesn't make sense. If I remove merely the usage of the binding (not the reference to its containing lib), build works fine

Repro steps

Provide the steps required to reproduce the problem

  1. Create a new solution
  2. Add a .Net Standard 2.0 class library project and implement a new custom output binding
  3. Add a Functions v2 HttpTrigger project and use the output binding in the signature of the generated Function1 class
  4. Build the solution

Expected behavior

The custom binding and consuming Function build successfully and my binding is used by the Function.

Actual behavior

The build system errors out with the following message:

Severity    Code    Description Project File    Line    Suppression State
Error       System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Azure.WebJobs, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
File name: 'Microsoft.Azure.WebJobs, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
   at System.ModuleHandle.ResolveType(RuntimeModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
   at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
   at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
   at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(CustomAttributeRecord caRecord, MetadataImport scope, Assembly& lastAptcaOkAssembly, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, Object[] attributes, IList derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctor, Boolean& ctorHasParameters, Boolean& isVarArg)
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes, Boolean isDecoratedTargetSecurityTransparent)
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeType type, RuntimeType caType, Boolean inherit)
   at System.Attribute.InternalGetAttributeUsage(Type type)
   at System.Attribute.InternalParamGetCustomAttributes(ParameterInfo param, Type type, Boolean inherit)
   at MakeFunctionJson.ParameterInfoExtensions.GetDisabledAttribute(ParameterInfo parameterInfo)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at MakeFunctionJson.MethodInfoExtensions.GetDisabled(MethodInfo method)
   at MakeFunctionJson.MethodInfoExtensions.HasUnsuportedAttributes(MethodInfo method, String& error)
   at MakeFunctionJson.FunctionJsonConverter.<GenerateFunctions>d__9.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at MakeFunctionJson.FunctionJsonConverter.TryGenerateFunctionJsons()
   at MakeFunctionJson.FunctionJsonConverter.TryRun()

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

Error generating functions metadata
    TestFunction    C:\Users\...\.nuget\packages\microsoft.net.sdk.functions\1.0.9\build\netstandard1.0\Microsoft.NET.Sdk.Functions.Build.targets   39  

Known workarounds

None

Related information

brandonh-msft commented 6 years ago

I forked @lindydonna's SlackBinding repo, added v2 binding and functions projects to it, and reproduced the error. The v1 portions of her repo do not error out at all. This, also, was curious to me since in the Wiki we say the following:

To author a custom binding for Azure Functions, you must use the 2.0 runtime. See Azure Functions 2.0 support.

¯\_(ツ)_/¯

brandonh-msft commented 6 years ago

TL;DR: our nuget packages need some love. Recommend version syncing across NetFX and NetStandard + not locking (=) to specific versions of dependencies, especially Newtonsoft.JSON

Ok I got this working but boy did it require some sleuthing & hacking. It really shows the issues we've got today with our nuget packages...

Bottom line, you can't use a .Net Standard implementation of a Binding across both Functions v1 and Functions v2 (:sad panda:) The issues show up when you look at the dependencies for Microsoft.NET.Sdk.Functions (v1.0.9) and see this: image

Where across NetFX and NetCore we're not only referencing different versions of the same packages, but locking to versions (= vs >=). Then, when you create a new .Net Standard lib, and use Type Resolution to automatically pull in Microsoft.Azure.Webjobs for the types needed to create a binding, you get the stable versions which means v2.1.0 and its dependencies which look like: image

So now you've got a mismatch on Webjobs & Webjobs.Core between your Function app and the Binding library.

If you manually bump your Webjobs SDK version to the 3.0.0-beta4 used by the .Net Standard Functions SDK, you'll be good for a .Net Standard-based binding. However, that won't work for your NetFX-based binding, because it needs Webjobs 2.1.0 locked (nothing greater) so you'll have to make a separate lib for your NetFX binding for the sole purpose of having the right references - nothing else.

To boot, after you solve this problem, you're left dealing with the issue of the Host vs the Nupkg and have to do the project gymnastics outlined here.

paulbatum commented 6 years ago

@brandonh-msft since you got things working, would it make sense to move your observations on nuget versions into a separate issue, since this one is about creating and using a custom binding?

irensaltali commented 5 years ago

Following SDK's versions are compatible with each other: Microsoft.Azure.WebJobs (2.1.0) Microsoft.NET.Sdk.Functions (1.0.11) Newtonsoft.Json (9.0.1)

paulbatum commented 5 years ago

I would recommend folks use the more recent versions:

Microsoft.Azure.WebJobs (2.2.0) Microsoft.NET.Sdk.Functions (1.0.21) Newtonsoft.Json (9.0.1)

CoenraadS commented 5 years ago

I just experienced this also with

<PackageReference Include="Microsoft.Azure.WebJobs.ServiceBus" Version="2.3.0" />
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.26" />

I had to use Webjobs.ServiceBus 2.2.0 to resolve it.

The strange this is in some projects the above combination does work..