Autofac 和 ASP .Net Web API 版本 4.2.0 .NET Framework 4.7.2

Autofac and ASP .Net Web API version 4.2.0 .NET Framework 4.7.2

请注意,我正在使用 Autofac,但是当我 运行 API 并使用此 URL 检查 Postman 时,:

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

我收到这个错误:

{
    "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)"
            }
        }
    }
}

当我调查时,我发现了这些网站:

Autofac and ASP .Net MVC 4 Web API

但是我有一个public计算控制器的无参数构造函数:

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

到目前为止,我已经在这里检查了解决方案:

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

但我认为它不适用于我的情况。

这是我的注册服务:

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

这是我认为出现错误的函数:

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

有人有什么建议吗? TIA.

更新:

请注意,我发现我缺少这个构造函数。

    public MyModelUserRepository()
    {
    }

但是现在当我与 Postman 核实时,我收到“500 内部服务器错误”,所以有人有什么建议吗?

更新 2:

请注意,我已经构建了一个单元测试并且它没有错误地通过了,所以我不确定邮递员请求失败的原因。有什么建议么? 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));
    }

错误消息中有趣的部分是

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).

这意味着 Autofac 试图创建一个 CalcRepository 但没有 ICalcContext 可用。

如果您查看您的注册,您只注册了类型而没有指明它是 ICalcContext

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

如果将其更改为

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

您的 CalcContext 类型将被注册为 ICalcContext,这将使 Autofac 创建您的 CalcRepository