1

Please note that I am using Autofac, but when I run the API and check with Postman using this URL, :

http://localhost:1234/api/calculations/corpname&51&114&1045

I am getting this error:

{
    "message": "An error has occurred.",
    "exceptionMessage": "An error occurred when trying to create a controller of type 'CalculationsController'. Make sure that the controller has a parameterless public constructor.",
    "exceptionType": "System.InvalidOperationException",
    "stackTrace": "   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()",
    "innerException": {
        "message": "An error has occurred.",
        "exceptionMessage": "An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = CalculationsController (ReflectionActivator), Services = [MyAppTools.Controllers.CalculationsController], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = OwnedByLifetimeScope ---> An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = CalcRepository (ReflectionActivator), Services = [MyAppTools.Data.ICalcRepository], Lifetime = Autofac.Core.Lifetime.MatchingScopeLifetime, Sharing = Shared, Ownership = OwnedByLifetimeScope ---> None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyAppTools.Data.CalcRepository' can be invoked with the available services and parameters:\r\nCannot resolve parameter 'MyAppTools.Data.ICalcContext context' of constructor 'Void .ctor(MyAppTools.Data.ICalcContext)'. (See inner exception for details.) (See inner exception for details.)",
        "exceptionType": "Autofac.Core.DependencyResolutionException",
        "stackTrace": "   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)\r\n   at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context, Service service, IEnumerable`1 parameters)\r\n   at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType)\r\n   at Autofac.Integration.WebApi.AutofacWebApiDependencyScope.GetService(Type serviceType) in C:\\projects\\autofac-webapi\\src\\Autofac.Integration.WebApi\\AutofacWebApiDependencyScope.cs:line 76\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)",
        "innerException": {
            "message": "An error has occurred.",
            "exceptionMessage": "An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = CalcRepository (ReflectionActivator), Services = [MyAppTools.Data.ICalcRepository], Lifetime = Autofac.Core.Lifetime.MatchingScopeLifetime, Sharing = Shared, Ownership = OwnedByLifetimeScope ---> None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyAppTools.Data.CalcRepository' can be invoked with the available services and parameters:\r\nCannot resolve parameter 'MyAppTools.Data.ICalcContext context' of constructor 'Void .ctor(MyAppTools.Data.ICalcContext)'. (See inner exception for details.)",
            "exceptionType": "Autofac.Core.DependencyResolutionException",
            "stackTrace": "   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.<Execute>b__5_0()\r\n   at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func`1 creator)\r\n   at Autofac.Core.Resolving.InstanceLookup.Execute()\r\n   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.ResolveComponent(IComponentRegistration registration, IEnumerable`1 parameters)\r\n   at Autofac.Core.Activators.Reflection.AutowiringParameter.<>c__DisplayClass0_0.<CanSupplyValue>b__0()\r\n   at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()\r\n   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)",
            "innerException": {
                "message": "An error has occurred.",
                "exceptionMessage": "None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyAppTools.Data.CalcRepository' can be invoked with the available services and parameters:\r\nCannot resolve parameter 'MyAppTools.Data.ICalcContext context' of constructor 'Void .ctor(MyAppTools.Data.ICalcContext)'.",
                "exceptionType": "Autofac.Core.DependencyResolutionException",
                "stackTrace": "   at Autofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(IComponentContext context, IEnumerable`1 parameters)\r\n   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters)\r\n   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters)"
            }
        }
    }
}

When I investigate, I have found these sites:

Autofac and ASP .Net MVC 4 Web API

But I have a public parameterless constructor for calculation controller:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using AutoMapper;
using MyAppTools.Data;
using MyAppTools.Models;

namespace MyAppTools.Controllers
{
    public class CalculationsController : ApiController
    {
        private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
        private readonly IMapper _mapper;
        private readonly ICalcRepository _repository;
        private readonly IMyModelUserRepository _myModelRepository;

        public CalculationsController()
        {
        }

        public CalculationsController(ICalcRepository repository, IMyModelUserRepository myModelRepository, IMapper mapper)
        {
            _repository = repository;
            _myModelRepository = myModelRepository;
            _mapper = mapper;
        }

        public async Task<IHttpActionResult> Get()
        {
            try
            {
                var result = await _repository.GetAllCalculationsAsync();
                if (result == null) return NotFound();

                // Mapping
                // This centralizes all of the config
                var mappedResult = _mapper.Map<IEnumerable<CalculationModel>>(result);

                return Ok(mappedResult);
            }
            catch (Exception ex)
            {
                Logger.Error(ex);

                // Be careful about returning exception here
                return InternalServerError();
            }
        }

