How to get all user with the associate organization? - asp.net-core

Its keep a week that I'm trying to figure this out. I hope to get help from community. Here is a scenario:
I have a entity class called "Company". One company has many users (One-To-Many)
public class User : IdentityUser<int>
{
public User()
{
Company = new Company();
}
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime CreatedDate { get; set; } = DateTime.Now;
public virtual ICollection<UserRole> UserRoles { get; set; }
public virtual Company Company { get; set; }
public int CompanyId { get; set; }
}
I also have a company entity like so.
public class Company
{
public Company()
{
Users = new List<User>();
}
public int CompanyId { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Company Name")]
public string CompanyName { get; set; }
public virtual List<User> Users { get; set; }
}
Now, I can add new company but I cannot add users.
Here is my Controller/Create
[HttpGet]
public IActionResult Create(int companyId)
{
ViewData["UserList"] = new SelectList(_context.Companies, "CompanyId", "CompanyName", companyId);
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(RegisterViewModel viewModel)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(viewModel.UserName);
if (user == null)
{
user = new User
{
UserName = viewModel.UserName,
FirstName = viewModel.FirstName,
LastName = viewModel.LastName,
Email = viewModel.UserName,
PhoneNumber = viewModel.PhoneNumber
};
var result = await _userManager.CreateAsync(user, viewModel.Password);
if (result.Succeeded)
{
RedirectToAction(nameof(Index));
}
else
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
return View();
}
}
return View("Success");
}
ViewData["CompanyId"] = new SelectList(_context.Companies, "Id", "Id", viewModel.CompanyId);
return View();
}
When i run the program and enter data in a POST/Form,
if (ModelState.IsValid)
{
Model.IsValid is always return false. and it ask to enter Company information which i don't want it because i already have company data. I all was trying to do is have Foreign Id linked with user.
Since Identity already have built in function like
var users = await _userManager.GetUserAsync(viewModel.UserName);
How to i also query like Include in GetUserAsync method?

Related

ASP.NET Core Web API - How to display users with respective role

I am implementing ASP.NET Identity in ASP.NET Core-6 Web API
Entities:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<ApplicationUserRole> UserRoles { get; set; }
}
public class ApplicationRole : IdentityRole
{
public ICollection<ApplicationUserRole> UserRoles { get; set; }
}
public class ApplicationUserRole : IdentityUserRole<string>
{
public virtual ApplicationUser User { get; set; }
public virtual ApplicationRole Role { get; set; }
}
Then I have this DTOs:
public class AllRoleListDto
{
public string Id { get; set; }
public string Name { get; set; }
}
public class AllUserListDto
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Fullname
{
get { return FirstName + " " + LastName; }
}
}
I did the Mapping using AutoMapper as shown below:
public class AdminMapperProfile: Profile
{
public AdminMapperProfile()
{
CreateMap<ApplicationUser, AllUserListDto>().ReverseMap();
CreateMap<ApplicationRole, AllRoleListDto>().ReverseMap();
}
}
I want to display all the users with there respective roles using:
public async Task<PagedResponse<AllUserListDto>> GetAllUserAsync(int page, int limit)
{
var response = new PagedResponse<AllUserListDto>();
try
{
if (page >= 1 && limit >= 1)
{
var userQueryable = _context.ApplicationUsers.AsQueryable();
var pagedUsers = await userQueryable.ToPagedListAsync(page, limit);
response.Result = _mapper.Map<List<AllUserListDto>>(pagedUsers.ToList());
response.TotalPages = pagedUsers.PageCount;
response.Page = pagedUsers.PageNumber;
response.PerPage = pagedUsers.PageSize;
}
else
{
response.Error = new ErrorResponseDto()
{
ErrorCode = 400,
Message = "The page number and page size must be greater than 1!"
};
}
}
catch (Exception ex)
{
response.Error = new ErrorResponseDto()
{
ErrorCode = 500,
Message = ex.Message
};
}
return response;
}
What I have above only get all the users without the roles.
How do I get all the users with their respective roles as shown below?
UserName | FirstName | LastName | Role
Thanks
You can use _userManager.GetRolesAsync(user) to get the respective roles, here is a simple demo( I have used MVC here to demonstrate it more clearly):
First, Create a viewModel
public class UserRole
{
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public List<string> roles { get; set; } = new List<string>();
}
Then in controller:
public class RegisterController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<ApplicationRole> _roleManager;
public RegisterController(UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
public async Task<IActionResult> show()
{
List<UserRole> userRoles = new List<UserRole>();
//get all users
var user = _userManager.Users.ToList();
foreach (var item in user)
{
UserRole userRole = new UserRole();
userRole.UserName = item.UserName;
userRole.FirstName = item.FirstName;
userRole.LastName = item.LastName;
userRole.Email = item.Email;
//get the user's roles
var roles = await _userManager.GetRolesAsync(item);
foreach (var roleName in roles)
{
userRole.roles.Add(roleName);
}
userRoles.Add(userRole);
}
return View(userRoles);
}
}
View:
#model List<UserRole>
#foreach (var item in Model)
{
<h2>#item.UserName</h2>
<h2>#item.FirstName</h2>
<h2>#item.LastName</h2>
<h2>#item.Email</h2>
#foreach (var role in item.roles)
{
<h3>#role</h3>
}
<h1>==================================</h1>
}
Demo:

