im using vs 2013, mvc5 and ef6 + unity.mvc5:
my account controller class has this constructor:
public AccountController(UserManager<ApplicationUser> userManager)
{
this.UserManager = userManager;
}
and this is my unity config:
container.RegisterType(typeof(AccountController),
new InjectionConstructor(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>())));
when i try to register a new user i get this exception:
Cannot access a disposed object.
Object name: 'UserManager`1'.
on this line of code and register action:
var result = await UserManager.CreateAsync(user, model.Password);
when i remove unity and set dependecy resolver to default it works just fine.
i`v tried many unity configs but didnt work...
thanks alot for reading.
i found the solution, changed the unity config to this:
container.RegisterType<IUserStore<ApplicationUser>,
UserStore<ApplicationUser>>(new InjectionConstructor(new ApplicationDbContext()));
thanks all.
Do NOT create a parameterless constructor, (I can't vote it down as I don't have enough reputation), that answer totally avoids IoC and instead tries to build up the object by knowing the entire dependency hierarchy for the object, i.e. AccountController needs to know that it has a dependency on UserStore and it needs to know that Userstore has a dependency on UserContext. This is exactly what DI containers are there to avoid!
It is hard to provide you with an exact answer as there is a lot of your code missing.
One thing that looks odd to me is that you have an uppercase UserManger, that usually means that you are using it as a type, not referencing a local private variable. Can you show me the rest of the code?
Also, I would question why you are not referencing everything via Interfaces. That is by far the preferred way to set up proper DI.
I will try to knock up some test code that shows what I would do and then post this here, if you could answer those questions in the meantime that would be great.
Cheers Mike
Here is what I would do.
In your controller
public class HomeController : Controller
{
private IUserManager<ApplicationUser> userManager;
public HomeController(IUserManager<ApplicationUser> userManager)
{
this.userManager = userManager;
}
public ActionResult Index()
{
var user = "user";
var password = "password";
var result = userManager.CreateAsync(user, password);
return View();
}
}
Interface for UserManager
public interface IUserManager<T> where T : ApplicationUser
{
int CreateAsync(string user, string password);
}
Actual UserManager class
public class UserManager<T> : IUserManager<T> where T : ApplicationUser
{
private IUserStore<ApplicationUser> userStore;
public UserManager(IUserStore<ApplicationUser> userStore)
{
this.userStore = userStore;
}
public int CreateAsync(string user, string password)
{
return 0;
}
}
Interface for UserStore
public interface IUserStore<T> where T : ApplicationUser
{
}
Actual UserStore
public class UserStore<T> : IUserStore<T> where T : ApplicationUser
{
}
Unity configuration
container.RegisterType(typeof (IUserManager<>), typeof (UserManager<>));
container.RegisterType(typeof (IUserStore<>), typeof (UserStore<>));
Hope this helps.
There is obviously lots that is not the same as your app, i.e. not doing the method call async, not reading the password in from the model, etc. but it should give an idea of how to solve the problem that you outlined.
This solution will give you proper constructor dependency injection, which will allow you to have all of your configuration in one place (i.e. the container config) and it will give you interfaces in your constructors which will make it much easier for you to mock those dependencies in your unit tests.
Cheers Mike
Related
I wish to use settings from appsettings.json in my own class.
I have this working well in a controller and in razor. I tried to use the same code as in a controller in my own class:
public class Email
{
private readonly IConfiguration _config;
public Email(IConfiguration config)
{
_config = config;
}
but when I try to call this
Email sendEmail = new Email();
it requires that I provide config as a parameter. Shouldn't the DI system provide (inject) this? In ConfigureServices I have this:
services.AddSingleton(Configuration);
Do I need to register Email class somewhere too? Do I need to call it some different way?
When you use the following code:
Email sendEmail = new Email();
The DI system isn't involved at all - You've taken things into your own hands. Instead, you should add Email to the DI system and then have it injected. e.g.:
services.AddSingleton<Email>(); // You might prefer AddScoped, here, for example.
Then, as an example, if you're accessing Email in a controller, you can have it injected too:
public class SomeController : Controller
{
private readonly Email _email;
public SomeController(Email email)
{
_email = email;
}
public IActionResult SomeAction()
{
// Use _email here.
...
}
}
Essentially, this just means you need to use DI all the way. If you want to provide more details about where you're currently creating your Email class, I can tailor the examples more to that.
It's a bit of an side, but you can also inject dependencies using the [FromServices] attribute inside of an action. Using this means you can skip the constructor and private field approach. e.g.:
public class SomeController : Controller
{
public IActionResult SomeAction([FromServices] Email email)
{
// Use email here.
...
}
}
As you mentioned, you defined a constructor which requires the parameter.
Please check out the concept of Class Constructors.
Injection is design pattern, when we use class and interfaces to implement it, it should still follow the basic Class methodology and concept.
Hope it helps.
I have a controller decorated with [Authorize] attribute. I would like to accomplish the following so that I don't have to repeatedly create repository obj and pass currentUser in each method:
[Authorize]
public class HomeController : ApiController
{
Repository repo;
public HomeController()
{
var userName = User.Identity.IsAuthenticated ? User.Identity.Name : null;
repo = new Repository(userName);
}
}
I know User.Identity is not available in constructor or in Initialize method.
What is the best practice to inject authenticated user in controller constructor.
If we use dependency injection - while registering our custom created UserResolverService inside WebApiConfig.cs in Register method - User.Identity is not available at this point as well.
This is a very common issue with web api but somehow couldn't find any article showing proper solution.
Is it really achievable and if yes - can you please provide some sample code?
Here is how I worked around this (not sure how appropriate this method is, but it works).
In your BaseContoller (a controller from which all other controllers inherit from) create instance of Repository like so:
private Repository _Repository;
private Repository Repository
{
get
{
_Repository.InjectUsername(User.Identity.Name); // value is already available here
return _Repository;
}
set
{
_Repository = new Repository();
}
}
Notice how your Repository has InjectUsername method. That method will simple assign passed parameter to some Repository's property, like so:
public class Repository
{
private string Username { get; set; }
public void InjectUsername(string username)
{
Username = username;
}
}
Every time you will call some method in repository from a controller action you will inject usrename which will already exist, and you won't have to duplicate code by passing username to every method in repository every time you call it.
You can register a factory delegate and get user identity from HttpContext.Current.
Here's a sample code for simpleinjector
container.Register<IPrincipal>(() => HttpContext.Current.User);
I'm currently writing unit test for my project where I'm using HttpContext.Current.User.Identity.Name at a defined time. Unfortunately, I can't make the test work since HttpContext is null when I run the test.
I already tried some solution I found on internet like Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("rmllcc"), new string[0]); but I can't get it work.
I'm using a Forms Authenticate system, xUnit with Moq. I'm not testing a controller but a Repository where I'm just logguing each time a user make use of a particular method. How could I accomplish this?
Listen to what your tests are telling you: use the fact that this test is hard to write to think about the structure of your code. You have introduced a dependency in your repository layer to the web application. That's not good. You also have two things going on in your repository: data access and logging.
Maybe wrap the current user in an abstraction that will get the user you need, but can be easily stubbed. Or you could wrap the repository in a decorator that does the logging for you.
Sorry this is not a direct answer to the question but, when tests are hard to write, there is usually a deeper underlying reason that you need to address.
I suggest you dont use the HttpContext from the repository, Make a own context class or a Interface wrapping the user-property.
Something like this:
public class MyContext
{
public MyContext(string username)
{
Username = username;
}
public string Username { get; private set; }
public static MyContext CreateFromHttpContext(HttpContext httpContext){
return new MyContext(HttpContext.Current.User.Identity.Name);
}
}
public class MyRep
{
private readonly VtContext _context;
public MyRep(MyContext context)
{
_context = context;
}
... other repository code...
}
then just create a MyContext in your test:
var rep = new MyRep(new MyContext("unittest"));
The question is pretty simple, I'm trying to implement roles into my application, and most if not all places that I go to, tell me to use the following line in the startup.auth:
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
The problem is, Visual studio keeps telling me that ApplicationRoleManager doesn't exist! I already searched for different ways to maybe implement this, but everyone keeps saying "use ApplicationRoleManager", but I can't use it and apparently, I already got the libraries needed for it too.
Any help is very welcome here.
Apparently, my application didn't auto-generate the ApplicationRoleManager code, so i'm trying to add it manually. In IdentityConfig.Cs I have added the following code:
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
}
At this point i'm stuck, because apparently I need other methods (like the create method) to make this work, but I cannot find any example of this code to add.
EDIT I am currently trying to implement a factory to implement the role management. But I'm having problems with VS not detecting certain objects, here's a picture to show it off better:
I have updated my identity packages in nuget, I'm still having problems with the libraries.
You are creating a factory to create the role manager. So the create method is the only method you should implement. But to be honest you don't need either if you don't want. So there are two ways of doing this:
app.CreatePerOwinContext<RoleManager<IdentityRole>>(new RoleManager<IdentityRole>(new RoleStore<IdentityRole, string>(new SomeContext()));
Or you can create a factory to do it for you:
public class RoleManagerFactory
{
private readonly IDbContextFactory<SomeContext> contextFactory
public RoleManagerFactory(IDbContextFactory<SomeContext> contextFactory)
{
this.contextFactory = contextFactory;
}
public RoleManager<IdentityRole> Create()
{
return new RoleManager<IdentityRole>(new RoleStore<IdentityRole, string>(contextFactory.Create()));
}
// If you have already instantiated a context to use, then you can pass it in here
public RoleManager<IdentityRole> Create(SomeContext context)
{
return new RoleManager<IdentityRole>(new RoleStore<IdentityRole, string>(context));
}
}
var factory = new RoleManagerFactory();
app.CreatePerOwinContext<RoleManager<IdentityRole>>(factory.Create());
I believe these ways are easier than what you are trying to do.
EDIT
I added the context factory in, because I remembered you need to pass a context into the role store. So EntityFramework already as a IDbContextFactory<TContext> interface, so you just need to create a concrete implementation and implement the interface, which is another Create method where you return a new context: new SomeContext().
This is what I do in my apps. In fact I use dependency injection and make the role manager be created per request. I use this factory so that I can inject the role manager into my classes:
public interface IRoleManagerFactory
{
RoleManager<IdentityRole> Create();
}
So in my classes I can do this:
public class RoleController : Controller
{
private readonly IRoleManagerFactory roleManagerFactory;
public RoleController (IRoleManagerFactory roleManagerFactory)
{
this.roleManagerFactory = roleManagerFactory;
}
// Create method
public async Task<JsonResult> CreateRole(string role)
{
using (var roleManager = this.roleManagerFactory.Create())
{
var result = await roleManager.CreateAsync(role);
return Json(new { succeeded: result.Succeeded });
}
}
}
EDIT
I have updated the example with correct usage of role manager and db context.
I have implemented my mvc base controller called DefaultController using dependency injection pattern in order to be able to construct test cases. Example below:
public class DefaultController : Controller
{
protected readonly ISessionHelper _sessionHelper;
string _thisUserOpenID;
protected IUsersRepository _UserRepository;
...
public DefaultController()
{ } //not for testing
public DefaultController(ISessionHelper session, IUserRepository repo)
{
_sessionHelper=session;
_UserRepository = repo;
}
}
Then I have my controllers using this controller, homecontroller, usercontroller, etc.
Now, building some test cases I found myself in a situation where I don't know how to actually use the injection dependency pattern.
[TestMethod]
public void Welcome_Message_In_ViewData_Has_Coockie_User_Display_Name()
{
// Below I want to insert FakeRepositories using
//ISessionHelper and so on. but the constructor
//for homecontroller don't have it.
HomeController controller = new HomeController();
Any ideas?
Your HomeController needs to have a matching "injectable" constructor, which would then call the base constructor.
public HomeController(ISessionHelper session, IUserRepository repo)
: base(session, repo)
{
}
Now, in your test, you would create your HomeController using that constructor, and pass in a mocked up session and user repository. Speaking of mocking, you might also be interested in Scott Hanselman's MvcMockHelpers classes, with code for many popular mocking frameworks.
I don't see why you have two constructors. You should only have one, get rid of the constructor with no parameters. Using a DI framework like Castle Windsor, or my preferred one, Autofac will handle all of this for you. Then as far as testing is concerned use something like Moq. Ie
public DefaultController(ISessionHelper session, IUserRepository repo)
{
_sessionHelper = session;
_UserRepository = repo;
}
Register DefaultController, ISessionHelper and IUserRepository with your DI framework. Something along the lines of:
Register(new DefaultController()); (it is something like that in Autofac)
Register<SessionHelper>().As<ISessionHelper>();
Register<UserRepository>().As<IUserRepository>();
That way, you can pull DefaultController from the container and the DI framework will inject the two parameters for you. I wrap up a static method to access my DI container, it looks like:
var controller = IoC.Resolve<DefaultController>();
Basically head over to Autofac and have a look. There's also a web module for registering your Controllers for you.
Then for testing just use Moq, or find some form of "AutoMocker" (google it). I would do:
var session = new Mock<ISessionHelper>();
var repo = new Mock<IUserRepository>();
repo.Setup(s => s.FindById(123)).Returns(new User());
var conroller = new DefaultController(session.Object, repo.Object);
controller.Execute();
Also ewww repositories. With .Net and generics etc... just create yourself an nice ISession.
var session = IoC.Resolve<ISession>();
var user1 = session.Get<User>(123);
var user2 = session.Get<User>(u => u.Username == "admin");
session.Update(user3);
Means you only need to pass in one thing and you can use it for whatever. Rather than having to pass in sometimes many repositories. Also sets you up nicely for the Unit Of Work pattern.