Cannot convert from int to Project.Models.ApplicationUser - asp.net

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");

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 Core DI unable to resolve service for type

I am creating an application using ASP.NET Core. In which I have created a custom ApplicationUserManager along with a couple of services. Also, I am using SAAS Kit for multitenancy. But I am stuck with an error which says unable to resolve service.
Previously It was all working fine but all of a sudden after some change this error occurred. Here is my code:
AppTenantResolver For Multi-Tenancy
public class AppTenantResolver : MemoryCacheTenantResolver<TenantEditModel>
{
private readonly ApplicationUserManager _userManager;
private readonly TenantService _tenantService;
private readonly IMapper _mapper;
public AppTenantResolver(
IMapper mapper,
TenantService tenantService,
ApplicationUserManager userManager,
IMemoryCache cache,
ILoggerFactory loggerFactory
) : base(cache, loggerFactory)
{
_userManager = userManager;
_mapper = mapper;
_tenantService = tenantService;
}
protected override string GetContextIdentifier(
HttpContext context)
{
return context.Request.Host.Value.ToLower();
}
protected override IEnumerable<string> GetTenantIdentifiers(
TenantContext<TenantEditModel> context)
{
return new[] { "localhost:44321" };
}
protected override async Task<TenantContext<TenantEditModel>> ResolveAsync(
HttpContext context)
{
TenantContext<TenantEditModel> tenantContext = null;
var host = context.Request.Host.Value.ToLower();
if (context.User.Identity.IsAuthenticated && context.User.IsInRole("Admin"))
{
var user = await _userManager.GetUserAsync(context.User);
var tenant = await _tenantService.GetByIdAsync(user.TenantId);
if (tenant != null)
{
tenantContext = new TenantContext<TenantEditModel>(
_mapper.Map<TenantEditModel>(tenant));
return tenantContext;
}
}
return new TenantContext<TenantEditModel>(new TenantEditModel());
}
}
StudentService:
public class StudentService
{
private readonly IMapper _mapper;
private readonly CourseService _courseService;
private readonly IStudentRepository _studentRepository;
private readonly IUnitOfWork _unitOfWork;
public StudentService(
IMapper mapper,
IStudentRepository studentRepository,
IUnitOfWork unitOfWork,
CourseService courseService)
{
_studentRepository = studentRepository;
_mapper = mapper;
_unitOfWork = unitOfWork;
_courseService = courseService;
}
public async Task CreateAsync(MongoIdentityUser user)
{
try
{
var student = _mapper.Map<Student>(user);
_unitOfWork.Students.Add(student);
await _unitOfWork.CommitAsync();
}
catch (Exception ex)
{
throw ex;
}
}
}
CourseService:
public class CourseService
{
private readonly IFileUploadProcessor _fileUploadProcessor;
private readonly IAppConfiguration _appConfiguration;
private readonly IUnitOfWork _unitOfWork;
private readonly ITenantRepository _tenantRepository;
private readonly TenantEditModel _tenant;
private readonly IMapper _mapper;
public CourseService(
IUnitOfWork unitOfWork,
ITenantRepository tenantRepository,
TenantEditModel tenant,
IMapper mapper,
IAppConfiguration appConfiguration,
IFileUploadProcessor fileUploadProcessor)
{
_unitOfWork = unitOfWork;
_tenantRepository = tenantRepository;
_tenant = tenant;
_mapper = mapper;
_fileUploadProcessor = fileUploadProcessor;
_appConfiguration = appConfiguration;
}
public async Task<List<CourseListModel>> GetAllAsync()
{
var tenant = await _unitOfWork.Tenants.GetByIdAsync(_tenant.Id);
return _mapper.Map<List<CourseListModel>>(tenant.Courses);
}
}
The error only occurred when I inject CourseService in StudentService why? As soon as I remove CourseService from StudentService code works fine.

Remove User with using Guid Id from API

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");
}
}
}

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());
}

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