Search code examples
c#mysqlazureazure-functionsazure-mysql-database

Using MySqlDatabase (MySql.Data.MySqlClient) on Azure Functions v2 - "Unable to resolve service"


I have created an Azure Functions app ~v2 project that uses the MySql.Data.MySqlClient dependency.

The project is setup to also use the SwashBuckle library to create a callable API.

When I execute my project from my local settings, it works fine. Yet, when I publish the Functions app to our Azure server and try testing the function there, I get this error:

System.InvalidOperationException : Unable to resolve service for type 'MyFunctionApp.MySqlDatabase' while attempting to activate 'MyFunctionApp.PostsService'.

at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp,Type type,Type requiredBy,Boolean isDefaultParameterRequired)

...

My StartUp.cs:

using System;
using System.Reflection;
using AzureFunctions.Extensions.Swashbuckle;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Hosting;
using Microsoft.Extensions.DependencyInjection;
using MyFunctionApp;

[assembly: WebJobsStartup(typeof(SwashBuckleStartup))]
namespace MyFunctionApp
{
    internal class SwashBuckleStartup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {
            ConfigureServices(builder.Services);
            builder.AddSwashBuckle(Assembly.GetExecutingAssembly());
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<MySqlDatabase>(_ => new MySqlDatabase(Environment.GetEnvironmentVariable("MyFunctionApp-DbConn")));
        }
    }
}

My MySqlDatabase.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;

namespace MyFunctionApp
{
    public class MySqlDatabase : IDisposable
    {
        public MySqlConnection Connection;

        public MySqlDatabase(string connectionString)
        {
            Connection = new MySqlConnection(connectionString);
            this.Connection.Open();
        }

        public void Dispose()
        {
            Connection.Close();
        }
    }
}

Here's the service I'm calling that's throwing the error mentioned above (PostsService.cs):

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Net;
using MySql.Data.MySqlClient;

namespace MyFunctionApp
{
    public class PostsService
    {
        private readonly MySqlDatabase _MySqlDatabase;

        public PostsService(MySqlDatabase mySqlDatabase)
        {
            _MySqlDatabase = mySqlDatabase;
        }

        [FunctionName("InsertIntoPost")]
        public async Task<IActionResult> InsertIntoPost(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] PostClassObject request,
            ILogger log)
        {
            var cmd = _MySqlDatabase.Connection.CreateCommand() as MySqlCommand;
            cmd.CommandText = @"INSERT INTO PostsTable(ID) VALUES (12345)";

            int rowCount = await cmd.ExecuteNonQueryAsync();
            Console.WriteLine(String.Format("Number of rows inserted={0}", rowCount));

            return (ActionResult)new OkObjectResult(1);
        }
    }
}

Solution

  • I ended up separating my StartUp.cs into two files. Now everything works!

    WebJobsStartup.cs:

    using AzureFunctions.Extensions.Swashbuckle;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Hosting;
    using System.Reflection;
    using MyFunctionApp;
    
    [assembly: WebJobsStartup(typeof(WebJobsStartup))]
    namespace MyFunctionApp
    {
        public class WebJobsStartup : IWebJobsStartup
        {
            public void Configure(IWebJobsBuilder builder)
            {
                builder.AddSwashBuckle(Assembly.GetExecutingAssembly());
            }
        }
    
    }
    

    MyFunctionAppStartUp.cs:

    using Microsoft.Azure.Functions.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection;
    using System;
    
    [assembly: FunctionsStartup(typeof(MyFunctionApp.MyFunctionAppStartup))]
    namespace MyFunctionApp
    {
        public class MyFunctionApp : FunctionsStartup
        {
            public override void Configure(IFunctionsHostBuilder builder)
            {
                builder.Services.AddTransient<MySqlDatabase>((s) =>
                {
                    return new MySqlDatabase(Environment.GetEnvironmentVariable("MyFunctionApp-DbConn"));
                });
                builder.Services.AddSingleton<ServiceQueries>();
            }
        }
    }