I have a controller action which i am performing some work on (example below)
public ActionResult Dashboard()
{
// Redirect back to login page if not authenticated
if (!this.HttpContext.User.Identity.IsAuthenticated)
{
return this.RedirectToAction(string.Empty, "Account");
}
this.ApplicationDbContext = new ApplicationDbContext();
this.UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(this.ApplicationDbContext));
var user = this.UserManager.FindById(this.User.Identity.GetUserId());
MyRitualDashboardData model = new MyRitualDashboardData();
Member member = db.Members.Single(m => m.AspNetUserId == user.Id);
model.Gravatar = string.Format("<img src='{0}' class='gravatar img-circle'/>", user.PhotoUrl);
model.UserMember = member;
model.UserHomeLocation = member.getUserHomeLocation();
model.UserActiveMembership = member.getActiveMembership();
model.UserPastMemberships = member.getExpiredMemberships();
model.UserPayments = member.getUserPayments();
model.UserStatistics = member.GetMembershipStatistics();
if (model.UserActiveMembership != null)
{
model.DaysTillMembershipExpiry = member.getActiveMembership().daysTillExpiry();
}
return this.View(model);
}
If i run this code and perform some changes to the database with some other actions then when i refresh my dashboard the various updates that i am making to the member profile is fine.
If however i try to re-factor my code and place the above code into a seperate class and use a static method to do the call like so:
public ActionResult Dashboard()
{
// Redirect back to login page if not authenticated
if (!this.HttpContext.User.Identity.IsAuthenticated)
{
return this.RedirectToAction(string.Empty, "Account");
}
this.ApplicationDbContext = new ApplicationDbContext();
this.UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(this.ApplicationDbContext));
var user = this.UserManager.FindById(this.User.Identity.GetUserId());
MyRitualDashboardData model = new MyRitualDashboardData();
model = MyRitualService.GetModelForMyRitual(user);
return this.View(model);
}
and have a method in a seperate class like so:
public static MyRitualDashboardData GetModelForMyRitual(ApplicationUser user)
{
MyRitualDashboardData model = new MyRitualDashboardData();
Member member = db.Members.Single(m => m.AspNetUserId == user.Id);
model.Gravatar = string.Format("<img src='{0}' class='gravatar img-circle'/>", user.PhotoUrl);
model.UserMember = member;
model.UserHomeLocation = member.getUserHomeLocation();
model.UserActiveMembership = member.getActiveMembership();
model.UserPastMemberships = member.getExpiredMemberships();
model.UserPayments = member.getUserPayments();
model.UserStatistics = member.GetMembershipStatistics();
if (model.UserActiveMembership != null)
{
model.DaysTillMembershipExpiry = member.getActiveMembership().daysTillExpiry();
}
return model;
}
Then it is using cached data from the database and i do not know why? Why would the same code called inline in the action be fine but when called from a seperate static function that it caches the data.
Any clues would be great.
Thanks
Both versions have the line
Member member = db.Members.Single(m => m.AspNetUserId == user.Id);
but since this is now in 2 different classes it must also be 2 different dbs.
The second one is static and will live longer (ie never refresh).
Avoid static. The separation in 2 classes is a good idea but just make instances.
Follow naming standards so that properties are easier to recognize.
Related
I have a test that looks like this.
namespace Domain.Tests.Unit.Features.ForUser.Auth
{
[TestClass]
public class LoginHandlerTests
{
[TestMethod]
public async Task Should_Succeede_With_Valid_User()
{
// Arrange
var loginCommand = new LoginHandler.LoginCommand
{
Email = "testemail",
Password = "testpassword"
};
var user = new User
{
Email = loginCommand.Email,
UserName = "testname",
};
var userServiceMock = new UserServiceFixture()
.WithSucceededFindByEmailAsync(loginCommand.Email)
.WithSucceededGetRolesAsync(user)
.GetMock();
// Problematic MOCK
var result = new Mock<ISignInServiceResult>()
.SetupProperty(l => l.Succeeded, true);
var signInServiceMock = new Mock<ISignInService>();
signInServiceMock.Setup(l => l.CheckPasswordSignInAsync(user, loginCommand.Password))
.Returns(Task.FromResult(result.Object));
var jwtGeneratorServiceMock = new JwtGeneratorServiceFixture()
.WithSucceededGeneration(loginCommand.Email, new string[] { "User" })
.GetMock();
// Here the result is what i expect
//var result1 = await signInServiceMock.Object.CheckPasswordSignInAsync(user, loginCommand.Password);
// Act
var sut = new LoginHandler.Handler(
userServiceMock.Object,
signInServiceMock.Object,
jwtGeneratorServiceMock.Object
);
var loginResponse = await sut.Handle(loginCommand, new CancellationToken());
// Assert
loginResponse.Should().NotBeNull();
loginResponse.Success.Should().BeTrue();
loginResponse.Token.Should().NotBeEmpty();
loginResponse.RefreshToken.Should().NotBeEmpty();
The only problem is that signInServiceMock returns null when the method is called on my handler. If I call it directly on my test i recieve the expected result. But when its called on my handler it always returns null.
I have checked the setup method and the params needed, all seems correct. Any idea? Thanks
The handler is this:
public class Handler : IRequestHandler<LoginCommand, LoginResponse>
{
private readonly IUserService _userService;
private readonly ISignInService _signInService;
private readonly IJwtGeneratorService _jwtGeneratorService;
public Handler(IUserService userService, ISignInService signInService, IJwtGeneratorService jwtGeneratorService)
{
_userService = userService;
_signInService = signInService;
_jwtGeneratorService = jwtGeneratorService;
}
public async Task<LoginResponse> Handle(LoginCommand command, CancellationToken _cancellationToken)
{
var user = await _userService.FindByEmailAsync(command.Email);
if (user is null) throw new InvalidLoginCredentialsException();
ISignInServiceResult checkedPassword
= await _signInService.CheckPasswordSignInAsync(user, command.Password);
if (!checkedPassword.Succeeded) throw new InvalidLoginCredentialsException();
var roles = await _userService.GetRolesAsync(user);
if (roles is null)
throw new UnableToGetRolesException();
ITokenData? token = _jwtGeneratorService.Generate(user.Email, roles);
if (token is null)
throw new LoginTokenGenerationException();
return new LoginResponse
{
Success = true,
Token = token.Token,
RefreshToken = token.RefreshToken
};
}
}
The problem is that your mock setup is not correctly aligned with how your Handler internally uses it.
In your setup you have this:
var user = new User
{
Email = loginCommand.Email,
UserName = "testname",
};
signInServiceMock.Setup(l => l.CheckPasswordSignInAsync(user, loginCommand.Password))
.Returns(Task.FromResult(result.Object));
That instructs the mock to return the desired result only upon receiving this exact user instance, while internally in your Handler you're creating another User instance and passing it to the mocked method as follows:
// new User is being created:
var user = await _userService.FindByEmailAsync(command.Email);
// No longer matches your setup:
await _signInService.CheckPasswordSignInAsync(user, command.Password);
Perhaps you meant this, instead:
signInServiceMock.Setup(l => l.CheckPasswordSignInAsync(It.IsAny<User>(), loginCommand.Password))
Update:
Actually, the real problem probably lies in a missing setup of your UserService mock.
Although you're calling .WithSucceededGetRolesAsync(user), I believe it doesn't affect the eventual call to FindByEmailAsync(user).
All in all, you have to make sure the call to FindByEmailAsync(user) would indeed return the same user instance in your setup.
I believe what you want is:
signInServiceMock.Setup(l => l.CheckPasswordSignInAsync(user, loginCommand.Password))
.ReturnsAsync((User user, string password) => { return result.Object; });
rather than Returns with a Task<T>. Other than that, the code calling the CheckPasswordSignInAsync method may be passing a different argument value than your Mock is configured with, such as a Hash for the password. You can set a breakpoint and inspect that the values passed in actually match what your test configured.
Normally with Mocks you would configure to expect It.IsAny and assert the values using means like:
signInServiceMock.Setup(l => l.CheckPasswordSignInAsync(It.IsAny<User>(), It.IsAny<string>()))
.ReturnsAsync((User user, string password) => { return result.Object; });
from here the Returns will received the passed in values if it needs to perform any simple computation to mock out, or you can verify, such as that the user and password passed matched via:
signInServiceMock.Verify(l => l.CheckPasswordSignInAsync(It.Is<User>(u => u.EMail == "testemail"), It.Is<string>(p => p == "testpassword"));
This would at least fail with some description that the method was called, but the expected parameters didn't match.
I'm using C#, ASP.NET MVC and .NET 4.5. I have a test controller which only I can access, basically I want to be able to create test users of say 500 at a time and insert these into my aspnetusers table, this is on my test environment.
In my controller I have this:
RegisterViewModel model = new RegisterViewModel();
var s = Guid.NewGuid().ToString();
model.AccountType = accountType;
model.Email = s + "#email.com";
model.Password = s;
model.ConfirmPassword = s;
var result = new AccountController().Register(model);
This goes off to the standard register controller:
public async Task<ActionResult> Register(RegisterViewModel model)
However, it won't register a user? It goes wrong at the CreateAsync part:
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, AccountType = model.AccountType };
var result = await UserManager.CreateAsync(user, model.Password);
I have seen others mention about "seeding" this at the start but I don't want to do this, I've have loads of data I need to automate/add in once the user is in the system, so need to loop over each user entered then insert a load more data. I don't want to have to create an account for each manually and then have to add in all the other details in all the other tables also.
Surely there is a simple way to do this that somebody knows?..
make your non-sync function like that...
public class TestController : Controller
{
ApplicationDbContext db = new ApplicationDbContext();
// GET: Test
public ActionResult Index()
{
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
string s = "User!1Nom"; // must contain special char if you use asp.net identity default validation
for (int i = 1; i < 501; i++)
{
s = s + i;
var user = new ApplicationUser { UserName = s, Email = s+"#gmail.com" };
var result = userManager.Create(user, s);
}
return View();
}
}
I'm testing some code which needs user to be logged in. When I'm trying to log in with AccountController, it's looks like everything is working, but at AccountController (IPrincipal) User is still null. How can I properly log in (or better, can I mock it somehow)?
public async Task SetupAsync()
{
var context = new DataContext();
var manager = new UserManager(new UserStore(context));
var accountController = new AccountController(manager);
var mockAuthenticationManager = new Mock<IAuthenticationManager>();
mockAuthenticationManager.Setup(am => am.SignOut());
mockAuthenticationManager.Setup(am => am.SignIn());
accountController.AuthenticationManager = mockAuthenticationManager.Object;
var user = new LoginViewModel
{
Email = "user#wp.pl",
Password = "useruser",
RememberMe = false
};
if (manager.FindByEmail("user#wp.pl") == null)
{
await manager.CreateAsync(new User { Email = "user#wp.pl", UserName = "user#wp.pl" }, "useruser");
}
await accountController.Login(user, "home/index");
_calendarController = new CalendarController(context);
}
Here I got User null exception:
public ClaimsPrincipal CurrentUser
{
get { return new ClaimsPrincipal((System.Security.Claims.ClaimsPrincipal)this.User); }
}
Edit: At return line, I have still User property null. This is sample from AccountController:
var user = await _userManager.FindAsync(model.Email, model.Password);
if (user != null)
{
await SignInAsync(user, model.RememberMe);
return RedirectToAction("index", "calendar");
}
You should mock your _userManager, and use a mock setup for when the method FindAsync is called. Then you return a fake user you can use later in the code
Figured it out on my own, probably not elegant solution but I'm happy anyway. #andreasnico your answer helped, thanks.
I'm mocking my custom ClaimsPrincipal, and setting up UserId - that's what I really needed.
var mockCp = new Mock<IClaimsPrincipal>();
mockCp.SetupGet(cp => cp.UserId).Returns(user.Id);
_calendarController.CurrentUser = mockCp.Object;
I have the following SpecFlow scenario:
[When(#"the registration is submitted")]
public void WhenTheRegistrationIsSubmitted()
{
//var controller = _kernel.Get<AccountController>();
var factory = new HockeyDbContextFactory();
var userRepository = new Repository<User>(factory);
var cryptoService = new CryptoService();
var roleRepository = new Repository<Role>(factory);
var playerService = new Mock<IPlayerService>();
var leagueService = new Mock<ILeagueService>();
var userService = new UserService(userRepository, cryptoService, roleRepository);
var controller = new AccountController(userService, playerService.Object, leagueService.Object);
controller.Register(_registerModel);
}
Which eventually calls the following method through my controller:
public void RegisterUser(User user)
{
var salt = _cryptoService.GenerateSalt();
var hasedPassword = _cryptoService.HashPassword(user.Password, salt);
user.PasswordSalt = salt;
user.Password = hasedPassword;
var defaultRole = _roleRepository.GetAll().Single(x => x.RoleName == "User");
user.Roles.Add(defaultRole);
Insert(user);
}
All of my database calls are fine until I get to this line:
var defaultRole = _roleRepository.GetAll().Single(x => x.RoleName == "User");
When I breakpoint on that line and inspect the call to GetAll(), I have context and I can view the query. The exception occurs on the call to Single(). Now, if I stick a .Include(x => x.Users) on the call to GetAll(), I'm fine. This tells me it has something to do with lazy-loading.
The error i get is: error: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
When RegisterUser is called from my web application, I'm fine. When RegisterUser is called from my specification test, it fails. Does anyone have some incite?
UPDATE:
To add a little more information, here is the controller action being called:
[HttpPost]
[AllowAnonymous]
public ActionResult Register(RegisterModel model)
{
if (!_userService.EmailIsUnique(model.EmailAddress))
ModelState.AddModelError("EmailAddress", "Email Address is already in use.");
if (!_userService.UserNameIsUnique(model.UserName))
ModelState.AddModelError("UserName", "User Name is already in use");
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
var user = Mapper.Map<User>(model);
_userService.RegisterUser(user);
FormsAuthentication.SetAuthCookie(model.UserName, false);
return View("RegisterSuccess");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
stepping through the code, I never make it to FormsAuthentication.SetAuthCookie(model.UserName, false);
I figured out what the issue was. I was seeding my test database with this step:
[BeforeFeature]
public static void BeforeFeature()
{
MappingConfig.RegisterMappings();
Database.SetInitializer(new TestDatabaseInitializer());
}
The context in my TestDatabaseInitializer must have been conflicting with the context I created in my scenario. Thanks for the comment Gert, it gave me the idea to take a closer look at what was going on in the rest of my scenario.
I'm developing a web app based on Orchard.
I'm coding a module that manages Staff Users, this users are ContentTypes(Staff_User) composed of UserPart and StaffUserPart (Custom part, defined in a migration) -> this part has a MediaPickerField.
This is the code in my controller to show the creation template of a staff users
public ActionResult CreateStaff() {
IContent staffUser = _contentManager.New("Staff_User");
var model = _contentManager.BuildEditor(staffUser);
return View((object)model);
}
Ok, I have a template in EditorTemplates/Staff.cshtml . The MediaPicker field is attached by the the BuildEditor function (as a shape).
This is the Post controller:
public ActionResult CreateStaffPost(FormCollection input) {
IContent staffUser = _contentManager.New("Staff_User");
//UserPart validation
if (String.IsNullOrEmpty(input["user.Email"]))
ModelState.AddModelError("Email", "The Email field is required.");
//Check if user already exits
var oldUser = _contentManager.Query("User").Where<UserPartRecord>(x => x.Email == input["user.Email"])
.List()
.FirstOrDefault();
if (oldUser != null)
ModelState.AddModelError("Email", "That email adress is already registered.");
if (!ModelState.IsValid) {
var model = _contentManager.UpdateEditor(staffUser, this);
return View(model);
}
StaffUserPart staff = staffUser.As<StaffUserPart>();
staff.FirstName = input["FirstName"];
staff.LastName = input["LastName"];
staff.Location = input["Location"];
staff.JobTitle = input["JobTitle"];
staff.Summary = input["Summary"];
staff.AreaOfExpertise = input["AreaOfExperience"];
staff.Category = input["Category"];
staff.Experience = input["Experience"];
//Media picker field values
var staffImageField = (MediaPickerField)staff.Fields.Single(x => x.Name == "Photo");
//TODO Fix image save during creation
staffImageField.Url = input["StaffUserPart.Photo.Url"];
staffImageField.AlternateText = input["StaffUserPart.Photo.AlternateText"];
staffImageField.Class = input["StaffUserPart.Photo.Class"];
staffImageField.Style = input["StaffUserPart.Photo.Style"];
staffImageField.Alignment = input["StaffUserPart.Photo.Alignment"];
staffImageField.Width = String.IsNullOrEmpty(input["StaffUserPart.Photo.Width"]) ? 0 : Convert.ToInt32(input["StaffUserPart.Photo.Width"]);
staffImageField.Height = String.IsNullOrEmpty(input["StaffUserPart.Photo.Height"]) ? 0 : Convert.ToInt32(input["StaffUserPart.Photo.Height"]);
UserPart userPart = staffUser.As<UserPart>();
userPart.UserName = input["user.Email"];
userPart.Email = input["user.Email"];
userPart.NormalizedUserName = input["user.Email"].ToLowerInvariant();
userPart.Record.HashAlgorithm = "SHA1";
userPart.RegistrationStatus = UserStatus.Approved;
userPart.EmailStatus = UserStatus.Approved;
//Set Password
_membershipService.SetPassword(userPart.As<UserPart>(), input["password"]);
//Create the StaffUser
_contentManager.Create(staffUser);
return RedirectToAction("Index");
}
Question
This works but the MediaPickerField doesn;t save the data. I use the debugger to see if the values from input["StaffUserPart.Photo"] and the values are there.
Any ideas?
It looks like you're doing more work than you need to. If you move your call to UpdateEditor, this method will do the work of putting posted values into your content. You'll need to make sure you're implementing IUpdater. Also, I added a dependency on ITransactionManager. I'm hoping this will help catch something not getting put in the right spot.
public ActionResult CreateStaffPost(FormCollection input) {
IContent staffUser = _contentManager.New("Staff_User");
//Create the StaffUser
_contentManager.Create(staffUser);
//UserPart validation
if (String.IsNullOrEmpty(input["user.Email"]))
ModelState.AddModelError("Email", "The Email field is required.");
//Check if user already exits
var oldUser = _contentManager.Query("User").Where<UserPartRecord>(x => x.Email == input["user.Email"])
.List()
.FirstOrDefault();
if (oldUser != null)
ModelState.AddModelError("Email", "That email adress is already registered.");
//This does all the work of hydrating your model
var model = _contentManager.UpdateEditor(staffUser, this);
if (!ModelState.IsValid) {
_transactionManager.Cancel();
return View(model);
}
//Set Password
_membershipService.SetPassword(userPart.As<UserPart>(), input["password"]);
return RedirectToAction("Index");
}