Search code examples
asp.net-mvc-5unity-containerdapperasp.net-identity-2

MVC Repository, Unity, Identity Error


I'm starting a new project using MVC 5, Identity 2.x, Unity, and Dapper. I'm using the standard EF functionality for Identity but using Dapper for the rest of the DB access. I'm using a Repository Pattern for all my (non-Identity) DB calls.

I'm fairly new to Unity and Dapper but keep gettin a "Object reference not set to an instance of an object." error whenever I make a call to the DB interface in the Account Controller line from below:

var result = _companyaccountrepository.AddToCompanyUsers(model);

Can anyone point out what I'm doing wrong? Thanks in advance.

Account Controller

private ICompanyAccountRepository _companyaccountrepository { get; set; }

public ICompanyAccountRepository companyaccountrepository
{
    get { return _companyaccountrepository ?? (_companyaccountrepository = new CompanyAccountRepository());  }
}

private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
    get
    {
        return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
    }
    private set
    {
        _userManager = value;
    }
}


private ApplicationSignInManager _signInManager;

public ApplicationSignInManager SignInManager
{
    get
    {
        return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
    }
    private set { _signInManager = value; }
}

public AccountController()
{

}

public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, ICompanyAccountRepository companyaccountrepository)
{
    UserManager = userManager;
    SignInManager = signInManager;
    _companyaccountrepository = companyaccountrepository;
}

...

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SignUp(RegisterUserAndCompanyViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email };

        user.FirstName = model.FirstName;
        user.LastName = model.LastName;

        var result = await UserManager.CreateAsync(user, model.Password);
        if (result.Succeeded)
        {

            await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);

            var result = _companyaccountrepository.AddToCompanyUsers(model);   //*** THIS IS WHERE THE PROBLEM OCCURS ****

            return RedirectToAction("Confirmation");

        }
        AddErrors(result);
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

Interface/Dapper SQL (dummy code to make it simple)

public interface ICompanyAccountRepository
{
    CompanyUser AddToCompanyUsers(RegisterUserAndCompanyViewModel user);

}


public class CompanyAccountRepository : ICompanyAccountRepository
{
    private string dbconn = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;

    public bool AddToCompanyUsers(RegisterUserAndCompanyViewModel user);
    {
        using (SqlConnection cn = new SqlConnection(dbconn))
        {
            cn.Open();
            cn.Insert(new CompanyUser() { CompanyId = user.companyid, UserId = user.id });
            cn.Close();

        }

        return true;

    }

}

Unity.Config

public static void RegisterTypes(IUnityContainer container)
{
    // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
    // container.LoadConfiguration();

    // TODO: Register your types here

    //12-1-16 Need this for Identity
    container.RegisterType<ApplicationDbContext>();
    container.RegisterType<ApplicationSignInManager>();
    container.RegisterType<ApplicationUserManager>();
    container.RegisterType<EmailService>();

    container.RegisterType<IAuthenticationManager>(
        new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));

    container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
        new InjectionConstructor(typeof(ApplicationDbContext)));


    container.RegisterType<AccountController>(
        new InjectionConstructor(typeof(ApplicationUserManager), typeof(ApplicationSignInManager), typeof(ICompanyAccountRepository)));

    container.RegisterType<AccountController>(
            new InjectionConstructor());


    //Identity / Unity stuff below to fix No IUserToken Issue  - http://stackoverflow.com/questions/24731426/register-iauthenticationmanager-with-unity
    //container.RegisterType<DbContext, ApplicationDbContext>(
    //    new HierarchicalLifetimeManager());
    container.RegisterType<UserManager<ApplicationUser>>(
        new HierarchicalLifetimeManager());
    container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
        new HierarchicalLifetimeManager());

        container.RegisterType<ICompanyAccountRepository, CompanyAccountRepository>();

}

Thanks again for any suggestions.

NOTE: If I add instantiate the repository just before the AddToCompanyUsers call (below), it works fine. However, this breaks Unity/IOC

_companyaccountrepository= new CompanyAccountRepository();
var result = _companyaccountrepository.AddToCompanyUsers(model);

Solution

  • You can try it like this:

    (this should fix your repository error. As for your userManager and signInManager, I believe you can improve how they are configured as well, but that will take to take a look on your startup.auth and your ApplicationDbContext and with all the Identity configuration)

    Account Controller

    private readonly ICompanyAccountRepository _companyaccountrepository;// { get; set; } -- remove the getter and setter here
    
    
    
    //remove this
    
    // public ICompanyAccountRepository companyaccountrepository
    // {
    //     get { return _companyaccountrepository ?? (_companyaccountrepository = new CompanyAccountRepository());  }
    // }
    
    private ApplicationUserManager _userManager;
    public ApplicationUserManager UserManager
    {
        get
        {
            return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }
    
    
    private ApplicationSignInManager _signInManager;
    
    public ApplicationSignInManager SignInManager
    {
        get
        {
            return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
        }
        private set { _signInManager = value; }
    }
    
    //I think you can remove the parameterless constructor as well
    //public AccountController()
    //{
    //
    //}
    
    public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, ICompanyAccountRepository companyaccountrepository)
    {
        UserManager = userManager;
        SignInManager = signInManager;
        _companyaccountrepository = companyaccountrepository;
    }
    
    ...
    

    EDIT

    Change your constructor to:

    public AccountController(ICompanyAccountRepository companyaccountrepository)
    {
        _companyaccountrepository = companyaccountrepository;
    }