-
Notifications
You must be signed in to change notification settings - Fork 450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Azure Functions Host appears to be looking for dll's that don't exist #5796
Comments
Ok i've managed to pin it down to a way smaller sample of code. Install the .Net Core SDK v3.1 from the current download location on top of VS 2019. ... I think this may happen with other stuff too since the project in my main solutoin isn't particularly complex. but anyway I opened up the project file and replaced the reference from 3.0 to 3.1 (since for some reason the default was 3.0) ... <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
<LangVersion>latest</LangVersion>
</PropertyGroup> ... adding the langversion node is something of a default for me too lately (apparently VS is happier in general when I do this. I then updated the program.cs file to this ... using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace FunctionApp1
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
var result = await new ScriptRunner().Run<string>("\"Hello \" + Name", new[] { "System" }, new Args { Name = name });
return name != null
? (ActionResult)new OkObjectResult(result)
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
public class Args
{
public string Name { get; set; }
}
internal class ScriptRunner
{
internal static Assembly[] references;
static ScriptRunner()
{
// some of the stack might not have been loaded, lets make sure we load everything so we can give a complete response
// first grab what's loaded
var loadedAlready = AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => !a.IsDynamic)
.ToList();
// then grab the bin directory
var binDir = Assembly.GetExecutingAssembly().CodeBase
.Replace(Assembly.GetExecutingAssembly().CodeBase.Split('/').Last(), "")
.Replace("file:///", "")
.Replace("/", "\\");
// from the bin, grab our core dll files
var stackDlls = Directory.GetFiles(binDir)
.Select(i => i.ToLowerInvariant())
.Where(f => f.EndsWith("dll"))
.ToList();
// load the missing ones
var stackPaths = stackDlls.Where(assemblyPath => loadedAlready.All(a => a.CodeBase.ToLowerInvariant() != assemblyPath.ToLowerInvariant()));
foreach (var assemblyPath in stackPaths)
loadedAlready.Add(Assembly.LoadFile(assemblyPath));
references = loadedAlready.ToArray();
}
public async Task<T> Run<T>(string code, string[] imports, object args)
{
try
{
var referencesNeeded = references.Where(r => r.GetExportedTypes().Any(t => imports.Contains(t.Namespace)));
var options = ScriptOptions.Default
.AddReferences(referencesNeeded)
.WithImports(imports);
return await CSharpScript.EvaluateAsync<T>(code, options, args, args.GetType());
}
catch (NullReferenceException ex)
{
var typeAndCall = $"(({ex.TargetSite.DeclaringType.Name})object).{ex.TargetSite.Name}";
var data = new List<string>();
foreach (var k in ex.Data.Keys) data.Add($"{k}: {ex.Data[k]}");
throw new Exception(ex.Message + $"\nContext: {ex.Source}\nTarget: {typeAndCall}\n{string.Join("\n", data)}");
}
catch (CompilationErrorException ex)
{
throw new Exception($"Compilation failed:\n{ex.Message}\n{string.Join(Environment.NewLine, ex.Diagnostics)}");
}
}
public Task Run(string code, string[] imports, object args) => Run<bool>(code + ";return true;", imports, args);
}
} ... build and run this.
... looking in the build output folder I can see ... |
Yeh ok it definitely appears to be a functions framework host issue, here's the same code in a console app that works ... using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace WorkflowConsole
{
class Program
{
static void Main(string[] args)
{
var name = args[0];
var result = new ScriptRunner().Run<string>("\"Hello \" + Name", new[] { "System" }, new Args { Name = name }).Result;
Console.WriteLine(
name != null
? result
: "Please pass a name on the query string or in the request body"
);
_ = Console.ReadKey();
}
}
public class Args
{
public string Name { get; set; }
}
public class ScriptRunner
{
internal static Assembly[] references;
static ScriptRunner()
{
// some of the stack might not have been loaded, lets make sure we load everything so we can give a complete response
// first grab what's loaded
var loadedAlready = AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => !a.IsDynamic)
.ToList();
// then grab the bin directory
var binDir = Assembly.GetExecutingAssembly().CodeBase
.Replace(Assembly.GetExecutingAssembly().CodeBase.Split('/').Last(), "")
.Replace("file:///", "")
.Replace("/", "\\");
// from the bin, grab our core dll files
var stackDlls = Directory.GetFiles(binDir)
.Select(i => i.ToLowerInvariant())
.Where(f => f.EndsWith("dll"))
.ToList();
// load the missing ones
var stackPaths = stackDlls.Where(assemblyPath => loadedAlready.All(a => a.CodeBase.ToLowerInvariant() != assemblyPath.ToLowerInvariant()));
foreach (var assemblyPath in stackPaths)
loadedAlready.Add(Assembly.LoadFile(assemblyPath));
references = loadedAlready.ToArray();
}
public async Task<T> Run<T>(string code, string[] imports, object args)
{
try
{
var referencesNeeded = references.Where(r => r.GetExportedTypes().Any(t => imports.Contains(t.Namespace)));
var options = ScriptOptions.Default
.AddReferences(referencesNeeded)
.WithImports(imports);
return await CSharpScript.EvaluateAsync<T>(code, options, args, args.GetType());
}
catch (NullReferenceException ex)
{
var typeAndCall = $"(({ex.TargetSite.DeclaringType.Name})object).{ex.TargetSite.Name}";
var data = new List<string>();
foreach (var k in ex.Data.Keys) data.Add($"{k}: {ex.Data[k]}");
throw new Exception(ex.Message + $"\nContext: {ex.Source}\nTarget: {typeAndCall}\n{string.Join("\n", data)}");
}
catch (CompilationErrorException ex)
{
throw new Exception($"Compilation failed:\n{ex.Message}\n{string.Join(Environment.NewLine, ex.Diagnostics)}");
}
}
public Task Run(string code, string[] imports, object args) => Run<bool>(code + ";return true;", imports, args);
}
} |
Got this issue too What i did simply updating these dll
from
Doing a rollback now and see if the issue is gone |
it works again after rolling back, i think Microsoft.NET.Sdk.Functions somewhere between 3.03 - 3.0.6 is broken |
Same issue after upgrading the Functions SDK beyond 3.0.2. Rolling back to 3.0.2 allows the Functions app to run properly again. |
I confirm the same. I've bumped into this issue while using version 3.0.9 of Microsoft.NET.Sdk.Functions. Changing to 3.0.2 get's it fixed. Wondering when or if it will be fixed. |
Its important which version you have referenced in csproj. For this, please have a look on tools folder from azure-functions-core-tools-3 (somewhere on your drive) [System.Diagnostics.FileVersionInfo]::GetVersionInfo("Microsoft.CodeAnalysis.dll") after that reference in your csproj expected version And module gets referenced in runtime. used this with codedom and cs-script (csscript for function app) ping for @alrod to update tags. |
@TehWardy the files you see in your bin / obj directories are not the dll which will be used in runtime binding. Azure function host decide on their own half based on version, and may override out-of-the-box libraries. Thats why this is happening, you version is being replaced by azure function host. |
General .Net etiquette If I'm dependent on an assembly directly then I should be able to deploy that assembly with my application code and force usage of that particular version. The complications as I see them Forcing me to use specific versions of assemblies is against everything .Net is built on. That said, as per that same issue I ended up over on dotnet/aspnetcore#25305 which highlighted that some packages may not report their dependencies correctly further complicating the process. Clearly there's a lot of different things at play here but my understanding from "general advice" I receive on most tickets is that to resolve any reference issues directly reference the version of the problem assembly directly in my project and the build process should honour that. So @DenisBalan: the bottom line We presumably need some way that we as consumers of the Azure functions framework can reliably control or derive the versions needed explicitly by the framework to enforce the same versioning constraints on our deployments? Or am I missing something here? |
@TehWardy this is. The whole process of building function involves a lot of msbuild target files, where, if you want, you could replace libraries that came out of the box with your own ones, but there is no compatibility guarantee. There is a lot to say on what should and should not allow the host to do, but starting from the point that there is a way to deal with those issues, you just have to comply with those. IMHO. |
I'm not sure how that helps / what you're trying to say exactly but my take from it is ... In some cases like my SignalR case above I can clearly do everything right and still not have it all work.
In addition to that you're saying the rules that Azure Functions adds are something like ...
I'm simply asking if there's a means to allow for some ability to "manually resolve" or "advise" azure functions that I "prefer" a given version of something because other parts of .Net "require" that version (which I also have no control over). I've been told in other tickets that all .Net Core 3.x assemblies that are part of the Microsoft ecosystem should be compatible. I don't see how I'm breaking any rules here by trying to force consistency in my assembly stack when some of it isn't correctly linked on your (Microsofts) end. I also hit issues like:
If Microsoft wants to have a framework dependency "recommendation" based on what is known to be tested and working or a "minimum version" requirement that's fine with me. My reasoning is simple Alternative suggestion |
Ping ... to prevent bot closes¬ |
This is still a problem in Microsoft.NET.Sdk.Functions 3.0.11 Microsoft.CodeAnalysis 3.8.0 works with Microsoft.NET.Sdk.Functions 3.0.2 The problem: 'Could not load file or assembly 'Microsoft.CodeAnalysis, Version=3.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Can be resolved in Azure Functions by referencing: Microsoft.NET.Sdk.Functions 3.0.2 instead of 3.0.>=3 Code to demo problem, this will work in Functions 3.0.2 but fail between 3.0.3 to 3.0.11, latest at time of writing:
|
Hi @TehWardy , Can we know if you are seeing this issue still and requires further follow up. |
I no longer have this issue but there is something still about this i'm not confident is "quite right" ... I think this got passed around ... I never really got an answer to it other than "there's some stuff you just can't do in Azure Functions when it comes to the reflection API's". I think the real underlying issue here is dependency graphing across Microsoft's teams is inconsistent because Microsoft's reference policies are quite strict regarding versioning (in places) and very relaxed in others. I find the biggest issues with this is when a project is migrated from a given .Net version to the next, the dependency tree isn't properly recomputed and VS does a decent job compared to something like VS Code of tryign to keep it all together but the net result that is that I was told "explicitly specify the version when you can", which doesn't work on dependencies of dependencies (the root cause of this issue). |
I initially hit this dotnet/core#4390 which in turn led me to dotnet/roslyn#42445 because i noticed this only happened in my functions project and not the rest of my stack.
The roslyn guys have suggested "quote" ...
... so here I am.
Any help with this would be really appreciated as I have an urgent need to get a deployment through for an important project.
The text was updated successfully, but these errors were encountered: