locked
Unexplained behavior when reference library changes - Method not found RRS feed

  • General discussion

  • This is related to 

    https://social.msdn.microsoft.com/Forums/azure/en-US/b04440c9-9233-4558-bf54-136b000c0464/code-changes-seems-to-be-not-applied-on-the-run?forum=AzureFunctions

    The error I am receiving is

    2016-06-16T02:07:05.927 Exception while executing function: Functions.GetUserDetails. mscorlib: Exception has been thrown by the target of an invocation. ƒ-GetUserDetails#ℛ*a5b873d3-e5f5-419d-95c3-8992a7946ce3#17-0: Method not found: 'xxxxx.Common.IdentityService.Models.xxxxxUser xxxxx.Common.IdentityService.Core.AuthenticationService.GetUserDetails(System.String)'.

    My solution original was composed of one referenced class library: xxxxx.Common.IdentityService.Core.  This was deployed and referenced in the function app without an issue.  The library was then refactored where the models were moved to a referenced class library: xxxxx.Common.IdentityService.Models.  

    The project was then updated (the original library was deleted and the two new libraries were uploaded using an ftp client).

    Now the project fails at runtime with the strange error which appears that the host is trying to resolve the method in the wrong library.

    I have tried re-ordering my #r statements.  No luck.  I also tried to create a new function within the same resource and the same error happens.

    Now for the interesting part.  In a different subscription I created a new function app and uploaded the same libraries with the same .csx file and the function works correctly without error!

    So is there a way to kick the Function App host in the guts and get it to "re-map" or whatever magic it is doing under the hood?

    Here is my .csx:

    #r "xxxxx.Common.IdentityService.Models.dll"
    #r "xxxxx.Common.IdentityService.Core.dll"
    using System;
    using System.Configuration;
    using System.IO;
    using System.Net;
    using System.Text;
    using xxxxx.Common.IdentityService.Core;
    using xxxxx.Common.IdentityService.Core.CRM;

    public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
    {
        // parse query parameter
        string username = req.GetQueryNameValuePairs()
            .FirstOrDefault(q => string.Compare(q.Key, "username", true) == 0)
            .Value;

        // Get request body
        dynamic data = await req.Content.ReadAsAsync<object>();

        // Set name to query string or body data
        username = username ?? data?.username;

        var authService = new AuthenticationService();
        var details = authService.GetUserDetails(username);

        return details == null
            ? req.CreateResponse(HttpStatusCode.NotFound, details)
            : req.CreateResponse(HttpStatusCode.OK, details);
    }

    Jeff

    Thursday, June 16, 2016 9:46 PM

All replies

  • Jeff,

    Thanks for opening this!

    This is an interesting one and there's some additional information we can look for to try to get to the bottom of this.

    First, a couple of questions:

    1. Do you have any other functions in the same Function App using the previous version of the assembly?
    2. Did you bump the assembly version when you refactored your code?

    Could you add the following to the function so we can get more details about the loaded assembly:

    log.Info($"Core assembly full name: {typeof(AuthenticationService).Assembly.FullName}");
    
    log.Info($"Core assembly location: {typeof(AuthenticationService).Assembly.CodeBase}");
    
    log.Info($"Models assembly full name: {typeof(xxxxUser).Assembly.FullName}");
    
    log.Info($"Models assembly location: {typeof(xxxxUser).Assembly.CodeBase}");
    

    Thanks,

    -Fabio

    Thursday, June 16, 2016 10:22 PM
  • Hello Fabio,

    You probably found the issue with your first question.  There are multiple functions defined and both use the library.  Because the bin is local to each functions directory, I create a copy of the libraries in each bin.

    Is there a better approach?  Can I create a bin folder at the same level as the functions' folders and only put a single copy of the library there?

    And, I did not update the assembly version.


    Jeff

    Thursday, June 16, 2016 10:39 PM
  • We do support relative references, so you could have a folder at the functions root folder and add the reference pointing to that location:

    #r "..\sharedassembliesfolder\assembly.dll"

    -Fabio

    Thursday, June 16, 2016 11:05 PM
  • Thanks Fabio.

    I will do some testing around this to fully understand but can you confirm my understanding.  It sounds like each function defined in a resource is not isolated so care needs to be taken.  I am guessing it is not advisable to have multiple versions of shared packages or other resources.  For example, two different version of the same nuget package.

    How does the resource behave then with nuget packages?  are all libraries downloaded to a hidden shared location?


    Jeff

    Thursday, June 16, 2016 11:11 PM
  • You're correct as there isn't a lot of isolation between functions. They're currently loaded within the same process and app domain and although multiple versions are not generally a problem, as we'll load multiple versions side-by-side, you do need to exercise care and issues will come up if you have multiple versions (meaning different binaries) that have the same assembly name and version. Bumping the assembly version in those cases addresses the problem, but in most cases, having a shared location for those common assemblies is the easier way to manage them.

    -Fabio


    Thursday, June 16, 2016 11:15 PM
  • Brilliant.  Thanks Fabio.  Much appreciated.

    Hope you don't mind but I posted this exchange on the Azure Dev Community as I think it is really helpful and insightful into how Azure Functions were put together.

    Cheers, Jeff


    Jeff

    Friday, June 17, 2016 12:24 AM