0

Ok, I am making a Api, trying to use DI.

My Controller:

 [Route("api/[controller]")]
    [ApiController]
    public class TerminalsController : ControllerBase
    {
        private readonly IServiceWrapper _service;

        public TerminalsController(IServiceWrapper service)
        {
            _service = service;
        }

        [HttpPost]
        public async Task<ActionResult> Post([FromBody] Message object)
        {
            try
            {

                Result result = await _service.Terminal.UpsertInfo(ternminalObject);

                if (result.shopId != -1 || result.deviceId != -1 || result.companyId != -1)
                {
                    return Ok(result);
                }
                else
                {
                    return BadRequest("Can not save info from session on database");
                }
            }
            catch (Exception ex)
            {
                return StatusCode(500, "Internal server error");
            }
        }
    }

And the code of my service:

public class TerminalService : ITerminalService
    {
        private readonly IRepositoryWrapper _repository;

        public TerminalService(IRepositoryWrapper repository) 
        {
            _repository = repository;
        }

        public async Task<Result> UpsertInfo(company company)
        {
            try
            {
                var company = await _repository.Company.GetById(int.Parse(company.Id))

                return result;
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }
    }

When my code rise the line

 var company = await _repository.Company.GetById(int.Parse(company.Id))

I get the error

System.NullReferenceException: 'Object reference not set to an instance of an object.'

Here there are my others class:

My factory:

 public class DbClientFactory<T>
    {
        private static Lazy<T> _factoryLazy = new Lazy<T>(
            () => (T)FormatterServices.GetUninitializedObject(typeof(T)),
            LazyThreadSafetyMode.ExecutionAndPublication);

        public static T Instance
        {
            get
            {
                return _factoryLazy.Value;
            }
        }
    }

The factory instace the service and the repositories.

This is my StartUp.cs:

 public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
            SqlHelper.connectionString = Environment.GetEnvironmentVariable("CONNECTION_STRING");
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.ConfigureCors();
            services.AddMvc();
            services.ConfigureServiceWrapper();
            services.ConfigureRepositoryWrapper();
            services.AddControllers().AddNewtonsoftJson();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseStaticFiles();
            app.UseCors("CorsPolicy");
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.All
            });

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }

The ConfigureRepositoryWrapper and the ConfigureServiceWrapper are in the ServiceExtensions.cs:

 public static class ServiceExtensions
    {
        public static void ConfigureCors(this IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod());
            });
        }
        public static void ConfigureRepositoryWrapper(this IServiceCollection services)
        {
            services.AddScoped<IRepositoryWrapper, RepositoryWrapper>();
        }
        public static void ConfigureServiceWrapper(this IServiceCollection services)
        {
            services.AddScoped<IServiceWrapper, ServiceWrapper>();
        }
    }

The implement of ServiceWrapper is:

 public class ServiceWrapper : IServiceWrapper
    {
        private ITerminalService _terminal;

        public ITerminalService Terminal {
            get
            {
                if (_terminal == null)
                {
                    _terminal = DbClientFactory<TerminalService>.Instance;
                }
                return _terminal;
            }
        }
    }

And the implement of RepositoryWrapper is:

public class RepositoryWrapper : IRepositoryWrapper
    {
        private IDeviceRepository _device;
        private IShopRepository _shop;
        private ICompanyRepository _company;
        public IDeviceRepository Device
        {
            get
            {
                if (_device == null)
                {
                    _device = DbClientFactory<DeviceRepository>.Instance;
                }
                return _device;
            }
        }

        public IShopRepository Shop
        {
            get
            {
                if (_shop == null)
                {
                    _shop = DbClientFactory<ShopRepository>.Instance;
                }
                return _shop;
            }
        }

        public ICompanyRepository Company {
            get {
                if (_company == null)
                {
                    _company = DbClientFactory<CompanyRepository>.Instance;
                }
                return _company;
            }
        }
    }

I really dont know what is wrong here...