Can i add a parent record and a child record using the same _context.SaveChangesAsync()

I have the following 2 Parent/Child objects:-
public Submission()
{
SubmissionQuestionSubmission = new HashSet<SubmissionQuestionSubmission>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Npi { get; set; }
public bool Independent { get; set; }
public string Comment { get; set; }
public virtual ICollection<SubmissionQuestionSubmission> SubmissionQuestionSubmission { get; set; }
}
public partial class SubmissionQuestionSubmission
{
public int SubmissionQuestionId { get; set; }
public int SubmissionId { get; set; }
public string Answer { get; set; }
public virtual Submission Submission { get; set; }
}
and i created the following view model:-
public class SubmissionCreate
{
public Submission Submission {set; get;}
public IList<SubmissionQuestion> SubmissionQuestion { set; get; }
public IList<SubmissionQuestionSubmission> SubmissionQuestionSubmission { set; get; }
}
where i have the following action method to add a parent record (submission) and a child record (SubmissionQuestionSubmission ), but to do so, i have to issue 2 save requests to the database, one to save the parent and get its ID, while the other to save the child record and assign it the parent ID, as follow:-
public async Task<IActionResult> Create(SubmissionCreate sc)//Bind("Id,FirstName,LastName,Npi,Independent,Comment")]
{
if (ModelState.IsValid)
{
var newsubmission = _context.Submission.Add(sc.Submission);
await _context.SaveChangesAsync();
foreach (var v in sc.SubmissionQuestionSubmission)
{
v.SubmissionId = sc.Submission.Id;
_context.SubmissionQuestionSubmission.Add(v);
}
await _context.SaveChangesAsync();
TempData["message"] = "Thank You.. Your request has been submitted...";
return View("Confirmation");
}
return View(sc);
}
so my question is if i can do the above job, using one save statement instead of 2?
You don't need use two SaveChanges. You can assign newsubmission into Submission property instead of v.SubmissionId = sc.Submission.Id;.
In this case Id and ForeignKey created automatically by EF Core
var newsubmission = _context.Submission.Add(sc.Submission);
foreach (var v in sc.SubmissionQuestionSubmission)
{
v.Submission = newsubmission;
_context.SubmissionQuestionSubmission.Add(v);
}
await _context.SaveChangesAsync();
Another way
sc.Submission.SubmissionQuestionSubmission = new List<SubmissionQuestionSubmission>();
foreach (var v in sc.SubmissionQuestionSubmission)
{
sc.Submission.SubmissionQuestionSubmission.Add(v)
}
_context.Submission.Add(sc.Submission);
await _context.SaveChangesAsync();

How to populate two tables in create method [asp.net mvc]

