我在ASP .Net MVC 4项目中使用Autofac for IoC. Autofac在初始化存储库并将其传递给API控制器时遇到一些问题.
我确信我的配置中缺少一些东西.
这是我在导航到以下时遇到的错误:https:// localhost:44305 / api / integration
<Error> <Message>An error has occurred.</Message> <ExceptionMessage> None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'EL.Web.Controllers.API.IntegrationController' can be invoked with the available services and parameters: Cannot resolve parameter 'EL.Web.Infrastructure.IRepository`1[EL.Web.Models.Integration] repository' of constructor 'Void .ctor(EL.Web.Infrastructure.IRepository`1[EL.Web.Models.Integration])'. </ExceptionMessage> <ExceptionType>Autofac.Core.DependencyResolutionException</ExceptionType> <StackTrace> at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context,IEnumerable`1 parameters) at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters) at Autofac.Core.Resolving.InstanceLookup.Execute() at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope,IComponentRegistration registration,IEnumerable`1 parameters) at Autofac.Core.Resolving.ResolveOperation.ResolveComponent(IComponentRegistration registration,IEnumerable`1 parameters) at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration,IEnumerable`1 parameters) at Autofac.Core.Lifetime.LifetimeScope.ResolveComponent(IComponentRegistration registration,IEnumerable`1 parameters) at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context,Service service,IEnumerable`1 parameters,Object& instance) at Autofac.ResolutionExtensions.ResolveOptionalService(IComponentContext context,IEnumerable`1 parameters) at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context,Type serviceType,Type serviceType) at Autofac.Integration.WebApi.AutofacWebApiDependencyScope.GetService(Type serviceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request,Type controllerType,Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request,HttpControllerDescriptor controllerDescriptor,Type controllerType) </StackTrace> </Error>
以下是一些相关的代码:
IoC Bootstrapper:
public static class Bootstrapper { public static void Initialize() { var builder = new ContainerBuilder(); builder.RegisterControllers(Assembly.GetExecutingAssembly()); builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); builder.Register(x => new SharePointContext(HttpContext.Current.Request)).As<ISharePointContext>().SingleInstance(); builder.RegisterType<SharePointRepository<IEntity>>().As<IRepository<IEntity>>(); builder.RegisterType<SharePointContextFilter>().SingleInstance(); builder.RegisterFilterProvider(); IContainer container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); var resolver = new AutofacWebApiDependencyResolver(container); GlobalConfiguration.Configuration.DependencyResolver = resolver; } }
IRepository:
public interface IRepository<T> { void Add(T entity); void Delete(int id); IEnumerable<T> Find(Expression<Func<T,bool>> filter = null); void Update(int id,T entity); }
SharePointRepository:
internal class SharePointRepository<T> : IRepository<T> where T : IEntity { private readonly ISharePointContext _context; private readonly string _listName; internal SharePointRepository(ISharePointContext context) { _context = context; object[] attributes = typeof (T).GetCustomAttributes(typeof (SharePointListAttribute),false); if (!attributes.Any()) { throw new Exception("No associated SharePoint list defined for " + typeof (T)); } _listName = ((SharePointListAttribute) attributes[0]).ListName; } public void Add(T entity) { throw new NotImplementedException(); } public void Delete(int id) { throw new NotImplementedException(); } public IEnumerable<T> Find(Expression<Func<T,bool>> filter) { throw new NotImplementedException(); } public void Update(int id,T entity) { throw new NotImplementedException(); } }
IntegrationController:
public class IntegrationController : ApiController { private readonly IRepository<Integration> _repository; public IntegrationController(IRepository<Integration> repository) { _repository = repository; } public void Delete(Guid integrationId) { _repository.Delete(Get(integrationId).Id); } public IEnumerable<Integration> Get() { return _repository.Find(); } public Integration Get(Guid integrationId) { return _repository.Find(i => i.IntegrationId == integrationId).FirstOrDefault(); } public void Post([FromBody] Integration integration) { _repository.Add(integration); } public void Put(Guid integrationId,[FromBody] Integration integration) { _repository.Update(Get(integrationId).Id,integration); } }
IEntity:
internal interface IEntity { int Id { get; } }
实体:
public abstract class Entity : IEntity { protected Entity(int id) { Id = id; } public int Id { get; private set; } }
积分:
[SharePointList("Integrations")] public class Integration : Entity { public Integration(int id) : base(id) { } public string ApiUrl { get; set; } public bool DeletionAllowed { get; set; } public Guid IntegrationId { get; set; } public string Key { get; set; } public string List { get; set; } public bool OutgoingAllowed { get; set; } public string RemoteWeb { get; set; } public string Web { get; set; } }
解决方法
您已将IRepository注册错误.随着线:
builder.RegisterType<SharePointRepository<IEntity>>().As<IRepository<IEntity>>();
你告诉Autofac,每当有人要求提供IRepository< IEntity>给他们一个SharePointRepository< IEntity>,但是你要求一个具体的IRepository< Integration>所以你得到一个例外.
你需要的是open generic registration feature of Autofac.所以你的注册更改为:
builder.RegisterGeneric(typeof(SharePointRepository<>)) .As(typeof(IRepository<>));
当您要求提供IRepository< Integration>时,它会像您期望的那样工作.它将提供SharePointRepository< Integration>.
您还有另一个不相关的问题:您的SharePointRepository只有一个内部构造函数.
默认情况下,Autofac只查找公共构造函数,因此您可以将构造函数和类更改为public,或者需要告诉Autofac使用FindConstructorsWith方法查找NonPublic构造函数:
builder .RegisterType<SharePointRepository<IEntity>>() .FindConstructorsWith( new DefaultConstructorFinder(type => type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance))) .As<IRepository<IEntity>>();