1

I've got a weird problem using ASP.NET in combination with Entity Framework and Unity Container.

This problem only occurs after the application has been running from a few hours to a few days. And after this happens it's temporally fixed (again for the same period) by restarting IIS.

Sometimes the problem gives an exception on trying to inject (using unity-container) a Controller.

Example:

public class PersonController
{
     private readonly ICrudService<Person> personCrudservice;

     public PersonController(ICrudService<Person> personCrudservice) 
     {
         this.personCrudservice = personCrudservice;
     }
}

The exception here is: An error occurred when trying to create a controller of type 'PersonController'. Make sure that the controller has a parameterless public constructor.

Of course the controller doesn't have a parameterless constructor, but using unity-container the personCrudservice is injected. However, this doesn't happen since the dbContext.Set<Person>() method gives the following exception: An item with the same key has already been added. which leads to the exception shown above.

Another example is an exception when trying to load data from the database. Which gives a NullReference exception. (Again, not all of the time and the data exists in the database)

Can you guys help me tackle the issue?

DataContext.cs:

public class DataContext : IUnitOfWork, IRepositoryFactory, ICrudServiceFactory
{
    private const string CONNECTIONSTRING = "Constring";
    private static readonly MedicijnverstrekkingDbContext dbContext = new MedicijnverstrekkingDbContext(CONNECTIONSTRING);
    public DbContext DbContext => dbContext;

    public static volatile Dictionary<string, object> repositories = new Dictionary<string, object>();

    public DataContext()
    {
        dbContext.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
    }   

    public void SaveChanges()
    {
        dbContext.SaveChanges();
    }

    public void Dispose()
    {
        dbContext.Dispose();
    }

    public IRepository<T> CreateRepositoryFor<T>() where T : class, IEntity
    {
        var naam = typeof(T).FullName;
        var repos = default(IRepository<T>);

        if(repositories.ContainsKey(naam))
        {
            repos = repositories[naam] as IRepository<T>;
        }
        if(repos == null)
        {
            repos = new Repository<T>(dbContext.Set<T>());

            repositories[naam] = repos;
        }
        return repos;
    }

    ICrudService<T> ICrudServiceFactory.GenerateCrudServiceFor<T>(IUnityContainer unityContainer)
    {
        var icrudServiceType = typeof(ICrudService<T>);

        var tService = icrudServiceType.Assembly.GetTypes().Where(t => icrudServiceType.IsAssignableFrom(t)).FirstOrDefault();

        //If predefined crud service exists, create an instance, otherwise create a generic crud service.
        if (tService != null)
        {
            return (ICrudService<T>)Activator.CreateInstance(tService, new object[] { unityContainer.Resolve<IUnitOfWork>(), unityContainer.Resolve<IRepository<T>>() });
        }
        else
        {
            return new GenericCrudService<T>(unityContainer.Resolve<IUnitOfWork>(), unityContainer.Resolve<IRepository<T>>());
        }
    }
}

UnityConfig.cs

public class UnityConfig
{
    private static readonly Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    public static IUnityContainer Container => container.Value;

    public static void RegisterTypes(IUnityContainer container)
    {
        RegisterDependencies(container);

        System.Web.Mvc.DependencyResolver.SetResolver(new UnityDependencyResolverAdapter(container));
        GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
    }

    private static void RegisterDependencies(IUnityContainer unityContainer)
    {
        RegisterDataContextAndUnitOfWork(unityContainer);
        RegisterRepositories(unityContainer);
        RegisterAuthenticationDependencies(unityContainer);
    }

    private static void RegisterDataContextAndUnitOfWork(IUnityContainer container)
    {
        container.RegisterType<IUnitOfWork, DataContext>(HttpContextLifetimeManager.FromType<DataContext>());
        container.RegisterType<IRepositoryFactory, DataContext>(HttpContextLifetimeManager.FromType<DataContext>());
        container.RegisterType<ICrudServiceFactory, DataContext>(HttpContextLifetimeManager.FromType<DataContext>());

    }

    private static void RegisterAuthenticationDependencies(IUnityContainer container)
    {
        container.RegisterType<IUserStore<GebruikerModel>, UserStore>(HttpContextLifetimeManager.FromType<UserStore>());
        container.RegisterType<IRoleStore<RoleModel, string>, RoleStore>(HttpContextLifetimeManager.FromType<RoleStore>());

        container.RegisterFactory<UserManager<GebruikerModel>>(unityContainer =>
        {
            var userStore = unityContainer.Resolve<IUserStore<GebruikerModel>>();
            var manager = new UserManager<GebruikerModel>(userStore)
            {
                PasswordHasher = new BcryptPasswordHasher()
            };
            manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<GebruikerModel>
            {
                MessageFormat = "Uw inlogcode is {0}."
            });
            manager.SmsService = new SmsService();
            return manager;
        });

