Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Newtonsoft.Json reference complaining on Azure Functions

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.

like image 772
justinyoo Avatar asked May 19 '16 22:05

justinyoo


3 Answers

@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.

like image 92
Fabio Cavalcante Avatar answered Nov 08 '22 07:11

Fabio Cavalcante


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:

  • Azure Functions C# developer reference

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

  • How can I use NuGet packages in my Azure Functions?

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:

  • How do I use external assemblies with Microsoft Azure Function Apps?
like image 19
Thomas Avatar answered Nov 08 '22 06:11

Thomas


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,

like image 2
justinyoo Avatar answered Nov 08 '22 06:11

justinyoo