Skip to main content
 首页 » 编程设计

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

2024年02月04日32mfryf

请注意,我正在使用 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

但是我有一个用于计算 Controller 的公共(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 Internal Server Error”,那么有人有什么建议吗?

更新 2:

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