Newtonsoft.Json reference complaining on Azure Functions

8

I'm running an Azure Functions, called SmsWebhook. It calls a method in an external assembly, AzureFunctionsSample.Services.dll that has a reference to Newtonsoft.Json 8.0.3

The details of my Run.csx looks like:

#r "AzureFunctionsSample.Services.dll"
using System.Net;
using AzureFunctionsSample.Services

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    ...
}

Within the Run() method above, I create an instance and call a method in the instance. However, whenever I call that method, I receive the following error:

2016-05-19T13:41:45  Welcome, you are now connected to log-streaming service.
2016-05-19T13:41:46.878 Function started (Id=64fccf0c-d0ef-45ef-ac1c-7736adc94566)
2016-05-19T13:41:46.878 C# HTTP trigger function processed a request. RequestUri=https://ase-dev-fn-demo.azurewebsites.net/api/smswebhook
2016-05-19T13:41:46.878 Function completed (Failure, Id=64fccf0c-d0ef-45ef-ac1c-7736adc94566)
2016-05-19T13:41:46.894 Exception while executing function: Functions.SmsWebhook. Microsoft.Azure.WebJobs.Script: One or more errors occurred. AzureFunctionsSample.Services: Could not load file or assembly 'Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040).

I manually added the same version of Newtonsoft.Json.dll under the bin directory, but still got the same error. Why is it complaining at the Newtonsoft.Json.dll file?

If I move all the logics within the external assembly into the Run.csx, it won't complain, by the way.

c#
azure
azure-functions
asked on Stack Overflow May 19, 2016 by JustInChronicles • edited Dec 8, 2018 by Thomas

3 Answers

17

Json.Net can be simply reference adding this line at the top of your Run.csx file :

#r "Newtonsoft.Json"

See this article if you want to know which assemblies are automatically added by the Azure Functions hosting environment:

Otherwise, if you want to use a specific version of Json.Net, you should probably add a reference to Json.Net using nuget package:

So you need to add a Project.json file that look like this:

{
  "frameworks": {
    "net46":{
      "dependencies": {
        "Newtonsoft.Json": "8.0.3"
      }
    }
   }
}

If your external dependency references Newtonsoft.Json without using a nuget package, you can have a look at this post that explains how to upload your binaries:

answered on Stack Overflow May 19, 2016 by Thomas • edited May 23, 2017 by Community
5

@JustInChronicles, I'm adding this here as an answer for reference, but the expected behavior should be that indirect dependencies of private assemblies are resolved from your bin folder, as expected.

I put together the following test to reproduce your scenario:

  • Created a simple class library with a simple type that uses Json.NET to serialize an object and return the JSON string. This assembly references Json.NET 8.0.3. The result includes the Json.NET assembly version it is using
  • Created a function that references that type only with a #r "DependencyWithJsonRef.dll" and returns the result produced by the method mentioned above
  • Deployed DependencyWithJsonRef.dll and Newtonsoft.Json.dll (8.0.3) to my function's bin folder

Invoking the function produces the expected result.

Here is the function, for reference:

#r "DependencyWithJsonRef.dll"

using System.Net;

public static string Run(HttpRequestMessage req, TraceWriter log)
{
    var myType = new DependencyWithJsonRef.TestType();
    return myType.GetFromJson();
}

As you can see, no explicit reference to indirect dependencies (Json.NET) required.

This is the output I get:

{
    "Prop1":"Test",
    "Prop2":1,
    "AssemblyName": "Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed"
}

Quick note: One thing you may want to check, particularly if you've updated that dependency while developing your function is that assembly resultion results were not cached. A sure way to make sure you're starting with a clean slate is to (after you deploy your function and assemblies) go to Kudu and kill the non-scm w3wp process to see if that helps. I'd be curious to know if that does the trick as there are a few things we can to to improve this if it does.

answered on Stack Overflow May 20, 2016 by Fabio Cavalcante
2

After some trial-and-error approach. I found what the issue was here.

@FabioCavalcante gave me a hint using a file-based reference,

#r "Newtonsoft.Json.dll"

It didn't work actually. I've copied those four files to Azure Functions' bin directory:

  • AzureFunctionsSample.Services.dll
  • AzureFunctionsSample.Services.pdb
  • Newtonsoft.Json.dll
  • Newtonsoft.Json.xml

It still gave me the same error, even though I did the file-based reference. Then, I found another file, AzureFunctionsSample.Services.dll.config that actually defines assembly binding redirects like:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

After I copied this config file to the Azure Functions' bin directory, it worked!


Lessons Learnt

  • Use the file-based reference for Newtonsoft.Json, #r "Newtonsoft.Json.dll", if your external assembly also has a reference to it.
  • Make sure that the assembly binding redirect configuration exists in Azure Functions' bin directory.

Correct me, if I'm still wrong.

Cheers,

answered on Stack Overflow May 20, 2016 by JustInChronicles

User contributions licensed under CC BY-SA 3.0