asp.net webapi generic repository and dependency injection using resolver gives error

985 Views Asked by At

I am new to design pattern and dependency injection. I used this tutorial for implementing my project.

Enterprise Level Application Architecture with Web APIs using Entity Framework, Generic Repository Pattern and Unit of Work

Solution implementing the above tutorial design pattern and dependency injection with IOC

I have two API controllers:SongController and PlaylistController and as per the tutorial, I have implemented till chapter Resolve-dependency-injection

When I run my application,my two webapis 1)http://localhost:49544/api/song in songcontroller works fine with the resolver 2)http://localhost:49544/api/playlist/8a79e096-052b-4057-9683-7a7443aa305a returns error with following message

{ "message": "An error has occurred.", "exceptionMessage": "An error occurred when trying to create a controller of type 'PlayListController'. 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.d__1.MoveNext()", "innerException": { "message": "An error has occurred.", "exceptionMessage": "Resolution of the dependency failed, type = 'MusicCloudWebApi.Controllers.API.PlayListController', name = '(none)'.\nException occurred while: while resolving.\nException is: InvalidOperationException - The current type, MusicCloud.Services.IPlayListServices, is an interface and cannot be constructed. Are you missing a type mapping?\n-----------------------------------------------\nAt the time of the exception, the container was: \r\n Resolving MusicCloudWebApi.Controllers.API.PlayListController,(none)\r\n Resolving parameter 'playListServices' of constructor MusicCloudWebApi.Controllers.API.PlayListController(MusicCloud.Services.IPlayListServices playListServices)\r\n Resolving MusicCloud.Services.IPlayListServices,(none)\r\n", "exceptionType": "Unity.Exceptions.ResolutionFailedException", "stackTrace": " at Unity.UnityContainer.BuildUp(Type typeToBuild, Object existing, String name, ResolverOverride[] resolverOverrides)\r\n at Unity.UnityContainer.Resolve(Type type, String name, ResolverOverride[] resolverOverrides)\r\n at Unity.UnityContainerExtensions.Resolve(IUnityContainer container, Type t, ResolverOverride[] overrides)\r\n at Unity.WebApi.UnityDependencyScope.GetService(Type serviceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)", "innerException": { "message": "An error has occurred.", "exceptionMessage": "The current type, MusicCloud.Services.IPlayListServices, is an interface and cannot be constructed. Are you missing a type mapping?", "exceptionType": "System.InvalidOperationException", "stackTrace": " at Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicMethodConstructorStrategy.ThrowForAttemptingToConstructInterface(IBuilderContext context)\r\n at lambda_method(Closure , IBuilderContext )\r\n at Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicBuildPlanGenerationContext.<>c__DisplayClass16_0.<GetBuildMethod>b__0(IBuilderContext context)\r\n at Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n at Unity.ObjectBuilder.Strategies.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n at Unity.Container.StrategyChain.BuildUp(IBuilderContext builderContext)\r\n at Unity.Policy.BuildPlanPolicyExtensions.ExecuteBuildUp(IBuildPlanPolicy policy, IBuilderContext context)\r\n at Unity.ObjectBuilder.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey, Action1 childCustomizationBlock)\r\n at Unity.ResolverPolicy.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context)\r\n at lambda_method(Closure , IBuilderContext )\r\n at Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicBuildPlanGenerationContext.<>c__DisplayClass16_0.b__0(IBuilderContext context)\r\n at Unity.ObjectBuilder.BuildPlan.DynamicMethod.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)\r\n at Unity.ObjectBuilder.Strategies.BuildPlanStrategy.PreBuildUp(IBuilderContext context)\r\n at Unity.Container.StrategyChain.BuildUp(IBuilderContext builderContext)\r\n at Unity.Policy.BuildPlanPolicyExtensions.ExecuteBuildUp(IBuildPlanPolicy policy, IBuilderContext context)\r\n at Unity.UnityContainer.BuildUp(Type typeToBuild, Object existing, String name, ResolverOverride[] resolverOverrides)" } } }

userId in database table is of type nvarchar(128)

I have not yet implemented authentication but hardcoded the value from table as parameter to webapi.

what is the issue with the error?

Resolver project's solution explorer

