Autofac and ASP .Net MVC 4 Web API
You have registered your IRepository
wrong. With the line:
builder.RegisterType<SharePointRepository<IEntity>>().As<IRepository<IEntity>>();
You told Autofac that whenever somebody will request an IRepository<IEntity>
give them a SharePointRepository<IEntity>
, but you are requesting a concrete IRepository<Integration>
so you get an exception.
What you need is the open generic registration feature of Autofac. So change your registration to:
builder.RegisterGeneric(typeof(SharePointRepository<>))
.As(typeof(IRepository<>));
It will work as you would expect you when you ask for a IRepository<Integration>
it will give a SharePointRepository<Integration>
.
You also have a second unrelated problem: your SharePointRepository
has only an internal
constructor.
Autofac by default only looks for public
constructors so you either change your constructor and class to public
or you need to tell to Autofac to look for NonPublic constructors with the FindConstructorsWith
method:
builder
.RegisterType<SharePointRepository<IEntity>>()
.FindConstructorsWith(
new DefaultConstructorFinder(type =>
type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)))
.As<IRepository<IEntity>>();
Moon
I am hands-on software architect / engineer and effective manager with over 11 years of experience in software craftsmanship and cloud infrastructure. I have a degree in Computer Science. Key Skills Technical Leadership Team Building / Mentoring Software Architecture & Engineering Business Management Systems Implementation & Optimization Software Engineering Project Management Cloud Based Enterprise Solutions IT Infrastructure Management Quality Assurance Personal Favorites Kubernetes, Docker, Python, Golang (Google Go), RabbitMQ, RethinkDB, Google Cloud Platform, Webpack, React, ES6, Atom, Erlang/Elixir (currently learning), gRPC Background An entrepreneur at heart, I have dedicated my career to developing efficient and scalable solutions to problems faced by many organizations and governments across the world. I believe that educating and empowering individuals and teams to use cutting edge technical inventions help improve efficiency, reduce redundancy, and ultimately push the upward boundaries of potential that is the underlying key to success in any venture. I have an insatiable attitude towards learning and creating solutions that are aesthetically pleasing yet architecturally efficient and scalable. I have a solid background in microservices based enterprise applications development for systems related to business automation, such as Project Portfolio Management (PPM), Enterprise Resource Planning (ERP), Enterprise Content Management (ECM), and Customer Relationship Management (CRM). I am a balanced advocate and practitioner of design patterns with expertise in architecture and engineering of enterprise grade, scalable, real-time solution infrastructure on Microsoft Azure and Amazon Web Services (AWS). I have extensive experience managing teams of in-house and off-shore Software and QA Engineers. Over past few years, I have help build amazing products used and loved by many organizations and Governments worldwide.
Updated on July 20, 2022Comments
-
Moon almost 2 years
I am using Autofac for IoC in my ASP .Net MVC 4 project. Autofac is having some trouble initializing the repository and passing it to the API Controller.
I am sure I am missing something in my configuration.
Here is the error I get when I navigate to:
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, Service service, IEnumerable`1 parameters) at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, Type serviceType, IEnumerable`1 parameters) at Autofac.ResolutionExtensions.ResolveOptional(IComponentContext context, 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>
Here are some relevant bits of code:
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; } }
Entity:
public abstract class Entity : IEntity { protected Entity(int id) { Id = id; } public int Id { get; private set; } }
Integration:
[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; } }
-
Erik Funkenbusch about 11 yearsdefine "having some trouble". Did you read this? asp.net/web-api/overview/extensibility/…
-
-
Moon about 11 yearsthis did help me resolve the issue I was initially having. But, now I get a new error:
No constructors on type 'EL.Web.Infrastructure.SharePointRepository
1[EL.Web.Models.Integration]' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'. I am a little confused here. I have already defined to use
SharePointContext` asISharePointContext
-- and this is the only parameter the repository needs. -
nemesv about 11 yearsYour problem is that your
SharePointRepository1
class only has internal constructors. See my updated answer.