Remove User with using Guid Id from API - asp.net

I have problem when I'm making changes about deleting user. I want to make simple it. I want to find my user on context and delete by using UserManager. But, I have an error:
'Guid'cannot impilicitly convert a 'string'.
But, I check the migrations, Id is Guid ?!
public class Delete
{
public class Command : IRequest
{
public Guid Id { get; set; }
}
public class Handler : IRequestHandler<Command>
{
private readonly DataContext _context;
private readonly UserManager<AppUser> _userManager;
private readonly IdentityResult _identityResult;
public Handler(DataContext context, UserManager<AppUser> userManager, IdentityResult identityResult)
{
_context = context;
_userManager = userManager;
_identityResult = identityResult;
}
public async Task<Unit> Handle(Command request, CancellationToken cancellationToken)
{
var user = await _userManager.FindByIdAsync(request.Id);
var result = await _userManager.DeleteAsync(user);
var success = await _context.SaveChangesAsync() > 0;
if (success) return Unit.Value;
throw new Exception("Problem saving changes");
}
}
}

Related

RoleManager in asp.net core web app working with different tables

I have Four tables (Student, AspNetUsers, AspNetUserRoles and AspNetRoles).
I have three roles (user, Teacher, Admin).
The teacher/Admin creates a user account(fields ie Email, phone, address, role) with the user role and this is saved in the student table. The teacher gives an Email to the student.
The student creates an account with an Email(Created by teacher/Admin) and password and this is saved in the AspNetUsers table.
My Question Is: How to assign a role to the student that is given by the Teacher/Admin in AspNetUserRoles table (UserID and UserRoleId). UserId is in AspNetUsers table and UserRoleId is in student table
public class RolesAdminController : Controller
{
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager;
private ApplicationUserManager _userManager;
public RolesAdminController(ApplicationUserManager userManager,
ApplicationRoleManager roleManager, ApplicationSignInManager signInManager)
{
UserManager = userManager;
RoleManager = roleManager;
SignInManager = signInManager;
}
[HttpPost]
public async Task<IActionResult> Register(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if(ModelState.IsValid){
var user = new IdentityUser{Username = Input.Name, Email = Input.Email};
var result = await _UserManager.CreateAsync(user,Input.Password);
return RedirectToAction("Index");
}
}
I have no idea.. What should I add in my code to do it? Assign a role to the student that should be done while the student Register the account.
Need Help
Here is hoping that you have your startup code wired up correctly to include the AddRoleManager method like so
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Then your code is tweeked a bit since it seems as though you are tring to make the call from an api endpoint instead of an actual web page, hence issues such as redirecting to a return url will be handled by the caller when they assess whether the response from the api call they made succeeded or not. Note also that I use IdentityUser instead of ApplicationUser, but you can swap it out if you are using the later. Anyway, the code should give you a gist of how to implement it in your own project
public class RolesAdminController : ControllerBase
{
private UserManager<IdentityUser> userManager;
private readonly RoleManager<IdentityRole> roleManager;
public RolesAdminController(UserManager<IdentityUser> userManager,
RoleManager<IdentityRole> roleManager)
{
this.userManager = userManager;
this.roleManager = roleManager;
}
[HttpPost]
public async Task<IActionResult> Register(InputDto inputDto)
{
inputDto ??= new InputDto(); // if input is null, create new input
List<string> errors = inputDto.Errors();
if (errors.Any())
{
return BadRequest(errors);
}
var user = new IdentityUser(){ UserName = inputDto.Name, Email = inputDto.Email };
var result = await userManager.CreateAsync(user, inputDto.Password);
if (!result.Succeeded)
{
return BadRequest(result.Errors); //You can turn that errors object into a list of string if you like
}
string roleName = "";
switch (inputDto.RoleType)
{
case RoleType.User:
roleName = "user";
break;
case RoleType.Teacher:
roleName = "Teacher";
break;
case RoleType.Admin:
roleName = "Admin";
break;
default:
break;
}
//Checking if role is in not system
if(!(await roleManager.RoleExistsAsync(roleName)))
{
await roleManager.CreateAsync(new IdentityRole(roleName));
}
await userManager.AddToRoleAsync(user, roleName);
return Ok(); //Or you can return Created(uriToTheCreatedResource);
}
}
public class InputDto
{
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public RoleType RoleType { get; set; }
public List<string> Errors()
{
List<string> vtr = new List<string>();
if (String.IsNullOrWhiteSpace(Name))
{
vtr.Add("Name Cannot be null");
}
if (String.IsNullOrWhiteSpace(Email))
{
vtr.Add("Email Cannot be null");
}
//Do the rest of your validation
return vtr;
}
}
public enum RoleType
{
User, Teacher, Admin
}

Asp.Net Mocking a Repository that returns a DbSet with .GetAll().ToListAsync()

In my ASP.Net application I have a controller I'd like to unit test. Here's some relevant code:
public class UserController : Controller
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly IUserRepository _userRepository;
public UserController(IUserRepository repo, UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
{
_userRepository = repo;
_userManager = userManager;
_signInManager = signInManager;
}
public async Task<IActionResult> Index()
{
return View(await _userRepository.GetAll().ToListAsync());
}
I want to test the Index()-method, so I create a DummyDbContext using https://github.com/romantitov/MockQueryable to help mock the repository.
Relevant code:
public class DummyDbContext
{
private ICollection<User> _users;
public Mock<DbSet<User>> _dbsetUsers
{
get
{
return _users.AsQueryable().BuildMockDbSet();
}
}
public DummyDbContext()
{
_users= new List<User>();
_users.Add(new User("Alan"));
_users.Add(new User("Claire"));
_users.Add(new User("Paul"));
_users.Add(new User("John"));
}
In my test-class I proceed as follows:
public class UserControllerTest
{
private readonly DummyDbContext _context;
private readonly Mock<UserManager<IdentityUser>> _userManager;
private readonly Mock<SignInManager<IdentityUser>> _signInManager;
private readonly Mock<IUserRepository> _userRepository;
private readonly UserController _controller;
public UserControllerTest()
{
_context = new DummyDbContext();
_userManager = new Mock<UserManager<IdentityUser>>(
new Mock<IUserStore<IdentityUser>>().Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<IPasswordHasher<IdentityUser>>().Object,
new IUserValidator<IdentityUser>[0],
new IPasswordValidator<IdentityUser>[0],
new Mock<ILookupNormalizer>().Object,
new Mock<IdentityErrorDescriber>().Object,
new Mock<IServiceProvider>().Object,
new Mock<ILogger<UserManager<IdentityUser>>>().Object);
_signInManager = new Mock<SignInManager<IdentityUser>>(
_userManager.Object,
new Mock<IHttpContextAccessor>().Object,
new Mock<IUserClaimsPrincipalFactory<IdentityUser>>().Object,
new Mock<IOptions<IdentityOptions>>().Object,
new Mock<ILogger<SignInManager<IdentityUser>>>().Object,
new Mock<IAuthenticationSchemeProvider>().Object);
_userRepository = new Mock<IUserRepository>();
_controller = new UserController(_userRepository.Object, _userManager.Object, _signInManager.Object);
}
[Fact]
public async void Index_GetModelContainingAllUsers()
{
_userRepository.Setup(g => g.GetAll()).Returns(_context._dbsetUsers.Object);
var actionResult = await _controller.Index() as Task<ViewResult>;
var usersResult = actionResult?.Result?.Model as IEnumerable<User>;
foreach (var g in usersResult) {
Console.WriteLine(g.Username);
}
Assert.Equal(4, usersResult.Count());
}
Now, the problem is that usersResult is null. And I can't figure out why; have I done something wrong doing the setup for userRepository?
Frankly, I feel like I'm doing something wrong having to write all of this code just for something that should be a simple mock.
I managed to solve my own problem.
The issue was that I was casting the result of _controller.Index() as Task whereas I should have been casting it as ViewResult instead. When the Task is complete ("await"), I receive a ViewResult that gets assigned to actionResult. By casting it as Task I was getting null.
Here's what it should have read:
[Fact]
public async void Index_GetModelContainingAllUsers()
{
_userRepository.Setup(g => g.GetAll()).Returns(_context._dbsetUsers.Object);
var actionResult = await _controller.Index() as ViewResult;
var usersResult = actionResult?.Model as IEnumerable<User>;
Assert.Equal(4, usersResult.Count());
}

Cannot convert from int to Project.Models.ApplicationUser

The below code gets me the error.
_userManager.AddToRoleAsync(_userManager.FindByNameAsync(user.UserName).Id, "Employee");
I have included the code for further reference. I am trying to create a new user everytime the site is accessed and add a default role. User is properly added. Also I have previously seeded the roles, so roles exist.
public class ItemsController : Controller
{
private readonly MainContext _context;
private readonly OtherContext _orcontext;
private readonly IHostingEnvironment _appenv;
private readonly UserManager<ApplicationUser> _userManager;
}
public ItemsController(MainContext context, OtherContext _orcontext, IHostingEnvironment appEnvironment, UserManager<ApplicationUser> userManager)
{
_context = context;
_orcontext= orcontext;
_appenv = appEnvironment;
_userManager = userManager;
}
// GET: Items
public async Task<IActionResult> Index()
{
var uname = User.Identity.Name.Remove(0, 5);
if ((await _userManager.FindByNameAsync(uname)) == null)
{
ApplicationUser user = new ApplicationUser
{
UserName = uname
};
IdentityResult result = await _userManager.CreateAsync(user);
_userManager.AddToRoleAsync(_userManager.FindByNameAsync(user.UserName).Id, "Employee");
}
The first parameter to AddToRoleAsync is a user instance, not an id. Hence the error. In other words, remove the .Id bit.
_userManager.AddToRoleAsync(_userManager.FindByNameAsync(user.UserName), "Employee");

Store additional info when creating new user in IdentityStore in web api

I am building/learning token based authentication with OWIN and I would like to figure out how to insert additional information when creating a new user. The UserManager accepts IdentityUser, but the CreateAsync method only accepts a user name and passowrd. I would like to add at least the email address. I see that there is a SetEmailAsync method, but that requires a second call. I feel like there should be a single call that allows me to insert other columns, but I am not finding any documentation of how to do this, nor closely related questions in StackOverflow.
Here is the save routine:
public class AuthRepository : IDisposable
{
private readonly AuthContext _context;
private readonly UserManager<IdentityUser> _userManager;
public AuthRepository()
{
_context = new AuthContext();
_userManager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(_context));
}
public async Task<IdentityUser> FindUserAsync(string userName, string password)
{
IdentityUser user = await _userManager.FindAsync(userName, password);
return user;
}
public async Task<IdentityResult> RegisterUserAsync(UserModel userModel)
{
var user = new IdentityUser
{
UserName = userModel.UserName
};
//save all of this in one call?
var result = await _userManager.CreateAsync(user, userModel.Password);
var result1 = await _userManager.SetEmailAsync(userModel.UserName, userModel.EmailAddress);
return result;
}
public async Task<IdentityUser> FindIdentityUserAsync(string userName, string password)
{
var user = await _userManager.FindAsync(userName, password);
return user;
}
public void Dispose()
{
_context.Dispose();
_userManager.Dispose();
}
}
you can create your own User class by inheriting IdentityUser class.
public class User : IdentityUser
{
public string Email { get; set; }
}
var user = new User
{
UserName = userModel.UserName,
Email = userModel.EmailAddress
};
var result = await _userManager.CreateAsync(user, userModel.Password);
Make sure you are using User Class instead of IdentityUser.

How to get User Name from External Login in ASP.NET Core?

I have set up an external login (Google) in my ASP.NET Core application. I am finding it hard to get the User Name / Email after login. I can see the email stored in AspNetUsers table But I don't see User Name anywhere.
I searched over and found this code:
var userId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
But this is giving me userId as is present in table AspNetUsers. ClaimTypes.Email returns null but the value is present in table (probably this email is something else). I want to fetch User Name and User Email. Is it possible?
Do you have access to SignInManager or can you inject it? If yes, then this is how you would access user id (username), email, first & last name:
public class MyController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
public MyController (
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager
)
{
_userManager = userManager;
_signInManager = signInManager;
}
public async Task<IActionResult> MyAction(){
ExternalLoginInfo info = await _signInManager.GetExternalLoginInfoAsync();
string userId = info.Principal.GetUserId()
string email = info.Principal.FindFirstValue(ClaimTypes.Email);
string FirstName = info.Principal.FindFirstValue(ClaimTypes.GivenName) ?? info.Principal.FindFirstValue(ClaimTypes.Name);
string LastName = info.Principal.FindFirstValue(ClaimTypes.Surname);
}
}
GetUserId extension:
public static class ClaimsPrincipalExtensions
{
public static string GetUserId(this ClaimsPrincipal principal)
{
if (principal == null)
return null; //throw new ArgumentNullException(nameof(principal));
string ret = "";
try
{
ret = principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
}
catch (System.Exception)
{
}
return ret;
}
}

Resources