Skip to content
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

Dependency Injection in Azure Functions causing Object reference error #1440

Open
DarrenWainwright opened this issue Mar 19, 2021 · 3 comments

Comments

@DarrenWainwright
Copy link

Describe the bug
Trying to use FluentMigrator in an Azure Functions v3 app, and implementing with Dependency Injection. Database being used against is Postgre.

Experiencing an 'Object reference not set to an instance of an object' when trying to inject IMigrationRunner, or trying to access it in the IServiceProvider.

To Reproduce
Followed the steps on the projects quick start. Snippets of the important code are here:

Startup.cs:

// builder is an instance of IFunctionsHostBuilder
builder.Services.AddFluentMigratorCore()
                            .ConfigureRunner(runner => runner
                                .AddPostgres()
                                .WithGlobalConnectionString("xx")
                                .ScanIn(Assembly.GetExecutingAssembly()).For.Migrations()      
                            )
                            .AddLogging(log => log.AddFluentMigratorConsole())
                            .BuildServiceProvider(false); //Tried with this commented out too

DbMigrations file - attempt 1:

this one will not run at all - IMigrationRunner is null, so DI can't spin it up

public class DatabaseMigrations : IDatabaseMigrations
   {
       private ILogger<DatabaseMigrations> logger;
       private readonly IMigrationRunner runner;

       /// <summary>
       /// Database migrations implementation
       /// </summary>
       /// <param name="logger"></param>
       public DatabaseMigrations(ILogger<DatabaseMigrations> logger, IMigrationRunner runner)
       {
           this.logger = logger;
           this.runner = runner;
       }

       public void Up()
       {
           runner.MigrateUp();
       }
   }

Attempt 2:

This one fails trying to grab the required service, same error:

public class DatabaseMigrations : IDatabaseMigrations
    {
       private ILogger<DatabaseMigrations> logger;        
        private readonly IServiceProvider serviceProvider;
        private readonly IMigrationRunner runner;

        /// <summary>
        /// Database migrations implementation
        /// </summary>
        /// <param name="logger"></param>
        public DatabaseMigrations(ILogger<DatabaseMigrations> logger, IServiceProvider serviceProvider)
        {
            this.serviceProvider = serviceProvider;
            this.logger = logger;
            this.runner = serviceProvider.GetRequiredService<IMigrationRunner>();            
        }
     
        public void Up()
        {
              runner.MigrateUp(); 
        }
    }

Expected behavior
Expected IMigrationRunner to exist and be able to call .Up()

Information (please complete the following information):

  • OS: Mac OS
  • Platform Dotnet core 3.1 for Azure functions v3 (also have dotnet 5 installed)
  • Installed packages:
    -- FluentMigrator v3.2.15
    -- FluentMigrator.Runner v 3.2.15
    -- FluentMigrator.Runner.Postgre v3.2.15 (tried with and without this installed)
    -- FluentMigrator.Runner.Core v3.2.15 (tried with and without this installed)
  • Database - Postgres
@jzabroski
Copy link
Collaborator

jzabroski commented Mar 19, 2021

I hate Azure Functions so much. I've never once seen a project say, "Worked the first time." I don't know what to tell you, other than I have lost my desire to continue troubleshooting Azure Functions. I dealt with a bunch of bugs in RazorLight, too - that had nothing to do with RazorLight, but rather how poorly Azure Functions supports modular coding. I gave them feedback awhile ago and they downvoted my comments. So I pretty much peaced out after that interaction.

I guess I'd prefer to discuss, how does one integration test Azure Functions? Is it even testable? As in, testable without running func.exe and all its machinary.

I don't use Azure - I use AWS and AWS Lambda supports deploying an EXE in a docker container. Seems a lot simpler and more maintainble to me, as you get more control over when your application upgrades anything in its dependency graph. Plus it eliminates one more variable, which is the Azure Functions SDK is a separate SDK from the core .NET SDK. I just don't get it. FluentMigrator doesn't create a FluentMigrator SDK with a bunch of deployment logic tucked away in MSBuild targets.

@jzabroski
Copy link
Collaborator

jzabroski commented Mar 19, 2021

The problem you're probably running into is the stupid default behavior of Azure Functions SDK. By default, the SDK optimizes away your dependency tree if there are no symbol references in your project to a referenced dll. So you should probably start by seeing if your deploy directory has the right FluentMigrator dlls. I know, it's crazy. This was one of the feedback items I gave them they downvoted.

One workaround is to disable the default behavior. Another is to create an Assembly-level attribute to reference any type in the concrete Runner class.

Otherwise, in my opinion, the only way Azure FUnctions gets better is if they get more and more support requests until they realize their product is simply not good enough.

Sorry for the rant.

@DevelopmentLeadRR
Copy link

Hi @jzabroski & @DarrenWainwright,

I've just encountered exactly the same problem. Is there any update, or have you ever managed to make it work?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants