Home > Back-end >  dependency injection not working in data class "an object reference is required" error
dependency injection not working in data class "an object reference is required" error

Time:04-08

I have a c# DotNet6 project where I need to get my connection string from within my data classes, and usually did this via a global variable. I need to do this via dependency injection instead, and got the injection to work in my class, however, I can't use a property (in this case a simple string) of it without the "An object reference is required for the non-static field, method, or property ..." error message in the IDE. I'm not sure what I am doing incorrectly (and the following code was lifted from a tutorial for dotnetcore 2.0 - clearly something changed).

In my program.cs, I have created a class called DBconfig and the builder options, as so:

public class DBConfig
{
    public string ConnString { get; set; } = "";
}


var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers().AddOData(options => options.EnableQueryFeatures());
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton(new DBConfig() { ConnString = builder.Configuration.GetConnectionString("DBConn") });

var app = builder.Build();

In my data class, I have the following private property and constructor, for database methods inside:

 public class LiveItem_Data
    {
        private readonly DBConfig _conf;

        public LiveItem_Data(DBConfig conf)
        {
            _conf = conf;
        }

When I use _conf.ConnString inside my SqlConnection, I get the squiggly line, "_conf is not null here" and error "An object reference is required for the non-static field..." .

using (SqlConnection conn = new(_conf.ConnString))

So I figured I'd make the ConnString static, but then in the program.cs, but then I can't use it in the object initializer (since it's static - of course), and tried other things, but keep going in circles. Like the DI part works, but I can't seem to configure it so I can actually use it.

CodePudding user response:

I tried to somehow replicate your setup and I've created from scratch a .NET core API (c# 10/ .NET 6).

Here is my setup: Program.cs:

using WebApplication1;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton(new DBConfig() { ConnString = builder.Configuration.GetConnectionString("DBConn") });


var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

appsettings.config:

   {
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "ConnectionStrings": {
    "DBConn": "Server=localhost;Database=TestDb;"
  },
  "AllowedHosts": "*"
}

and default generated controller where I have injected the config:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;

namespace WebApplication1.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

        private readonly ILogger<WeatherForecastController> _logger;
        private readonly DBConfig _config;

        public WeatherForecastController(ILogger<WeatherForecastController> logger, DBConfig config)
        {
            _logger = logger;
            _config = config;
        }

        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()

        {
            //check connection string
            using (SqlConnection conn = new(_config.ConnString))
            {

            }

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

I can't see any error related to the null evaluation and the config value is passed correctly:

enter image description here

Maybe this example will help a bit, or maybe you could add some extra details to your question (like how is the LiveItem_Data registered with DI, or created)

CodePudding user response:

Dependency injection works for the request pipeline, it will not work for any class you may want to use. This would happen usually in controllers or razor pages. Once you capture the injected object there, you can add it to your variable declaration. For instance with controllers, you may want to do something like this, and your startup code would be unchanged from the looks for it

public class HomeController : Controller
{

    private DBConfig _conf;

    public HomeController(DBConfig conf)
    {
        _conf = conf;
    }

    public IActionResult Index() 
    {
        LiveItem_Data myclass = new LiveItem_Data(_conf)
        myclass.dostuff();
        //Do whatever


    }

}

I think if you follow the pattern of taking what injected into the request pipeline from the constructor of the controller (a bit diff if you are using razor pages) it should work fine.

CodePudding user response:

You need to add both to the service container if you wish your classes to resolve its dependencies via DI

using WebApplication1.Model;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// add dbconfig
builder.Services.AddSingleton(new DbConfig() { ConnString = builder.Configuration.GetConnectionString("DBConn") });
// add data layer
builder.Services.AddSingleton<LiveItem_Data>();
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

use it like this

        private LiveItem_Data _myClass;
        public WeatherForecastController(ILogger<WeatherForecastController> logger, LiveItem_Data myClass)
        {
            _logger = logger;
            _myClass = myClass;

            var test = _myClass.GetConnString();
        }

enter image description here

If you're still getting an error, check your appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "ConnectionStrings": {
    "DBConn": "Server=localhost;Database=TestDb;"
  },
  "AllowedHosts": "*"
}
  • Related