Pass a user to a ViewModel - c#

OK, a little stuck here.
VIEWMODEL
public class UserProfileEdit
{
public virtual ApplicationUser ApplicationUser { get; set; }
[Required]
public string FirstName { get; set; }
public string TwitterHandle{ get; set; }
[Required]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
// etc etc
}
CONTROLLER
public ActionResult YourProfile()
{
string username = User.Identity.Name;
ApplicationUser user = db.Users.FirstOrDefault(u => u.UserName.Equals(username));
// Construct the viewmodel
UserProfileEdit model = new UserProfileEdit();
model.ApplicationUser = user;
return View(model);
}
And on the View I have #model MySite.Models.UserProfileEdit at the top.
How can I pass the user to the ViewModel? I know I can do it line by line
model.Email = user.Email;
for example, but it should be simpler?

You can do it line by line, or you can use AutoMapper. Give it a try http://automapper.org/
This is very useful specially when you have the same kind of object mappings repeated in your code.

You have several options to do what you want to do.
You can use a tool, like AutoMapper.
Or you can pass data by a constructor :
public class UserProfileEdit
{
public virtual ApplicationUser ApplicationUser { get; set; }
[Required]
public string FirstName { get; set; }
public string TwitterHandle{ get; set; }
[Required]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
// etc etc
public UserProfileEdit() {}
public UserProfileEdit(ApplicationUser user) {
this.ApplicationUser = user;
this.Email = user.Email;
// ...
}
}
public ActionResult YourProfile()
{
string username = User.Identity.Name;
ApplicationUser user = db.Users.FirstOrDefault(u => u.UserName.Equals(username));
return View(new UserProfileEdit(user));
}
Or using a method to init your view model's data :
public class UserProfileEdit
{
public virtual ApplicationUser ApplicationUser { get; set; }
[Required]
public string FirstName { get; set; }
public string TwitterHandle{ get; set; }
[Required]
[Display(Name = "Email")]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
// etc etc
public void Init(ApplicationUser user) {
this.ApplicationUser = user;
this.Email = user.Email;
// do what you want to do
}
}
public ActionResult YourProfile()
{
string username = User.Identity.Name;
ApplicationUser user = db.Users.FirstOrDefault(u => u.UserName.Equals(username));
UserProfileEdit vm = new UserProfileEdit();
vm.Init(user);
return View(vm);
}

Related

How to include the ApplicationUser of an object in ASP.NET Core

I'm trying to make an app just like LinkedIn / Facebook.
I have a list of posts and each one has an ApplicationUser (ASP.NET IdentityUser).
In my PostController, I want to return the list of posts and include the ApplicationUser.
But I don't want every attribute of the user as an object containing a (hashed) password.
How can I return a post including ApplicationUser but without the password attribute?
Post.cs
public class Post
{
[Key]
public int Id { get; set; }
[Required]
public string ApplicationUserID { get; set; }
[MaxLength(500)]
public string Contents { get; set; }
[Required]
public ulong Timestamp { get; set; }
}
PostController:
[Authorize]
[HttpGet("{id}")]
public async Task<ActionResult<Post>> GetPost(int id)
{
var post = await _context.Posts
.Include(x=> x.ApplicationUser)
.FirstOrDefaultAsync(x => x.Id == id);
if (post == null)
{
return NotFound();
}
return post;
}
ApplicationUser:
public class ApplicationUser : IdentityUser
{
}
You can create a view model which included the required properties, such as below:
public class PostViewModel
{
[Key]
public int Id { get; set; }
[Required]
public string ApplicationUserID { get; set; }
[MaxLength(500)]
public string Contents { get; set; }
[Required]
public ulong Timestamp { get; set; }
public string UserName { get; set; } //Directly add the username property, used to store the user name
public UserViewModel User { get; set; } //create a new view model which contains the username
}
public class UserViewModel
{
public string UserName { get; set; }
}
Then, change the LINQ statement as as below:
var query = _dbcontext.Posts.Include(c => c.ApplicationUser)
.Select(c => new PostViewModel()
{
Id = c.Id,
Contents = c.Contents,
Timestamp = c.Timestamp,
UserName = c.ApplicationUser.UserName,
User = new UserViewModel()
{
UserName = c.ApplicationUser.UserName
}
}).ToList();
The result as below:

