0

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 ?

arman
  • 649
  • 1
  • 10
  • 27
  • Did you debug and check if `_service` or `_service.UserRepository` or `_service.RoleRepository` is null ? Can you also share the autofac configuration ? – Chetan Apr 09 '18 at 10:35
  • Try removing the public parameterless constructor in `GoldenBodyProvider`. If you registered correctly the repository classes in Autofac then the constructor with the automatically injected parameters should be used and those repositories would be instantiated. It would help if you provide your autofac configuration in the question. – Diana Apr 09 '18 at 21:09
  • @ChetanRanpariya added autofac config ,and get all method return value – arman Apr 10 '18 at 13:15
  • @Diana added autofac config, i removed `GoldenBodyProvider(IUnitOfWork unitOfWork, IService service)` but same error – arman Apr 10 '18 at 13:20
  • @arman it looks your `GoldenBodyProvider` is not being instantiated by the depency injection, therefore `_service` is null, thus causing this error. – Alisson Reinaldo Silva Apr 10 '18 at 13:20
  • @Alisson Should I register `GoldenBodyProvider` in the autofac config? – arman Apr 10 '18 at 13:27
  • You need to remove constructor `GoldenBodyProvider()`. Not the other constructor. – Chetan Apr 10 '18 at 13:36
  • @ChetanRanpariya i remove empty constructor and get me an error: **Configuration Error** ,**Description:** An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately. **Parser Error Message:** No parameterless constructor defined for this object. – arman Apr 10 '18 at 15:31

1 Answers1

0

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.

Diana
  • 2,186
  • 1
  • 20
  • 31
  • The first solution did not work, I think the second solution is the best. `` – arman Apr 11 '18 at 11:06
  • Sorry, my bad, autofac property injection requires the properties to have a public setter, they can't be private. I added an update to the answer. [Here](https://stackoverflow.com/a/18195058/1182515) you can find a workaround for this. – Diana Apr 12 '18 at 23:16
  • still not work,Maybe the problem is from my repositories – arman Apr 15 '18 at 06:48