        [Route("{username}/{password}/{latitude}/{longitude}/{depth}")]
        public async Task<IHttpActionResult> Get(string username, string password, double latitude, double longitude, double depth)
        {
            try
            {
                var result = await _repository.GetCalculationAsync(username, password, latitude, longitude, depth);
                if (result == null) return NotFound();

                // Mapping
                // This centralizes all of the config
                var mappedResult = _mapper.Map<IEnumerable<CalculationModel>>(result);

                return Ok(mappedResult);
            }
            catch (Exception ex)
            {
                Logger.Error(ex);

                // Be careful about returning exception here
                return InternalServerError();
            }
        }
    }
}

So far I have check for a solution here:

Autofac and ASP .Net MVC 4 Web API https://www.nopcommerce.com/boards/t/38102/none-of-the-constructors-found-with-autofaccoreactivatorsreflectiondefaultconstructorfinder-on-type.aspx

But I don't think it applies to my case.

Here is my Register services:

public class AutofacConfig
{
    public static void Register()
    {
        var bldr = new ContainerBuilder();
        var config = GlobalConfiguration.Configuration;
        bldr.RegisterApiControllers(Assembly.GetExecutingAssembly());
        RegisterServices(bldr);
        bldr.RegisterWebApiFilterProvider(config);
        bldr.RegisterWebApiModelBinderProvider();
        var container = bldr.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    }

    private static void RegisterServices(ContainerBuilder bldr)
    {
        var config = new MapperConfiguration(cfg => { cfg.AddProfile(new CalculationMappingProfile()); });

        bldr.RegisterInstance(config.CreateMapper())
            .As<IMapper>()
            .SingleInstance();

        bldr.RegisterType<CalcContext>()
            .InstancePerRequest();

        bldr.RegisterType<CalcRepository>()
            .As<ICalcRepository>()
            .InstancePerRequest();

        bldr.RegisterType<MyModelUserRepository>()
            .As<IMyModelUserRepository>()
            .InstancePerRequest();
    }
}

Here is the function where I think I am getting the error:

    public async Task<double[]> GetCalculationAsync(string username, string password, double latitude,
        double longitude, double depth, bool includeWellRuns = false)
    {
        Calculation calc = new Calculation();
        double[] results = null;

        try
        {
            var user = _context.MyModels.FirstOrDefault(e => e.UserName == username);
            if (user?.LicenseKey == password)
            {
                myModelServiceClient client = new myModelServiceClient("NetTcpBinding_IMyModelService");

                results = client.GetMyModel(latitude, longitude, depth, DateTime.Now.Day,
                    DateTime.Now.Month, DateTime.Now.Year, DateTime.Now.Year, calc.UseGeoid, calc.UseDecimalYear);
                calc.Inclination = Convert.ToString(results[0]);
                calc.Declination = Convert.ToString(results[1]);
                calc.TotalField = Convert.ToString(results[6]);
                calc.CorporationId = 19;
                _context.Calculations.AddOrUpdate(calc);
                await SaveChangesAsync();
            }

        }
        catch (Exception ex)
        {
            Logger.Error(ex);
        }

        return results;
    }

Does anyone have any suggestions? TIA.

UPDATE:

Please note that I've found that I was missing this constructor.

    public MyModelUserRepository()
    {
    }

But now when I check with Postman, I'm getting "500 Internal Server Error" so does anyone have any suggestions?

UPDATE 2:

Please note that I have constructed a unit test and it passes without error so I'm not sure why the Postman request fails. Any suggestions? TIA.

    [TestMethod]
    public async Task GetMyModelCalculationAsync()
    {
        // Arrange
        ICalcRepository calcRepository = new CalcRepository(_calcContext);
        string username = "corpname";
        string password = "licensekey";
        double latitude = 12.3456;
        double longitude = 198.76543;
        double depth = 876;

        // Act
        var actual = await calcRepository.GetCalculationAsync(username, password, latitude, longitude, depth);

        // Assert
        Assert.AreEqual(Math.Round(24.5667789, 2), Math.Round(actual[0], 2));
        Assert.AreEqual(Math.Round(87.3028596, 2), Math.Round(actual[1], 2));
    }

1 Answer 1

4

The interesting part of the error message is

None of the constructors found with Autofac.Core.Activators.Reflection.DefaultConstructorFinder on type EddiTools.Data.CalcRepository can be invoked with the available services and parameters:

Cannot resolve parameter EddiTools.Data.ICalcContext context of constructor Void .ctor(EddiTools.Data.ICalcContext).

which means Autofac tries to create a CalcRepository but no ICalcContext is available.

If you look at your registration, you only register the type without indicating it is a ICalcContext

    bldr.RegisterType<CalcContext>()
        .InstancePerRequest();

If you change this to

    bldr.RegisterType<CalcContext>()
        .As<ICalcContext>()
        .InstancePerRequest();

Your CalcContext type will be registered as a ICalcContext which will let Autofac create your CalcRepository

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.