Thank you!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    Does this answer your question? [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – marc_s Aug 13 '21 at 16:40
  • @marc_s, no, the problem is that i dont know why I get this error, because I thinks I am initializating all right – José Pablo Medina Grande Aug 13 '21 at 16:45
  • 2
    Are you debugging? Is the company.Id an actual value or null? Also change the name of the object you are initializing, you cannot have a parameter named `company` and another instance within the method named `company`. – xtryingx Aug 13 '21 at 20:08
  • I now see that you are trying to pass in the service into a non service class. That is why it is null. You will need to pass the`IRepositoryWrapper` into the controller, then pass that value into the constructor when you call`TerminalService`. – xtryingx Aug 13 '21 at 20:53
  • Hi @JoséPabloMedinaGrande I think you can add a break at line `var company = await _repository.Company.GetById(int.Parse(company.Id))` to check if `_repository` is null or the parameter `company` is null. – Tiny Wang Aug 15 '21 at 04:43

1 Answers1

0

You are getting this error because company.Id does not exist.

var company = await _repository.Company.GetById(int.Parse(company.Id));

You are creating/fetching an object named company and at the same already have an object passed in that is named company, you can not do have two variables or objects in the same scope with the same name. Rename one of the objects from company to something else.

Also you likely are not passing in an object in the parameter, you are probably passing in null which is the reason for company.Id not existing. Check the value you are passing in, and rename one of the items.

var newCompany = await _repository.Company.GetById(int.Parse(company.Id));

If the exception is happening on _repository, the reason is that you are trying to pass a dependency into a non service class. To fix it, pass the dependency into the controller, then when initializing TerminalService just pass in the _repository. Also make sure that _service.Terminal is instantiated.

public class TerminalsController : ControllerBase
{
     private readonly IServiceWrapper _service;
     private readonly IRepositoryWrapper _repository;

    public TerminalsController(IServiceWrapper service, IRepositoryWrapper repository)
    {
         _service = service;
         _repository = repository;
    }

    [HttpPost]
    public async Task<ActionResult> Post([FromBody] Message object)
    {
        _service.Terminal = new TerminalService(_repository);
        Result result = await _service.Terminal.UpsertInfo(ternminalObject);

        //remaining code    
    }
}
xtryingx
  • 152
  • 7
  • The null is in _repostory, not in the object... is like the constructor cant Inject the deendecy – José Pablo Medina Grande Aug 13 '21 at 20:18
  • Instead of calling `services.ConfigureRepositoryWrapper();` in the ConfigureServices method of Startup. Have you tried just having `services.AddScoped();` in the `ConfigureServices` method instead? – xtryingx Aug 13 '21 at 20:23
  • What is the benefit of having `ConfigureREpositoryWrapper()` if all it does is `services.AddScoped();`? Why not just call `AddScoped` within the ConfigureServices method in Startup? My guess is that the dependency injection is not working because of this. – xtryingx Aug 13 '21 at 20:44
  • I just realized that you are trying to use dependency injection on a non service class. Since the class is not a controller, you should accept the service on the controller that will call the `TerminalService` class and pass it in the constructor. Startup by default will pass dependencies into controllers. – xtryingx Aug 13 '21 at 20:51
  • hi xtryingx.. I tryed that you said in your commetn and still get the null exception.... and I dont know what you mean in the last coment.... – José Pablo Medina Grande Aug 13 '21 at 22:02
  • In the last comment I am saying to pass `private readonly IRepositoryWrapper _repository;` into the TerminalsController. It will have two parameters now, the IServiceWrapper and IRepositoryWrapper. Then when you need to call TerminalService, instantiate a new TerminalService and pass _repository from the TerminalContoller into the constructor of TerminalService. – xtryingx Aug 13 '21 at 22:06
  • I have made updates to my answer. Look at the last chunk. – xtryingx Aug 13 '21 at 22:13
  • Hi @xtrying....but, this dont make that DI stop making sense?? – José Pablo Medina Grande Aug 14 '21 at 04:34