4
votes

I have an Azure Function App with a function that runs on a blob trigger. I've proven that this function can run through the Azure Portal and responds to this blob trigger without issues... or at least it did.

Now that I've added functionality which makes use of EF Core (2.2.4), it gives me the following error, both when debugging locally and when publishing to Azure:

Microsoft.Azure.WebJobs.Host: Error indexing method 'ParseThings'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'context' to type AvastusContext. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

I have a Startup class as instructed by Azure Function App documentation here, and have followed their example to the letter, aside from the following line in place of their configured example services:

[assembly: FunctionsStartup(typeof(AvstFunctionApp.Startup))]

namespace AvstFunctionApp
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddDbContext<AvastusContext>(options => options.UseSqlServer(Environment.GetEnvironmentVariable("AvastusDb")));
        }
    }
}

And the beginning of my function:

public static class ParseThings
{
    [FunctionName("ParseThings")]
    public static void Run([BlobTrigger("summaries/{name}", Connection = "StorageConnectionString")]Stream myBlob, string name, ILogger log, AvastusContext context)

I can confirm that the AddDbContext line is getting hit in a debugger, so presumably there's some bug happening behind the scenes here, or I'm doing something incredibly silly.

Things I've tried that haven't worked include:

  • Adding .BuildServiceProvider(true) to the AddDbContext line
  • Using WebJobsStartup instead of the more recently advertised FunctionsStartup
  • Downgrading to .NET Core 2.2.0
  • Changing the Function class and Run method from static to instance
  • Fixing incorrect namespace of the injected AvastusContext

It's also worth noting that there are two other functions in this Function App project which don't seem to have any serious issues, and I've been able to get dependency injection working using a similar method with EF Core for another (ASP.NET Core MVC) project in this solution.

Thank you in advance for any help anyone can provide!

P.S. I find it incredibly weird that there hasn't been anything describing this situation with the later versions of .NET Core, Azure Function Apps, and EF Core on the interwebs, which leads me to believe that this might be a simple mistake. Hopefully not.

2
I've struggled with this myself today. Try making the ParseThings class non-static and injecting the context into a constructor instead of the method. I got it working that way. I'm new to Azure functions though, so I don't know if the class needs to be static for any reason when deployed to Azure, but it works locally for me.Matthew Sawrey
Thanks for the suggestion. Unfortunately, changing a Function class to an instance class instead of a static one, adding a constructor with dependency-injected parameters, and changing the Run method to an instance method from a static one did not fix the problem. I can confirm that an ILogger<> instance was not complained about, while the AvastusContext threw an InvalidOperationException for lack of resolving.phantomraa
Perhaps the line where you add the DbContext should be moved above the line where you add azure functions? I'm just guessing here, but if they build the serviceprovider before you added the DbContext, that could be a problem.Jesse de Wit
Thanks for that, Jesse. Unfortunately, the pattern dictated by Functions exposes the IFunctionsHostBuilder in an overriden Configure method, so I don't explicitly build anything as that's handled by the FunctionsStartup class. I'll update my first code block in my question to show you the lines surrounding AddDbContext.phantomraa

2 Answers

0
votes

perhaps one solution can be you can try injecting IServiceProvider in your function instead of AvastusContext like I have injected in the repository class below:

private readonly IServiceProvider serviceProvider;

        public SomeRepository(IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
        }
    
        using var context = this.serviceProvider.GetService<XYZDBContext>(); 

This will provide a context object to you. Also, Not sure why you are trying to access context in the function directly for good practice have a context class defined, and maintain repository to do any CRUD operation in the code.

Startup.cs you can add extra configurations like :

builder.Services.AddDbContext<XYZDBContext>(
            options =>
            {
                options.UseSqlServer(
                    conn,
                    sqlServerOptionsAction:
                    sqlOptions =>
                    {
                        sqlOptions.EnableRetryOnFailure(maxRetryCount: 3, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
                    });
            }, ServiceLifetime.Transient);

this configuration works perfectly fine in my current solution. Try this out.

0
votes

Function app can't resolve dbcontext in functions as it can only resolve BindingContext. You need to create custom bindings to use dbcontext directly in function app.

Other way to get dbcontext injected via DI is to pass it to constructor and using a class level variable in the function.

public class ParseThings
{
    private AvastusContext _context;
    public ParseThings(AvastusContext context){
        _context = context;
    }

    [FunctionName("ParseThings")]
    public void Run([BlobTrigger("summaries/{name}", Connection = "StorageConnectionString")]Stream myBlob, string name, ILogger log){
      // use _context here
    }
}

If it still doesn't resolve you might want to look it into whether the functionsStartup is configured properly