How do I make a relationship between my Aspnetusers table and a custom table?

I have extended my Aspnetusers table to include FirstName, MiddleName, LastName, StudentID.
I want a simple registation page where in the admin will create student accounts. The student accounts then should
be able to add their own personal contact details.
Now, I created a custom table named "ContactDetails" containing the ff:
public class Contact
{
[Key]
[Display(Name = "User Name")]
public string UserName { get; set; }
[Display(Name = "Contact Number")]
public string StudentContactNumber { get; set; }
[Display(Name = "Mother First Name")]
public string MotherFirstName { get; set; }
[Display(Name = "Mother Middle Name")]
public string MotherMiddleName { get; set; }
[Display(Name = "Mother Last Name")]
public string MotherLastName { get; set; }
[Display(Name = "Mother Contact Number")]
public string MotherContactNumber { get; set; }
[Display(Name = "Father First Name")]
public string FatherFirstName { get; set; }
[Display(Name = "Father Middle Name")]
public string FatherMiddleName { get; set; }
[Display(Name = "Father Last Name")]
public string FatherLastName { get; set; }
[Display(Name = "Father Contact Number")]
public string FatherContactNumber { get; set; }
[Display(Name = "Emergency First Name")]
public string EmergencyFirstName { get; set; }
[Display(Name = "Emergency Middle Name")]
public string EmergencyMiddleName { get; set; }
[Display(Name = "Emergency Last Name")]
public string EmergencyLastName { get; set; }
[Display(Name = "Emergency Contact Number")]
public string EmergencyContactNumber { get; set; }
public virtual ApplicationUser User { get; set; }
}
IdentityModels class:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string StudentID { get; set; }
public string College { get; set; }
public virtual System.Collections.Generic.ICollection<Contact> ContactInfo { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
How do I put my user(Aspnetusers.Id) in ContactDetails (User_Id) table when the student is registered?
How do I make a relationship between them?
My AdminController:
// GET: /Admin/Edit/Create
[Authorize(Roles = "Administrator")]
#region public ActionResult Create()
public ActionResult Create()
{
ExpandedUserDTO objExpandedUserDTO = new ExpandedUserDTO();
ViewBag.Roles = GetAllRolesAsSelectList();
return View(objExpandedUserDTO);
}
#endregion
// PUT: /Admin/Create
[Authorize(Roles = "Administrator")]
[HttpPost]
[ValidateAntiForgeryToken]
#region
public ActionResult Create(ExpandedUserDTO paramExpandedUserDTO)
{
try
{
if (paramExpandedUserDTO == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var Email = paramExpandedUserDTO.Email.Trim();
var UserName = paramExpandedUserDTO.Email.Trim();
var Password = paramExpandedUserDTO.Password.Trim();
//
var FirstName = paramExpandedUserDTO.FirstName.Trim();
var MiddleName = paramExpandedUserDTO.MiddleName.Trim();
var LastName = paramExpandedUserDTO.LastName.Trim();
var StudentID = paramExpandedUserDTO.StudentID.Trim();
var College = paramExpandedUserDTO.College.Trim();
// UserName is LowerCase of the Email
UserName = Email.ToLower();
// Create user
var objNewAdminUser = new ApplicationUser { UserName = UserName, Email = Email, FirstName = FirstName, MiddleName = MiddleName, LastName = LastName, StudentID = StudentID, College = College };
var AdminUserCreateResult = UserManager.Create(objNewAdminUser, Password);
if (AdminUserCreateResult.Succeeded == true)
{
string strNewRole = Convert.ToString(Request.Form["Roles"]);
if (strNewRole != "0")
{
// Put user in role
UserManager.AddToRole(objNewAdminUser.Id, strNewRole);
}
return Redirect("~/Admin");
}
else
{
ViewBag.Roles = GetAllRolesAsSelectList();
ModelState.AddModelError(string.Empty, "Error: User "+Email+ " already exists!");
//"Error: Failed to create the user. Check password requirements.");
return View(paramExpandedUserDTO);
}
}
catch (Exception ex)
{
ViewBag.Roles = GetAllRolesAsSelectList();
//ModelState.AddModelError(string.Empty, "Error: " + ex);
return View("Create");
}
}
#endregion
Im not sure how do I proceed? Thanks in advance.
In Contact class you should have these:
public int UserId { get; set; }
public virtual ApplicationUser User { get; set; }
In ApplicationUser class you should have these:
public int ContactId { get; set; }
public virtual Contact Contact { get; set; }

How do I link my Profile table to my AspNetUsers table when registering?

So I'm making a .NET Core app with MVC and I'm wondering how I can make a new profile and at the same time put the id of that row in my AspNetUsers as "ProfileId" when someone registers.
Here's my Profile.cs :
namespace Overnight.Models
{
public enum GenderType : byte {
Unknown = 0,
Male = 1,
Female = 2,
NotApplicable = 9
}
public class Profile : BaseEntity<Int64>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public GenderType Gender { get; set; }
public Nullable<DateTime> DayOfBirth { get; set; }
public Nullable<DateTime> LastActivityDate { get; set; }
//TODO One to One reference for image and adress
public List<ProfileReview> Reviews { get; set; }
public List<Blog> Blogs { get; set; }
public List<Accomodation> Accomodations { get; set; }
public List<Post> Posts { get; set; }
public List<Wishlist> Wishlists { get; set; }
public List<Invoice> Invoices { get; set; }
public List<Discount> Discounts { get; set; }
public Security.ApplicationUser ApplicationUser { get; set; }
}
}
Here's my ApplicationUser.cs :
namespace Overnight.Models.Security
{
public class ApplicationUser : IdentityUser<Guid>
{
public string PlainPassword { get; set; }
public DateTime CreatedAt {get; set;}
public Nullable<DateTime> UpdatedAt {get; set;}
public Nullable<DateTime> DeletedAt {get; set;}
public Int64 ProfileId { get; set; }
public Profile Profile { get; set; }
}
}
And here's the code for registering in my AccountController.cs :
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation(3, "User created a new account with password.");
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
so not sure if this is the best approach but I think you should first create a profile and then insert it into AspNetUser table, you also have to come up with a 'rollback' mechanism, either using stored procedures or manually track your work and backtrack if anything goes wrong.
so make your RegisterViewModel to contain information needed to create a Profile, and before creating user, there should be a line like:
var profile = profileRepo.add(new profile { /* use registerViewModel to fill*/});
profleRepo.SaveChanges(); // now your profile has the Id of last inserted row
then you can do this:
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, profileId = profile.Id};