I have two tables in my database: referents and users.
Referents:
FirstName|LastName|Phone|Password|ConfirmPassword|UserName|Email
And
Users:
FirstName|LastName|UserRole|Password|ConfirmPassword|UserName
Currently Create method in my controler looks like:
// GET: Referents/Create
public ActionResult Create()
{
return View();
}
// POST: Referents/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ReferentID,FirstName,LastName,Phone,Email,Password,ConfirmPassword")] Referents referents)
{
if (ModelState.IsValid)
{
db.Referents.Add(referents);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(referents);
}
Obvious, right now I'm populating only Referents.
How to also populate Users table with certain data (UserName, LastName, UserName) in the same time?
In UserRole column I want to write string "referent".
EDIT Added model:
Referents:
namespace StudentService.Models
{
public class Referents
{
[Key]
public int ReferentID { get; set; }
[Required(ErrorMessage = "Морате унети име!")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Презиме је обавезно!")]
public string LastName { get; set; }
[Required(ErrorMessage = "Корисничко име је обавезно!")]
[Index(IsUnique = true)]
public string UserName { get; set; }
[Required(ErrorMessage = "Унесите исправан број телефона.")]
[DataType(DataType.PhoneNumber)]
public string Phone { get; set; }
[Required(ErrorMessage = "Унесите исправну адресу електронске поште.")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[Required(ErrorMessage = "Шифра је обавезна!")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Compare("Password", ErrorMessage = "Морате потврдити лозинку!")]
[DataType(DataType.Password)]
public string ConfirmPassword { get; set; }
}
}
You need to create the item for users and add it your your database.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ReferentID,FirstName,LastName,Phone,Email,Password,ConfirmPassword")] Referents referents)
{
if (ModelState.IsValid)
{
// Create the user data for the current referent.
Users currentUser = new Users(){
FirstName = referents.FirstName,
UserRole = "referent"
// .... Finish initializing fields of your model.
};
db.Referents.Add(referents);
// Save the new user in your database.
db.Users.Add(currentUser);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(referents);
}
Without seeing your model code it is hard to be specific, but you should be able to use that as an example. Just finish initializing the currentUser object to what you need it to be. It is possible this won't work depending on your schema.

How to log in my custom user table in MVC 4?

I want to use my custom User table in MVC 4 code first application. I defined advance User table in my database context:
public class MyDatabase : DbContext
{
public DbSet<User> UserSet { get; set; }
public DbSet<News> NewsSet { get; set; }
...
}
Model is like:
public class User
{
[Key]
public int Id{ get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Name { get; set; }
public string SurName { get; set; }
...
}
When application start, it calls this:
WebSecurity.InitializeDatabaseConnection("MyDatabase", "Users", "Id", "UserName", autoCreateTables: true);
In controller I use Add(entity) to save user entity. After saving I want to log in user. But it does not work:
[HttpPost]
public ActionResult Register(User user)
{
var result = MyService.SaveUser(user);
WebSecurity.Login(result.UserName, result.Password, true);
return RedirectToAction("Index", "Profile", new { id = result.Id });
}
After saving user, it's data stored in my database, but it can not log in. How should I do?
Edit:
Is it right to save User entity with my business method? Or I must do it only with
WebSecurity.CreateUserAndAccount()?
If I can use my own save method, how to save password in database?
You could just use forms authentication directly.
[HttpPost]
public ActionResult Register(User user)
{
var result = MyService.SaveUser(user);
SignIn(result.Id, "");
return RedirectToAction("Index", "Profile", new { id = result.Id });
}
public void SignIn(string accountId, string roles)
{
var authTicket = new FormsAuthenticationTicket(
1,
accountId,
DateTime.Now,
DateTime.Now.AddMinutes(20),
false,
roles
);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Current.Response.Cookies.Add(authCookie);
}
Here is a user class that will help you with password issue. It relies on BCrypt
public class UserAccount
{
public string Id { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public string Password
{
get { return PasswordHash; }
set { PasswordHash = HashPassword(value); }
}
public string PasswordHash { get; private set; }
public List<string> Roles { get; set; }
public string AuthenticationRoles
{
get { return Roles == null ? "" : String.Join(",", Roles.Select(x => x.ToString())); }
}
public bool IsActive { get; set; }
public string Name { get; set; }
public bool PasswordIsValid(string password)
{
bool matches = BCrypt.Net.BCrypt.Verify(password, Password);
return matches;
}
private string HashPassword(string value)
{
return BCrypt.Net.BCrypt.HashPassword(value);
}
}

Entity Framework Creates New Record in Table I Didn't Reference when Inserting Into Other Table

In this website, users can register under a username and password, and can also post comments on articles. The models are pretty straightforward:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool IsAdmin { get; set; }
public DateTime JoinDate { get; set; }
public string AvatarPath { get; set; }
public string EmailAddress { get; set; }
}
public class ArticleComment
{
public int Id { get; set; }
public int ArticleId { get; set; }
public int UserId { get; set; }
public string CommenterName { get; set; }
public string Message { get; set; }
public DateTime CommentDate { get; set; }
public User User { get; set; }
}
Entity Framework correctly made the foreign key relationship between UserId on ArticleComment and Id on User when the database was created using code-first.
Here's my code for when a user posts a new comment:
public JsonResult SubmitComment(int articleId, string comment)
{
var response = new JsonResponse();
var currentUser = _userRepository.GetUserByUsername(User.Identity.Name);
//...
var newComment = new ArticleComment
{
ArticleId = articleId,
CommentDate = DateTime.Now,
CommenterName = currentUser.Username,
UserId = currentUser.Id,
User = currentUser,
Message = comment,
};
try
{
_articleRepository.Insert(newComment);
}
catch (Exception e)
{
response.Success = false;
response.AddError("newComment", "Sorry, we could not add your comment. Server error: " + e.Message);
return Json(response);
}
response.Success = true;
response.Value = newComment;
return Json(response);
}
The values that make up the newComment object all appear to be correct, and the Insert method in my Article repository class is straight and to the point:
public void Insert(ArticleComment input)
{
DataContext.ArticleComments.Add(input);
DataContext.SaveChanges();
}
But once this happens, poof: a new record in my Users table appears along with the new record in ArticleComments. All of the info in the new Users record is duplicated from that user's existing record - the only difference is the value for the primary key Id. What gives?
In addition to my comment, you need to make sure that both _userRepository and _articleRepository are using the same DbContext instance.
Either that, or you can try this:
var newComment = new ArticleComment
{
ArticleId = articleId,
CommentDate = DateTime.Now,
CommenterName = currentUser.Username,
UserId = currentUser.Id,
// User = currentUser, let the UserId figure out the User, don't set it yourself.
Message = comment,
};