2013-03-11 20 views
8

Używam Autofac dla IoC w moim projekcie ASP .Net MVC 4. Autofac ma problemy z zainicjalizowaniem repozytorium i przekazaniem go do kontrolera API .Autofac i ASP .Net MVC 4 Web API

Jestem pewien, że brakuje mi czegoś w mojej konfiguracji.

Oto błąd pojawia się, kiedy należy przejść do: 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> 

Oto niektóre istotne fragmenty kodu:

IoC inicjującego:

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

Podmiot:

public abstract class Entity : IEntity 
{ 
    protected Entity(int id) 
    { 
     Id = id; 
    } 

    public int Id { get; private set; } 
} 

Integracja:

[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; } 
} 
+0

określenie „pewne kłopoty ". Czytałeś to? http://www.asp.net/web-api/overview/extensibility/using-twe-web-api-dependency-resolver –

Odpowiedz

9

zarejestrowaniu IRepository źle. Z linii:

builder.RegisterType<SharePointRepository<IEntity>>().As<IRepository<IEntity>>(); 

Mówiłeś Autofac że gdy ktoś będzie poprosić o IRepository<IEntity> dać im SharePointRepository<IEntity>, lecz żądasz konkretny IRepository<Integration> więc masz wyjątek.

To, czego potrzebujesz, to open generic registration feature of Autofac. Tak zmienić rejestracyjne:

builder.RegisterGeneric(typeof(SharePointRepository<>)) 
     .As(typeof(IRepository<>)); 

Będzie ona działać jak można się spodziewać, gdy cię poprosić o IRepository<Integration> to daje SharePointRepository<Integration>.

Masz również drugi niepowiązany problem: Twój SharePointRepository ma tylko konstruktor internal.

Autofac domyślnie wygląda tylko na public konstruktorów więc albo zmienić konstruktora i klasę do public albo trzeba powiedzieć do Autofac szukać konstruktorów niepublicznych metodą FindConstructorsWith:

builder 
    .RegisterType<SharePointRepository<IEntity>>() 
    .FindConstructorsWith(
     new DefaultConstructorFinder(type => 
      type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance))) 
    .As<IRepository<IEntity>>(); 
+0

pomogło mi to rozwiązać problem, który początkowo miałem. Ale teraz dostaję nowy błąd: 'Brak konstruktorów na typ 'EL.Web.Infrastructure.SharePointRepository'1 [EL.Web.Models.Integration]' można znaleźć za pomocą wyszukiwarki konstruktora 'Autofac.Core.Activators.Reflection. DefaultConstructorFinder''. Jestem trochę zdezorientowany. Zdefiniowałem już użycie 'SharePointContext' jako' ISharePointContext' - i jest to jedyny parametr wymagany przez repozytorium. – Moon

+0

Twój problem polega na tym, że twoja klasa 'SharePointRepository1' ma tylko wewnętrzne konstruktory. Zobacz moją zaktualizowaną odpowiedź. – nemesv

Powiązane problemy