简体   繁体   中英

ASP.NET MVC 5 Custom RoleProvider cannot retrieve roles from database for username

I Use Autofac and asp.net MVC 5, and Generic Repository pattern

i create Custom RoleProvider

Custom RoleProvider

namespace Web.Utility.Classes
{
    class GoldenBodyProvider : RoleProvider
    {
        private readonly IUnitOfWork _unitOfWork;

        private readonly IService _service;

        public GoldenBodyProvider()
        {
        }

        public GoldenBodyProvider(IUnitOfWork unitOfWork, IService service)
        {
            _unitOfWork = unitOfWork;
            _service = service;
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            throw new NotImplementedException();
        }

        public override string[] GetRolesForUser(string username)
        {
            var role = (from u in  _service.UserRepository.GetAll()
                        join r in _service.RoleRepository.GetAll() on u.RoleId equals r.Id
                        where u.MobileNumber == username
                        select r.RoleInSystem).ToArray();
            return role;
        }

    public override void CreateRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            throw new NotImplementedException();
        }

        public override bool RoleExists(string roleName)
        {
            throw new NotImplementedException();
        }

        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        public override string[] GetUsersInRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public override string[] GetAllRoles()
        {
            throw new NotImplementedException();
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            throw new NotImplementedException();
        }

        public override string ApplicationName { get; set; }
    }
}

In one of the Views called User.IsInRole("Coach") (The GetRolesForUser method is called in RoleProvider) . after that , in GetRolesForUser method in RoleProvider Gives me an error:

Object reference not set to an instance of an object.

The error pointed to _service.UserRepository.GetAll() ,this method is through autofact inject to RoleProvider

Source Error:

Line 31: public override string[] GetRolesForUser(string username)

Line 32: {

Line 33: var role = (from u in _service.UserRepository.GetAll()

Line 34: join r in _service.RoleRepository.GetAll() on u.RoleId equals r.Id

Line 35: where u.MobileNumber == username

Source File: I:\\GBWork\\GoldenBody\\Web\\Utility\\Classes\\GoldenBodyProvider.cs Line: 33

GetAll() method in GenericRepository pattern is :

   public virtual List<T> GetAll()
        {
            return _t.AsParallel().ToList();
        }

I think the injections do not work properly.

autofac configuration:

 #region Autofac

            var builder = new ContainerBuilder();
            #region Registery
            #region MVC Register
            //This allows you to add properties to your filter attributes and any matching dependencies that are registered in the container will be injected into the properties.
            builder.RegisterFilterProvider();

            // You can register controllers all at once using assembly scanning...
            builder.RegisterControllers(typeof(Global).Assembly);

            builder.RegisterModule<AutofacWebTypesModule>();


            builder.RegisterAssemblyTypes(Assembly.Load("ServiceLayer"))
                .Where(t => t.Name.EndsWith("Service"))
                .AsImplementedInterfaces()
                .InstancePerRequest();
            builder.RegisterType(typeof(GoldenBodyDb)).As(typeof(IUnitOfWork)).InstancePerRequest();
            #endregion
            #region WebApi
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); //Register WebApi Controllers
            //زیرا کنتلر های وب ای پی آی در همین اسمبلی می باشد
            #endregion
            #endregion
            var container = builder.Build();

            // Set the dependency resolver for Web API.
            var webApiResolver = new AutofacWebApiDependencyResolver(container);
            GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;

            // Set the dependency resolver for MVC.
            var mvcResolver = new AutofacDependencyResolver(container);
            DependencyResolver.SetResolver(mvcResolver);

            #endregion

Where have I made a mistake? Where is my problem? what's the solution ?

Looks like you are using Identity and implementing a custom Role Provider. I assume you are not using OWIN (there is nothing about it in your autofac configuration). I also assume that you are not using a SignInManager, UserManager, nor AuthenticationManager, you just use your RoleManager as configured in <system.web> with a <roleManager> section mapped to your GoldenBodyProvider class, with <authentication mode="Windows" /> .

If I am making wrong assumptions here my answer will be useless. It would be very helpful if you include this info in your question. Otherwise the right answer can't be provided.

Going on with all of those assumptions, as far as I know, you can't inject constructor parameters to a RoleProvider configured like that. It requires a parameterless constructor. I can think of several possible solutions:

Solution 1: Try to use autofac property injection, instead of injection of constructor parameters. You need to register your provider like this (note: you may want to add a lifetime scope configuration):

builder.RegisterType<GoldenBodyProvider>().PropertiesAutowired();

And convert your readonly fields to writable properties: change this:

private readonly IService _service;
private readonly IUnitOfWork _unitOfWork;

To this:

public IService _service { get; set; }
public IUnitOfWork _unitOfWork { get; set; }

( Update : The original code above defined the properties as private , I changed it to public . Property injection requires the properties to have a public setter, so this solution is not good for you if you need to keep your properties private. Here you can find a workaround for this issue.)

More info about property injection here .

Solution 2: You can implement your RoleProvider methods without Dependency Injection, just directly instantiating the identity database context every time you need to use it, as in this answer (check the code example for class AppRoleProvider ).

public class AppRoleProvider : RoleProvider
{
    public override string[] GetAllRoles()
    {
        using (var userContext = new UserContext())
        {
            ...  //Do the query with userContext and return some value
        }
    }
    ...
}

Solution 3: use Service Locator, as explained in this answer . In the code of your parameterless constructor, do an explicit Resolve to instantiate the fields you need. This solution is not very clean. Accessing the container at run time and doing Resolve should be avoided.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM