Search code examples
c#asp.net-mvc-5

ValueProvider Is Null MVC


I use this startup class in asp.net MVC 5 (using Microsoft.Extensions.DependencyInjection)

    [assembly: OwinStartupAttribute(typeof(MVC5.Startup))]
namespace MVC5
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);

            var services = new ServiceCollection();

            // configure all of the services required for DI
            ConfigureServices(services);           
            
            // Create a new resolver from our own default implementation
            var resolver = new MyDependencyResolver(services.BuildServiceProvider());            
            // Set the application resolver to our default resolver. This comes from "System.Web.Mvc"
            //Other services may be added elsewhere through time
            DependencyResolver.SetResolver(resolver);
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersAsServices(new[]
                { typeof(HomeController), typeof(AccountController), typeof(ManageController)});

            services.AddTransient<AppDbContext>();
                        
            //====================================================
            // ApplicationUserManager
            //====================================================
            // instantiation requires the following instance of the Identity database
            services.AddTransient(typeof(IUserStore<ApplicationUser>), p => new UserStore<ApplicationUser>(new IdentityContext()));

            // with the above defined, we can add the user manager class as a type
            services.AddTransient<ApplicationUserManager>();

            //====================================================
            // ApplicationSignInManager
            //====================================================
            // instantiation requires two parameters, [ApplicationUserManager] (defined above) and [IAuthenticationManager]
            services.AddTransient(typeof(Microsoft.Owin.Security.IAuthenticationManager), p => new OwinContext().Authentication);
            services.AddTransient<ApplicationSignInManager>();            

            //====================================================
            // ApplicationRoleManager
            //====================================================
            // Maps the rolemanager of identity role to the concrete role manager type
            services.AddTransient<RoleManager<IdentityRole>>();

            // Maps the role store role to the implemented type
            services.AddTransient<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>();
            
        }

       
        /// <summary>
        /// Provides the default dependency resolver for the application - based on IDependencyResolver, which hhas just two methods.
        /// This is combined dependency resolver for MVC and WebAPI usage.
        /// </summary>
        public class MyDependencyResolver : System.Web.Mvc.IDependencyResolver, System.Web.Http.Dependencies.IDependencyResolver
        {
            protected IServiceProvider serviceProvider;
            protected IServiceScope scope = null;

            public MyDependencyResolver(IServiceProvider serviceProvider)
            {
                this.serviceProvider = serviceProvider;
            }

            public MyDependencyResolver(IServiceScope scope)
            {
                this.scope = scope;
                this.serviceProvider = scope.ServiceProvider;
            }

            public IDependencyScope BeginScope()
            {
                return new MyDependencyResolver(serviceProvider.CreateScope());
            }

            public void Dispose()
            {
                Dispose(true);
            }

            protected virtual void Dispose(bool disposing)
            {
                scope?.Dispose();
            }

            public object GetService(Type serviceType)
            {                
                var ser = this.serviceProvider.GetService(serviceType);
                return ser;
            }

            public IEnumerable<object> GetServices(Type serviceType)
            {
                return this.serviceProvider.GetServices(serviceType);
            }
        }        

    }
    public static class ServiceProviderExtensions
    {
        public static IServiceCollection AddControllersAsServices(this IServiceCollection services, IEnumerable<Type> serviceTypes)
        {
            foreach (var type in serviceTypes)
            {
                services.AddTransient(type);
            }

            return services;
        }
    }

In ManageController all services are injected and Action method is ready to run, but due to its Base Controller that has ValueProvider is NULL, The controller is disposed before doing any job. Why controller's valueprovider is null and how to solve this?


Solution

  • I changed, ApplicationUserManager and ApplicationSignInManager and RoleManager injections to the code bellow and now, everything works:

    ...
    services.AddTransient<ApplicationUserManager>(p => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>());
    ...
    services.AddTransient<ApplicationSignInManager>(p => HttpContext.Current.GetOwinContext().Get<ApplicationSignInManager>());
    ...
    services.AddTransient<RoleManager<IdentityRole>>(p => 
                    HttpContext.Current.GetOwinContext().Get<RoleManager<IdentityRole>>());
    ...