-1

Hi I have a doubt about how implement correctly the followin code:

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 serivice:

public class TerminalService : ITerminalService
    {
        private readonly IRepositoryWrapper _repository;

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

        public async Task<Result> UpsertInfo(SessionMessage ternminalObject)
        {
            try
            {
                // Do dark things....

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

        }
    }

The service use several things for insert or update in several db tables.

and, finally, my factory:

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

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

The factory instace the service and the repositories.

Well, this code, fail and throw the error:

System.MissingMethodException: 'No parameterless constructor defined for type TerminalsController'

Ok, the only way that I Found was this: No parameterless constructor defined when accessing web service

I mean, put public TerminalService() : this(new RepositoryWrapper()) { } in TermialService.

My doubt is, ¿it this correct? I mean... I want that all go trow Interfaces, and I'm not sure if this "new RepositoryWrapper()" break this tarject

Im not sure if I make the question in the correct way... anyway, if you need more code, I will write here, I have written only what I considered necessary.

EDIT

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;
            }
        }
    }

Thanks!

  • I'm not sure but I still wanna ask that did you set the [dependency injection](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0#overview-of-dependency-injection) in startup.cs ? According to the error message, the issue points to the controller construction method. But we can see that it only have the injection code. So did you add the similar line-code `services.AddSingleton();` in ConfigureServices method? – Tiny Wang Aug 06 '21 at 06:56
  • Yeap, y tried this and didnt worked – José Pablo Medina Grande Aug 11 '21 at 08:23
  • could you pls show us the code in your startup.cs ? – Tiny Wang Aug 11 '21 at 08:31
  • I have written the startup class on the message. – José Pablo Medina Grande Aug 12 '21 at 07:26
  • Hi, I found that in your controller and startup file, you inject the service `ServiceWrapper`, but you only provide the content of service `TerminalService`. Hence we don't know what you composed in `IServiceWrapper`. Did you made a mistake by setting a wrong service? – Tiny Wang Aug 12 '21 at 08:50
  • Hi @TinyWang, I think I dint undertand you... this is my IServiceWrapper: ´´´ public interface IServiceWrapper { ITerminalService Terminal { get; } } ``` – José Pablo Medina Grande Aug 13 '21 at 06:10
  • The implement class for IServiceWrapper? – Tiny Wang Aug 13 '21 at 06:54
  • Like this ? public class ServiceWrapper : IServiceWrapper { public ITerminalService Terminal { get { return new TerminalService(); } } } – Tiny Wang Aug 13 '21 at 06:57
  • ok, I put in on the asnswer, thanks @TinyWang – José Pablo Medina Grande Aug 13 '21 at 07:03
  • The error message says "No parameterless constructor defined for type **TerminalsController**", so why are you talking about `TerminalService`? And what are these horrible static `SqlHelper` and `DbClientFactory` classes? The whole point of dependency injection is that you **don't** have static classes, the DI framework creates and injects your dependencies for you as needed. I think you need to take a step back and go and do some reading on DI before you get yourself further into a mess. – Ian Kemp Aug 13 '21 at 07:18
  • hahha well ok, I am still learnig... I will reasearch about it @IanKemp – José Pablo Medina Grande Aug 13 '21 at 07:36
  • @JoséPabloMedinaGrande try to replace `Activator.CreateInstance` with `FormatterServices.GetUninitializedObject` – Tiny Wang Aug 13 '21 at 07:38
  • hi @TinyWang. if I remove public TerminalService() : this(new RepositoryWrapper()) { } from TerminalService class, and remplace this in DBClientFactory, y get am error "System.NullReferenceException: 'Object reference not set to an instance of an object." In a line: var company = await _repository.Company.GetById(int.Parse(Id)) I mena, when I am trying to use the methods implemented in the repository – José Pablo Medina Grande Aug 13 '21 at 08:14
  • @JoséPabloMedinaGrande could you pls comment that line which appeared exception and use hard-code data instead to check whether the program can run completely? Let's make sure one issue has solved first. – Tiny Wang Aug 13 '21 at 08:44
  • But this is the problems now.. I mean. If I remove public TerminalService() : this(new RepositoryWrapper()) { } from TerminalService class, and keep Activator.CreateInstance instead use FormatterServices.GetUninitializedObject, the error is "System.MissingMethodException: 'No parameterless constructor defined for type", If Y use FormatterServices.GetUninitializedObject, the erro is now "System.NullReferenceException: 'Object reference not set to an instance of an object." So, I think yes, the first problem (No parameterless constructor defined for type) is solved. – José Pablo Medina Grande Aug 13 '21 at 09:13
  • @JoséPabloMedinaGrande Okay, then the next issue is `System.NullReferenceException` in that line-code. And about the new issue, I think it's better to create a new question with more details on the querying method. As you can see the new error is not suitable for using these content and title to help forum members trouble : ) – Tiny Wang Aug 13 '21 at 09:54
  • I mean a new question could make more users see and participate in this issue, as this question already have plenty of information about the `MissingMethodException` problem and is asked a week ago. I've sum up the solution below, you can accept it as the answer to make it benefit to others met similar error. Many thanks. – Tiny Wang Aug 13 '21 at 10:00
  • hi, @TinyWang, y put another answer here: https://stackoverflow.com/questions/68775058/dependecy-injection-troubles-system-nullreferenceexception-object-reference-n Shall you helpme? – José Pablo Medina Grande Aug 13 '21 at 20:19

1 Answers1

0

To sum up here, although the exception took place in controller, but with the code snippet provided by OP, we finally locate the error in the implement of ITerminalService.

Just using FormatterServices.GetUninitializedObject rather than Activator.CreateInstance to create instance can solve it.

Tiny Wang
  • 10,423
  • 1
  • 11
  • 29