MVC 5 GetUserId() returns null

I have created a custom User class implementing IUser.
When I register everything completes fine, the tables are created (if they don't exist) and all looks ok, but, as the subject states, I cannot get User.GetUserId() to work.
It always returns null which is really annoying.
Here is my User class:
public class User : IUser
{
public User()
{
this.LastLoginDate = DateTime.UtcNow;
this.DateCreated = DateTime.UtcNow;
}
public User(string userName)
{
this.Id = Guid.NewGuid().ToString();
this.UserName = userName;
this.CreatedBy = this.Id;
this.LastLoginDate = DateTime.UtcNow;
this.DateCreated = DateTime.UtcNow;
this.IsApproved = true;
}
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredUserName")]
public string UserName { get; set; }
public string Id { get; set; }
[Required] public string CompanyId { get; set; }
[Required] public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public DateTime LastLoginDate { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredTitle")]
public string Title { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredFirstName")]
public string Forename { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredLastName")]
public string Surname { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredEmail")]
public string Email { get; set; }
public string JobTitle { get; set; }
public string Telephone { get; set; }
public string Mobile { get; set; }
public string Photo { get; set; }
public string LinkedIn { get; set; }
public string Twitter { get; set; }
public string Facebook { get; set; }
public string Google { get; set; }
public string Bio { get; set; }
public string CompanyName { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredCredentialId")]
public string CredentialId { get; set; }
[Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredSecurityCode")]
public bool IsLockedOut { get; set; }
public bool IsApproved { get; set; }
[Display(Name = "Can only edit own assets")]
public bool CanEditOwn { get; set; }
[Display(Name = "Can edit assets")]
public bool CanEdit { get; set; }
[Display(Name = "Can download assets")]
public bool CanDownload { get; set; }
[Display(Name = "Require approval to upload assets")]
public bool RequiresApproval { get; set; }
[Display(Name = "Can approve assets")]
public bool CanApprove { get; set; }
[Display(Name = "Can synchronise assets")]
public bool CanSync { get; set; }
public bool AgreedTerms { get; set; }
public bool Deleted { get; set; }
}
public class UserContext : IdentityStoreContext
{
public UserContext(DbContext db)
: base(db)
{
this.Users = new UserStore<User>(this.DbContext);
}
}
public class UserDbContext : IdentityDbContext<User, UserClaim, UserSecret, UserLogin, Role, UserRole>
{
}
Here is my Register function:
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
try
{
// Create a profile, password, and link the local login before signing in the user
var companyId = Guid.NewGuid().ToString();
var user = new Skipstone.Models.User(model.UserName)
{
CompanyId = companyId,
Title = model.Title,
Forename = model.Forename,
Surname = model.Surname,
Email = model.Email,
CompanyName = model.CompanyName,
CredentialId = model.CredentialId
};
if (await IdentityStore.CreateLocalUser(user, model.Password))
{
// Create our company
var company = new Company()
{
Id = companyId,
CreatedBy = user.Id,
ModifiedBy = user.Id,
Name = model.CompanyName
};
using (var service = new CompanyService())
{
service.Save(company);
}
await AuthenticationManager.SignIn(HttpContext, user.Id, isPersistent: false);
var test = User.Identity.IsAuthenticated; // returns true
var u = User.Identity.GetUserId(); // returns null
return RedirectToAction("Setup", new { id = companyId });
}
else
{
ModelState.AddModelError("", "Failed to register user name: " + model.UserName);
}
}
catch (IdentityException e)
{
ModelState.AddModelError("", e.Message);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
var test returns true, so it knows the user is now logged in.
var u is null, so User.Identity.GetUserId() is not working as it should.
Does anyone have any idea why?
I can post more code on request :)
Update 1
By creating a fresh project and testing with defaults, I have found that called User.Identity returns null when in the Register method.
But in the fresh project, calling it anywhere else returns the right information, but in my project I get null for everything.
Update 2
It is definately related to the custom User class.
I created one on my fresh project and the same thing happens.
So, something is wrong :) now I just have to figure out what!?!
I assume somewhere in your project there is a row of database connection initialization, something like this:
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true)
So, make sure that you use "Id" instead of "UserId" in this line

How do I update a view model from an edit page in MVC3?

I have three models that are coming together to create one view model and I'd like to be able to edit that view model when clicking "edit". I can't find a straight forward example of how this works (anywhere).
I'm not sure if I'm going down the right path. I am able to get the view with the data. At this point, I am unable to save it.
Any help would be appreciated.
Thanks!
Models:
public class Person
{
[Key]
public int Id { get; set; }
[MaxLength(20)]
[Required(ErrorMessage = "First name is required.")]
public string FirstName { get; set; }
[MaxLength(20)]
[Required(ErrorMessage = "Last name is required.")]
public string LastName { get; set; }
[MaxLength(40)]
[Required(ErrorMessage = "Email is required.")]
public string Email { get; set; }
[MaxLength(20)]
[DataType(DataType.PhoneNumber)]
public string Phone { get; set; }
public bool Active { get; set; }
}
public class ClientContact
{
[Key]
[ForeignKey("Person")]
public int ClientPersonId { get; set; }
public int ClientId { get; set; }
[MaxLength(40)]
public string Title { get; set; }
public Person Person { get; set; }
[ForeignKey("ClientId")]
public Client Client { get; set; }
}
public class Client
{
[Key]
public int ClientId { get; set; }
public string Name { get; set; }
public bool Active {get;set;}
}
View Model:
public class ClientContactViewModel
{
private SimplexDB db = new SimplexDB();
public ClientContactViewModel()
{
}
public ClientContactViewModel(int id)
{
ClientPersonId = id;
InitializeClientContact();
}
public int ClientPersonId { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = " Last Name")]
public string LastName { get; set; }
[Display(Name = "Title")]
public string Title { get; set; }
[Display(Name = "Email Address")]
public string Email { get; set; }
[Display(Name = "Phone")]
public string Phone { get; set; }
[Display(Name = "Client Name")]
public int ClientId { get; set; }
public SelectList Clients
{
get
{
return new SelectList(db.Clients, "ClientId", "Name");
}
}
private void InitializeClientContact()
{
var contact = db.ClientPersons.Include("Person").Where(x => x.ClientPersonId == ClientPersonId).SingleOrDefault();
if (contact != null)
{
FirstName = contact.Person.FirstName;
LastName = contact.Person.LastName;
Title = contact.Title;
Email = contact.Person.Email;
Phone = contact.Person.Phone;
ClientId = contact.ClientId;
}
}
}
Controller:
public class ClientContactController : Controller
{
private database db = new database();
//
// GET: /ClientContact/Edit/5
public ActionResult Edit(int id)
{
return View(new ClientContactViewModel(id));
}
//
// POST: /ClientContact/Edit/5
[HttpPost]
public ActionResult Edit(ClientContactViewModel model)
{
if (ModelState.IsValid)
{
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
}
I get an error at the db.Entry(model).State... "The entity type ClientContactViewModel is not part of the model for the current context."
Your ViewModel is not an entity. You should map your ViewModel to your entity, then set the entity's state to modified.
Basically, this means that you should set your entity values with your view model values. You can use AutoMapper or handle it manually:
[HttpPost]
public ActionResult Edit(ClientContactViewModel model)
{
if (ModelState.IsValid)
{
ClientContact contact = db.ClientPersons.Include("Person")
.Where(x => x.ClientPersonId == model.ClientPersonId)
.SingleOrDefault();
contact.FirstName = model.FirstName;
// etc
db.Entry(contact).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
See http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ for an excellent approach to using ViewModels in MVC.
Also, I would highly recommend not doing any data access in your ViewModel. Do that in your Controller, or even better, in a Repository that is used by your Controller. Model binding doesn't play well with models that have logic (i.e they shouldn't contain anything more than simple get/set properties).
You need to move your models' properties to the viewmodel in the GET action. In the POST action, get your original models from the db, update the models with the data from the view model, and then save changes. Your models are essentially representations of tables in your database. Your view model is just what is shown on the screen.
[HttpPost]
public ActionResult Edit(ClientContactViewModel model)
{
if (ModelState.IsValid)
{
var client = db.Client.Where(c => c.Id = model.ClientPersonId);
client.FirstName = model.FirstName;
...etc through all your properties and other models...
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
There are slicker ways to do this, but this represents the idea without abstractions.

Categories