Resolver project has the following interfaces and class

        using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace Resolver
    {
       public  interface IComponent
        {

            void SetUp(IRegisterComponent registerComponent);

        }
    }

            using System;
        using System.Collections.Generic;
        using System.ComponentModel.Composition.Hosting;
        using System.ComponentModel.Composition.Primitives;
        using System.Linq;
        using System.Reflection;
        using System.Text;
        using System.Web;
        using Unity;
        using Unity.Lifetime;

        namespace Resolver
        {

            public static class ComponentLoader
            {
                public static void LoadContainer(IUnityContainer container, string path, string pattern)
                {
                    var dirCat = new DirectoryCatalog(path, pattern);
                    var importDef = BuildImportDefinition();
                    try
                    {
                        using (var aggregateCatalog = new AggregateCatalog())
                        {
                            aggregateCatalog.Catalogs.Add(dirCat);

                            using (var componsitionContainer = new CompositionContainer(aggregateCatalog))
                            {
                                IEnumerable<Export> exports = componsitionContainer.GetExports(importDef);

                                IEnumerable<IComponent> modules =
                                    exports.Select(export => export.Value as IComponent).Where(m => m != null);

                                var registerComponent = new RegisterComponent(container);
                                foreach (IComponent module in modules)
                                {
                                    module.SetUp(registerComponent);
                                }
                            }
                        }
                    }
                    catch (ReflectionTypeLoadException typeLoadException)
                    {
                        var builder = new StringBuilder();
                        foreach (Exception loaderException in typeLoadException.LoaderExceptions)
                        {
                            builder.AppendFormat("{0}\n", loaderException.Message);
                        }

                        throw new TypeLoadException(builder.ToString(), typeLoadException);
                    }
                }

                private static ImportDefinition BuildImportDefinition()
                {
                    return new ImportDefinition(
                        def => true, typeof(IComponent).FullName, ImportCardinality.ZeroOrMore, false, false);
                }
            }

            internal class RegisterComponent : IRegisterComponent
            {
                private readonly IUnityContainer _container;

                public RegisterComponent(IUnityContainer container)
                {
                    this._container = container;
                    //Register interception behaviour if any
                }

                public void RegisterType<TFrom, TTo>(bool withInterception = false) where TTo : TFrom
                {
                    if (withInterception)
                    {
                        //register with interception
                    }
                    else
                    {
                        this._container.RegisterType<TFrom, TTo>();
                    }
                }

                public void RegisterTypeWithControlledLifeTime<TFrom, TTo>(bool withInterception = false) where TTo : TFrom
                {
                    this._container.RegisterType<TFrom, TTo>(new ContainerControlledLifetimeManager());
                }
            }

        }

            using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;

        namespace Resolver
        {
            /// <summary>
            /// Responsible for registering types in unity configuration by implementing IComponent
            /// </summary>
            public interface IRegisterComponent
            {
                /// <summary>
                /// Register type method
                /// </summary>
                /// <typeparam name="TFrom"></typeparam>
                /// <typeparam name="TTo"></typeparam>
                /// <param name="withInterception"></param>
                void RegisterType<TFrom, TTo>(bool withInterception = false) where TTo : TFrom;

                /// <summary>
                /// Register type with container controlled life time manager
                /// </summary>
                /// <typeparam name="TFrom"></typeparam>
                /// <typeparam name="TTo"></typeparam>
                /// <param name="withInterception"></param>
                void RegisterTypeWithControlledLifeTime<TFrom, TTo>(bool withInterception = false) where TTo : TFrom;

            }
        }

in MusicWebAPI project solution, the following class UnityConfig is called at global.asax(UnityConfig.RegisterComponents();)

        using MusicCloud.Model;
        using MusicCloud.Services;
        using Resolver;
        using System.Web.Http;
        using System.Web.Mvc;
        using Unity;
        using Unity.Lifetime;
        using Unity.WebApi;

        namespace MusicCloudWebApi
        {
            public static class UnityConfig
            {
                public static void RegisterComponents()
                {
                    var container = BuildUnityContainer();


                    //  System.Web.Mvc.DependencyResolver.SetResolver(new UnityDependencyResolver(container));
                    System.Web.Mvc.DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));

                    // register dependency resolver for WebAPI RC
                    GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
                    // Create the depenedency resolver.
                    //var resolver = new AutofacWebApiDependencyResolver(container);

                    // Configure Web API with the dependency resolver.
                    //GlobalConfiguration.Configuration.DependencyResolver = resolver;


                }

                private static IUnityContainer BuildUnityContainer()
                {
                    var container = new UnityContainer();

                    // register all your components with the container here
                    // it is NOT necessary to register your controllers

                    // e.g. container.RegisterType<ITestService, TestService>();       
                    // container.RegisterType<IProductServices, ProductServices>().RegisterType<UnitOfWork>(new HierarchicalLifetimeManager());

                    RegisterTypes(container);

                    return container;
                }


                public static void RegisterTypes(IUnityContainer container)
                {

                    //Component initialization via MEFE:\Susana\Portfolio\MusicCloud\MusicCloud\MusicCloudWebApi\bin\MusicCloudWebApi.dll
                    ComponentLoader.LoadContainer(container, ".\\bin", "MusicCloudWebApi.dll");
                    ComponentLoader.LoadContainer(container, ".\\bin", "MusicCloud.Services.dll");
                   // container.Register<DashboardDbContext>(
        //    new InjectionFactory(c => new DashboardDbContext()));


                }

            }

            internal class AutofacWebApiDependencyResolver
            {
                private IUnityContainer container;

                public AutofacWebApiDependencyResolver(IUnityContainer container)
                {
                    this.container = container;
                }
            }
        }

