I want to be able to retrieve values from the database from a
specific user, which in this case #Model.user.Xp, it does not work, I
just get 0.
#model TheQuizR.Models.IndexViewModel
#using Microsoft.AspNet.Identity
<div class="row">
<div class="col-sm-6 col-md-6">
<ul class="list-group">
<div class="blue">
#User.Identity.GetUserName()<br />
</div>
<li class="list-group-item">
Title
<span class="badge">#Model.user.Xp</span>
</li>
<li class="list-group-item">
In the IndexViewModel I have this:
public class IndexViewModel
{
public ApplicationUser user = new ApplicationUser();
public bool HasPassword { get; set; }
public IList<UserLoginInfo> Logins { get; set; }
public string PhoneNumber { get; set; }
public bool TwoFactor { get; set; }
public bool BrowserRemembered { get; set; }
}
In the ApplicationUser class I have all the properties:
public class ApplicationUser : IdentityUser
{
[MaxLength(128)]
public string Title { get; set; }
[Range(0, 5000000)]
public int Xp { get; set; }
[Range(0, 100000)]
}
I cant get the id and the username thru Microsoft.AspNet.Identity (the one mark in yellow). I can't get all the other properties.
I would recommend to find the user in controller. Then you can create another model or use Viewbag.
string username = User.Identity.GetUserName();
var user = db.Users.First(u => u.UserAD == username);
ViewBag.userIDconnected = user.ID;
View -
<div class="row">
<div class="col-sm-6 col-md-6">
<ul class="list-group">
<div class="blue">
</div>
<li class="list-group-item">
Title
<span class="badge">#ViewBag.userIDconnected</span>
</li>
<li class="list-group-item">
Related
I have created a view that accepts a ProjectsCreatorsVM class. This class has been structured this way:
public class ProjectsCreatorsVM
{
public List<ProjectVM> ProjectsCreators { get; set; }
public ProjectsCreatorsVM(List<ProjectVM> projectsCreators)
{
ProjectsCreators = projectsCreators;
}
}
In addition, the ProjectVM follow this structure:
public class ProjectVM
{
public Project Project { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public ProjectVM(Project pro, ApplicationUser applUser)
{
Project = pro;
ApplicationUser = applUser;
}
}
Lastly, my view tries to go through the ProjectsCreators.Project but it does not seem to be possible.
<div class="card-content-container" >
#foreach (Project obj in #Model.ProjectsCreators.)
{
<div class="card">
<img class="card-img-top" src="#obj.ImgURL" alt ="project image" >
<div class="card-body d-flex flex-column">
<h5 class="card-title">#obj.Title</h5>
<h6 class="card-title">#obj.Title</h6>
<p class="card-text">
#obj.TruncatedDescription
</p>
<div class="mt-auto" style="display: flex; justify-content: space-between; align-items: center;">
View Details
</div>
</div>
</div>
I would appreciate any help. Thanks in advance.
ProjectCreators is a List and when you iterate ProjectCreators you get a ProjectVM object not a Project or ApplicaionUser instance. If you want to access Project instance add Project after #obj like #obj.Project.Title
<div class="card-content-container" >
#foreach (ProjectVM obj in #Model.ProjectsCreators.)
{
<div class="card">
<img class="card-img-top" src="#obj.Project.ImgURL" alt ="project image" >
<div class="card-body d-flex flex-column">
<h5 class="card-title">#obj.Project.Title</h5>
<h6 class="card-title">#obj.Project.Title</h6>
<p class="card-text">
#obj.Project.TruncatedDescription
</p>
<div class="mt-auto" style="display: flex; justify-content: space-between; align-items: center;">
View Details
</div>
</div>
</div>
}
</div>
To achieve what I wanted, I created another class. That looks like this:
public class ProjectAndUserVM
{
public string ProjectTitle { get; set; }
public string ProjectId { get; set; }
public string ProjectImageUrl { get; set; }
public string ProjectDescription { get; set; }
public string ProjectCreatorName { get; set; }
public string ProjectCreatorId { get; set; }
public string ProjectCreatorEmail { get; set; }
public ProjectAndUserVM(string projectTitle, string projectId, string projectImageUrl, string projectDescription, string projectCreatorName, string projectCreatorId, string projectCreatorEmail)
{
ProjectTitle = projectTitle;
ProjectId = projectId;
ProjectImageUrl = projectImageUrl;
ProjectDescription = projectDescription;
ProjectCreatorName = projectCreatorName;
ProjectCreatorId = projectCreatorId;
ProjectCreatorEmail = projectCreatorEmail;
}
}
So, basically my controller is returning that as a list which I convert to an IEnumerable. and I use that list on my view instead.
I am working on a Data Entry system for storing users financial data. Each user will enter his Revenues and Expenses each in a table.
The tables were designed as follows:
Primary Key: Rev/Exp ID
Foreign Key: Organization ID
This is a sample for my models:
public class Revenue
{
[Key]
public int RevenueId { get; set; }
public int Year { get; set; }
public double Source1 { get; set; } = 0;
public double Source2 { get; set; } = 0;
public double Source3 { get; set; } = 0;
public double Source4 { get; set; } = 0;
// Foreign Key Relationship
public string OrganizationId{ get; set; }
public virtual Organization Organization{ get; set; }
}
public class Organization
{
public virtual ICollection<Revenue> Revenues { get; set; }
public virtual ICollection<Expense> Expenses { get; set; }
}
This is the DBContext:
public class AppDbContext : IdentityDbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
// Create tables in DB
public DbSet<Organization > Organization { get; set; }
public DbSet<Revenue> Revenue { get; set; }
public DbSet<Expense> Expense { get; set; }
}
Here is the Create Action in the Controller:
// GET: Revenue/Create
public IActionResult Create()
{
return View();
}
// POST: Revenue/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("RevenueId,Year,Source1,Source2,...,OrganizationId")] Revenue revenue)
{
if (ModelState.IsValid)
{
_context.Add(revenue);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["OrganizationId"] = new SelectList(_context.OrganizationId, "Id", "Id", revenue.OrganizationId);
return View(revenue);
}
Finally, Create View:
#using Microsoft.AspNetCore.Identity
#inject SignInManager<IdentityUser> SignInManager
#inject UserManager<IdentityUser> UserManager
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Revenue</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Year" class="control-label"></label>
<input asp-for="Year" class="form-control" />
<span asp-validation-for="Year" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Source1" class="control-label"></label>
<input asp-for="Source1" class="form-control" />
<span asp-validation-for="Source1" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Source2" class="control-label"></label>
<input asp-for="Source2" class="form-control" />
<span asp-validation-for="Source2" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Source3" class="control-label"></label>
<input asp-for="Source3" class="form-control" />
<span asp-validation-for="Source3" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Source4" class="control-label"></label>
<input asp-for="Source4" class="form-control" />
<span asp-validation-for="Source4" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="OrganizationId" class="control-label"></label>
<input asp-for="OrganizationId" class="form-control" value="#UserManager.GetUserId(User)"/>
<span asp-validation-for="OrganizationId" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
So, after a lot of search I was able to capture user ID with UserManager and assigning it to a hidden field, then sending it with the form. However, that did not work, the form is not submitting and no error messages are displayed neither.
Is this is a correct way of capturing user ID as a Foreign Key and how to fix the Create Action ?
You didn't really specify anything about your authentication. If you are using typical ASP.Net authentication, you can probably use User.Identity.Name, like this:
if (ModelState.IsValid)
{
revenue.UserId = User.Identity.Name
_context.Add(revenue);
...
As from .NET 6, in order to assign an attribute in a model to be Nullable the ? should be added after the name of the attribute, otherwise it is required.
The problem was that the UserId is passed but the User object is null (which should be because it is just a reference).
So the model should be:
public class Revenue
{
[Key]
public int RevenueId { get; set; }
public int Year { get; set; }
public double Source1 { get; set; } = 0;
public double Source2 { get; set; } = 0;
public double Source3 { get; set; } = 0;
public double Source4 { get; set; } = 0;
// Foreign Key Relationship
public string OrganizationId{ get; set; }
public Organization? Organization{ get; set; }
}
And the view will be as is by passing user ID in a hidden field that we got from UserManager.
I'm somewhat new to MVC and have been following along with a tutorial but it has no answers regarding my question. For my Create page, the Foreign keys are not showing up. Basically, on the Projects page I created a project, on the People page I created a person. So when I try to create a ProjectRole on the ProjectRoles page, the ProjectId and PersonId are not showing up in the drop-down menu. Down below all of my code, I have provided a screenshot of what I have tried to put into words.
My models:
public class Project
{
public int Id { get; set; }
[Required]
[MaxLength(30)]
public string Name { get; set; }
[Required]
public DateTime StartDate { get; set; }
[Required]
public DateTime DueDate { get; set; }
public ICollection<ProjectRole> ProjectRoles { get; set; }
}
public class Person
{
public int Id { get; set; }
[Required]
[MaxLength(30)]
public string FirstName { get; set; }
[Required]
[MaxLength(30)]
public string MiddleName { get; set; }
[Required]
[MaxLength(30)]
public string LastName { get; set; }
[Required]
public string Email { get; set; }
public ICollection<ProjectRole> ProjectRoles { get; set; }
}
public class ProjectRole
{
public int Id { get; set; }
[Required]
public double HourlyRate { get; set; }
[ForeignKey("Person")]
public int PersonId { get; set; }
[ForeignKey("Project")]
public int ProjectId { get; set; }
[ForeignKey("AppRole")]
public int RoleId { get; set; }
}
My Controller code:
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,HourlyRate,PersonId,ProjectId,RoleId")] ProjectRole projectRole)
{
if (ModelState.IsValid)
{
_context.Add(projectRole);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(projectRole);
}
And my view code here:
#model Project2.Models.Entities.ProjectRole
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>ProjectRole</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="HourlyRate" class="control-label"></label>
<input asp-for="HourlyRate" class="form-control" />
<span asp-validation-for="HourlyRate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PersonId" class="control-label"></label>
<select asp-for="PersonId" class ="form-control" asp-items="ViewBag.PersonId"></select>
</div>
<div class="form-group">
<label asp-for="ProjectId" class="control-label"></label>
<select asp-for="ProjectId" class ="form-control" asp-items="ViewBag.ProjectId"></select>
</div>
<div class="form-group">
<label asp-for="RoleId" class="control-label"></label>
<input asp-for="RoleId" class="form-control" />
<span asp-validation-for="RoleId" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Screenshot of example of what I mean:
I suppose more personable to display the Person Name (and the Project Name) in the select controls, but to pass the PersonId (and ProjectId) to the Create method when click on the Create button.
Therefore, prepare the Person list (and the Project list) like below:
public IActionResult Create()
{
var persons = new List<SelectListItem>();
// Iterate through `Persons`
foreach(var p in _context.Persons)
{
persons.Add(new SelectListItem() { Value= p.Id, Text = p.FirstName+", "+p.LastName});
}
ViewBag.Persons = persons;
// Prepare the projects list (like `Persons` list above)
// ... your code here
ViewBag.Projects = persons;
return View(new ProjectRole(){ /* Add your code here to create the ProjectRole .../* });
}
And in the view:
<div class="form-group">
<label asp-for="PersonId" class="control-label"></label>
<select asp-for="PersonId" class="form-control" asp-items="ViewBag.Persons"></select>
</div>
<div class="form-group">
<label asp-for="ProjectId" class="control-label"></label>
<select asp-for="ProjectId" class="form-control" asp-items="ViewBag.Projects"></select>
</div>
For additional information see The Select Tag Helper
*NOTE: And I would recommend to create compound view model to include all required information. *
ViewModels or ViewBag?
Understanding Best Way to Use Multiple Models in ASP.NET MVC
I´m having an issue where I have three models as show below: Person, Competence with PersonCompetence between them. My current controller method gets an Id from previous page and shows that person with a list of this person's Competence and Level. In this View however I want to have a POST for new Competence. So at the same time you are adding a new one and you can see which ones you already have.
With the controller method I have now I can access the PersonCompetence and Competence when showing the list.
I dont have access to the Competence properties for asp-for="Competence" marked ###### in the View for AddComp.
I need the ID of person for POST to right person
I need the CompetenceType for POST to that property
I need PersonCompetence to show the list of current PersonCompetence.
I get that with the current #model CompetenceRadar.Models.Person I only reach Person properties.
I have looked at having a ViewModel with access to all tables with an IEnumerable for each table, but this breaks my current Controller when I search for the Id of the person showing. I have switched the #model in the View, but then I can't access Person ID/name.
So how do I access the Competence properties , list one person and get a list of PersonCompetences for that Person.
Please tell me if you want me to clarify something.
I don't need working code, just something to point me in the right direction for a solution.
Is it a ViewModel?
Can I POST without the asp-forattribute?
Models
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public ICollection<PersonCompetences> PersonCompetences { get; set; }
}
public class PersonCompetence
{
public int ID { get; set; }
public int PersonID { get; set; } // FK
public int CompetenceID { get; set; } // FK
public int Level { get; set; }
public Competece Competence { get; set; }
public Person Person { get; set; }
}
public class Competence
{
public int ID { get; set; }
public string CompetenceType { get; set; }
public string CompetenceCategory { get; set; }
public ICollection<PersonCompetence> PersonCompetences { get; set; }
}
AddComp Kontroller function
public async Task<IActionResult> AddComp(int? id)
{
var person = await _context.Personer
.Include(pk => pk.PersonCompetences)
.ThenInclude(k => k.Competence)
.FirstOrDefaultAsync(m => m.ID == id);
return View(person);
}
View_AddComp View for AddComp
#model CompetenceRadar.Models.Person
<h1>AddComp</h1>
<div class="row">
<form asp-action="AddComp">
<input type="hidden" asp-for="ID" />
<div class="form-group col-sm-4">
<label asp-for="#############" class="control-label col-sm-4"></label>
<input asp-for="#############" class="form-control col-sm-4" />
<span class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-dark" />
</div>
</form>
</div>
#foreach (var item in Model.PersonCompetences)
{
<div class="row py-2 rounded" style="background-color:lightslategray">
<div class="col-sm-3 pt-2">#item.Competence.CompetenceType</div>
<div class="col-sm-1 pt-2">#item.Niva</div>
<div class="col-sm-3 pt-2">#item.Competence.CompetenceCategory</div>
<div class="col-sm-5 d-flex justify-content-end">
<a class="btn btn-dark mr-1" role="button" asp-area="" asp-controller="Competence" asp-action="UpdateLevel" asp-route-id="#item.ID">Update</a>
<a class="btn btn-dark mr-1" role="button" asp-area="" asp-controller="Competence" asp-action="DeleteComp" asp-route-id="#item.CompetenceID">Remove</a>
</div>
</div>
}
Simple anwser is that I needed a ViewModel with all three Models
public class ExampleViewModel {
public Person person { get; set; }
public PersonCompetence personCompetence { get; set; }
public Competence competence { get; set; }}
This alows me to access the different values for ID, CompetenceType and a List for of the current PersonCompetence.
What is ViewModel in MVC?
I am attempting to create a modal that has a tab menu, which allows you to switch between views. The reasonable approach seemed to do partial views and build the table using a for each statement; however, they're in different models so I am struggling. I've got the first view working in the modal, but i am unsure how to use different models in each view.
#model PortalDev.Models.ViewModels.EditUserViewModel
<div class="modal-body">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="user-tab" data-toggle="tab" href="#user" role="tab" aria-controls="user" aria-selected="true">User</a>
</li>
<li class="nav-item">
<a class="nav-link" id="roles-tab" data-toggle="tab" href="#roles" role="tab" aria-controls="roles" aria-selected="false">Roles</a>
</li>
<li class="nav-item">
<a class="nav-link" id="claims-tab" data-toggle="tab" href="#claims" role="tab" aria-controls="claims" aria-selected="false">Claims</a>
</li>
</ul>
<div class="tab-content tabMenu" id="myTabContent">
#*----------------------Edit User Role Tab----------------------*#
<div class="tab-pane fade" id="roles" role="tabpanel" aria-labelledby="roles-tab">
<div class="wrapper">
<table class="table table-hover table-md ">
<thead>
<tr>
<td class="text-left TableHead">Id</td>
<td class="text-left TableHead">Role</td>
</tr>
</thead>
#*--Table Body For Each to pull DB records--*#
<tbody>
#foreach (var role in Model.Roles)
{
#Html.Partial("~/Views/Administration/Users/UserRoleTable.cshtml", role)
}
</tbody>
</table>
</div>
#*----------------------Edit User Claims Tab----------------------*#
<div class="tab-pane fade" id="claims" role="tabpanel" aria-labelledby="claims-tab">...</div>
</div>
</div>
</div>
------------------UserRoleTable.cshtml-------------------------------------
#model PortalDev.Models.ViewModels.ManageUserRoleViewModel
#{
ViewData["Title"] = "UserRoleTable";
}
<tr asp-action="ManageUserRoles" asp-controller="Administration" asp-route-id="#Model.RoleId">
<td class="text-left">#Model.RoleId</td>
<td class="text-left">#Model.RoleName</td>
</tr>
public class ManageUserRoleViewModel
{
public string RoleId { get; set; }
public string RoleName { get; set; }
public bool IsSelected { get; set; }
//Viewbag is used to store UserId
}
---------------EditUserVieModel.cs---------------
public class EditUserViewModel
{
public EditUserViewModel()
{
Claims = new List<string>(); Roles = new List<string>();
}
public string Id { get; set; }
[Required]
public string UserName { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
public string City { get; set; }
public List<string> Claims { get; set; }
public IList<string> Roles { get; set; }
}
----------------AdministrationController.cs (method i need to call)----------
[HttpGet]
public async Task<IActionResult> ManageUserRoles(string userId)
{
ViewBag.userId = userId;
var user = await userManager.FindByIdAsync(userId);
if (user == null)
{
ViewBag.ErrorMessage = $"User with Id = {userId} cannot be found";
return View("NotFound");
}
var model = new List<ManageUserRoleViewModel>();
foreach (var role in roleManager.Roles)
{
var manageUserRoleViewModel = new ManageUserRoleViewModel
{
RoleId = role.Id,
RoleName = role.Name
};
if (await userManager.IsInRoleAsync(user, role.Name))
{
manageUserRoleViewModel.IsSelected = true;
}
else
{
manageUserRoleViewModel.IsSelected = false;
}
model.Add(manageUserRoleViewModel);
}
return View(model);
}
I have a users table... I want to be able to click on the user, get the edit modal to come up (works right now). Have 3 sub menu tabs on top. One for editing user info, Second for listing their Roles, Third for listing "claims".
You have a few options here. You could use TempData or ViewData dictionaries or your EditUserViewModel needs to contain all the models required to render the entire view along with any partial's it contains.
public class EditUserViewModel
{
public ModelClass1 Model1 { get; set; }
public ModelClass2 Model2 { get; set; }
}
Then you would pass these into the partial views.