        container.RegisterType<ICurrentUserProvider, CurrentHttpUserProvider>();
    }

    private static void RegisterRepositories(IUnityContainer container)
    {
        var registerRepositoryMethodName = MemberNameHelper.GetActionName(() => RegisterRepository<IEntity>(container));
        var registerCrudserviceName = MemberNameHelper.GetActionName(() => RegisterCrudService<IEntity>(container));
        var registerRepositoryMethodInfo = typeof(UnityConfig).GetMethod(registerRepositoryMethodName, BindingFlags.NonPublic | BindingFlags.Static);
        var registerCrudserviceMethodInfo = typeof(UnityConfig).GetMethod(registerCrudserviceName, BindingFlags.NonPublic | BindingFlags.Static);

        foreach (var entityType in typeof(IEntity).Assembly.GetTypes().Where(t => typeof(IEntity).IsAssignableFrom(t)))
        {
            var registerRepositoryMethod = registerRepositoryMethodInfo.MakeGenericMethod(entityType);
            registerRepositoryMethod.Invoke(null, new object[] { container });

            var registerCrudserviceMethod = registerCrudserviceMethodInfo.MakeGenericMethod(entityType);
            registerCrudserviceMethod.Invoke(null, new object[] { container });
        }
    }

    private static void RegisterRepository<T>(IUnityContainer unityContainer) where T : class, IEntity
    {
        unityContainer.RegisterFactory<IRepository<T>>(
            factory => factory.Resolve<IRepositoryFactory>().CreateRepositoryFor<T>(),
            HttpContextFactoryLifetimeManager.ForRepository<T>()
        );
    }


    private static void RegisterCrudService<T>(IUnityContainer unityContainer) where T : class, IEntity
    {
        unityContainer.RegisterFactory<ICrudService<T>>(
            factory => factory.Resolve<ICrudServiceFactory>().GenerateCrudServiceFor<T>(factory),
            HttpContextFactoryLifetimeManager.ForCrudService<T>()
            );
    }
}

I've been having this problem for weeks now and trying different LifeTimeManagers and also downgrading Unity-Container / Entity Framework didn't help.

Stacktrace: An item with the same key has already been added.

   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at System.Data.Entity.Internal.InternalContext.Set[TEntity]()
   at System.Data.Entity.DbContext.Set[TEntity]()
   at Multitask.COMPANYNAME.DataAccess.EntityFramework.DataContext.CreateRepositoryFor[T]() in C:\Source\Workspaces\Multitask.COMPANYNAME\Multitask.COMPANYNAME\DataAccess\DataContext.cs:line 50
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Multitask.COMPANYNAME.WebApplication.Unity.HttpContextFactoryLifetimeManager.GetValue(ILifetimeContainer container) in C:\Source\Workspaces\Multitask.COMPANYNAME\Multitask.COMPANYNAME\WebApplication\Unity\HttpContextFactoryLifetimeManager.cs:line 60
   at Unity.Strategies.LifetimeStrategy.PreBuildUp(BuilderContext& context)
   at Unity.UnityContainer.<>c.<.ctor>b__73_1(BuilderContext& context)
   at Unity.UnityContainer.Unity.IUnityContainer.Resolve(Type type, String name, ResolverOverride[] overrides)
   at Unity.UnityContainerExtensions.Resolve[T](IUnityContainer container, ResolverOverride[] overrides)
   at Multitask.COMPANYNAME.DataAccess.EntityFramework.DataContext.Multitask.COMPANYNAME.Service.DataAccess.ICrudServiceFactory.GenerateCrudServiceFor[T](IUnityContainer unityContainer) in C:\Source\Workspaces\Multitask.COMPANYNAME\Multitask.COMPANYNAME\DataAccess\DataContext.cs:line 131
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Multitask.COMPANYNAME.WebApplication.Unity.HttpContextFactoryLifetimeManager.GetValue(ILifetimeContainer container) in C:\Source\Workspaces\Multitask.COMPANYNAME\Multitask.COMPANYNAME\WebApplication\Unity\HttpContextFactoryLifetimeManager.cs:line 70
   at Unity.Strategies.LifetimeStrategy.PreBuildUp(BuilderContext& context)
   at Unity.UnityContainer.<>c.<.ctor>b__73_2(BuilderStrategy[] chain, BuilderContext& context)
   at Unity.Builder.BuilderContext.Resolve(Type type, String name, InternalRegistration registration)
   at Unity.Builder.BuilderContext.Resolve(Type type, String name)
   at Unity.Builder.BuilderContext.Resolve(ParameterInfo parameter, Object value)
   at Unity.Processors.ConstructorProcessor.<>c__DisplayClass16_0.<GetResolverDelegate>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
   at Unity.UnityContainer.<>c.<.ctor>b__73_2(BuilderStrategy[] chain, BuilderContext& context)
   at Unity.Builder.BuilderContext.Resolve(Type type, String name, InternalRegistration registration)
   at Unity.Builder.BuilderContext.Resolve(Type type, String name)
   at Unity.Builder.BuilderContext.Resolve(ParameterInfo parameter, Object value)
   at Unity.Processors.ConstructorProcessor.<>c__DisplayClass16_0.<GetResolverDelegate>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
   at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
   at Unity.UnityContainer.<>c.<.ctor>b__73_1(BuilderContext& context)
   at Unity.UnityContainer.Unity.IUnityContainer.Resolve(Type type, String name, ResolverOverride[] overrides)
   at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
   --- End of inner exception stack trace ---
   at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
   at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)````
3
  • Could you attach StackTrace of error? Commented Feb 20, 2020 at 12:31
  • Watch out for private information in the stacktrace. I've edited out what I believe to be information you don't want to reveal Commented Feb 20, 2020 at 14:44
  • @Flater Thanks for that. I forgot to edit it. Commented Feb 21, 2020 at 8:34

1 Answer 1

-1

Add an Empty constructor like;

public PersonController() {};    
//before 

public PersonController(ICrudService<Person> personCrudservice) 
{
  this.personCrudservice = personCrudservice;
};
Sign up to request clarification or add additional context in comments.

1 Comment

This might cause Unity to use the empty constructor, instead of injecting the ICrudService<Person>, no?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.