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));
}
The interesting part of the error message is
None of the constructors found with
Autofac.Core.Activators.Reflection.DefaultConstructorFinder
on typeEddiTools.Data.CalcRepository
can be invoked with the available services and parameters:Cannot resolve parameter
EddiTools.Data.ICalcContext context
of constructorVoid .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