In MusicCloud.Model,i have a class name DependencyResolver

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.Threading.Tasks;
        using System.ComponentModel.Composition;
        using Resolver;
        using MusicCloud.Repository;
        using System.Data.Entity;
        using MusicCloud.Model;

        namespace MusicCloud.Model
        {
            /// <summary>
            /// a) Export in System.ComponentModel.Composition
            /// b)IComponent in Resolver in Resolver Project
            /// </summary>
            [Export(typeof(IComponent))]
            public class DependencyResolver : IComponent
            {
                public void SetUp(IRegisterComponent registerComponent)
                {
                    registerComponent.RegisterType<IUnitOfWork, UnitOfWork>();
                }
            }
        }

playlistcontroller(api)

         [System.Web.Http.HttpGet]
                //// GET api/playlist/abc
                public HttpResponseMessage GetPlayLists(string userId)
                {
                    userId = "8a79e096-052b-4057-9683-7a7443aa305a";
                    var playLists = _playListServices.GetAllPlayLists(userId);
                    if (playLists != null)
                    {
                        var playListEntities = playLists as List<PlayListEntity> ?? playLists.ToList();
                        if (playListEntities.Any())
                            return Request.CreateResponse(HttpStatusCode.OK, playListEntities);
                    }
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "PlayLists not found");
                }

In MusicCloud.Services, I have an interface IPlayListServices which implements PlayListServices

            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Text;
            using System.Threading.Tasks;
            using MusicCloud.Entities;
            using MusicCloud.Model;
            using AutoMapper;
            using MusicCloud.Model.EFModel;
            using System.Transactions;


            namespace MusicCloud.Services
            {
                public class PlayListServices : IPlayListServices
                {
                    private readonly UnitOfWork _unitOfWork;

                    /// <summary>
                    /// Public constructor.
                    /// </summary>
                    //public PlayListServices()
                    //{
                    //    _unitOfWork = new UnitOfWork();
                    //}

                    public PlayListServices(UnitOfWork unitOfWork)
                    {
                        _unitOfWork = unitOfWork;
                    }



                    /// <summary>
                    /// Fetches playList details by id
                    /// </summary>
                    /// <param name="playListId"></param>
                    /// <returns></returns>
                    public PlayListEntity GetPlayListById(int playListId)
                    {
                        var playList = _unitOfWork.PlayListRepository.GetByID(playListId);
                        if (playList != null)
                        {
                            // Mapper.CreateMap<Song, SongEntity>();
                            Mapper.Initialize(cfg =>
                            {
                                cfg.CreateMap<PlayList, PlayListEntity>();

                                //Mapper.Map<Song, SongEntity>();
                            });

                            var playListModel = Mapper.Map<PlayList, PlayListEntity>(playList);
                            return playListModel;
                        }
                        return null;
                    }


                    /// <summary>
                    /// Fetches all the songs.
                    /// </summary>
                    /// <returns></returns>
                     public IEnumerable<PlayListEntity> GetAllPlayLists(string userId)
                   // public PlayListEntity GetAllPlayLists(int userId)

                    {

                        var playLists = _unitOfWork.PlayListRepository
                            .GetAllSongs(x =>
                  x.PlayListSongs.Select(report => report.UserId==userId)).ToList();
                                                   if (playLists.Any())
                        {

                            Mapper.Initialize(cfg =>
                            {
                                cfg.CreateMap<PlayList, PlayListEntity>();
                             });

                             var playListsModel = Mapper.Map<List<PlayList>, List<PlayListEntity>>(playLists);
                            return playListsModel;
                        }
                        return null;
                    }


                    /// <summary>
                    /// Creates a product
                    /// </summary>
                    /// <param name="productEntity"></param>
                    /// <returns></returns>
                    public int CreatePlaylist(PlayListEntity playListEntity)
                    {
                        ///remove
                        var userId = "1";
                          using (var scope = new TransactionScope())
                        {
                            var playList = new PlayList
                            {
                                Name = playListEntity.Name,
                                CreatedDate= playListEntity.CreatedDate,
                                ModifiedDate=playListEntity.ModifiedDate


                            };


                         _unitOfWork.PlayListRepository.Insert(playList);
                        _unitOfWork.Save();
                        scope.Complete();
                         return playList.Id;


                    }
                }

             }
            }
1

There are 1 best solutions below

0
On

@NightOwl888 Thanks for the hint on dependencyresolver. I have found what causes the issue. I missed to register IplaylistServices in dependencyresolver.cs

    registerComponent.RegisterType<IPlayListServices, PlayListServices>();