I am using asp.net core with Identity. For user I have this class:
public class User : IdentityUser
{
public List<Rate> Rates { get; set; }
}
I would like to get Rates inside Razor, how can this be done with the Name field (User.Identity.Name).
First, please confirm whether you have successfully added a one to many relation of Rate table for Identityuser and generated the Rate
table in the database.
Please change all Identityuser references (except where the User class inherits) in your project to your customized User class, including the relevant view page and the startup class.
And then change the ApplicationDbContext as follow:
public class ApplicationDbContext : IdentityDbContext<User>
{
public DbSet<Rate> Rate { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
Then excute migration command. More details, refer to this video.
Here is my Rate Class:
public class Rate
{
[Key]
public int Id { get; set; }
public int rate { get; set; }
public virtual User User { get; set; }
}
After completing the above operations, add relevant Rates data to the database.
Then start the project, log in the user information, and then use the following code in the corresponding action and view to show Rates of associated Name field:
[Authorize]
public class AccountController : Controller
{
private readonly ApplicationDbContext _context;
public AccountController(ApplicationDbContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
var rates = await _context.Rate.Include(host => host.User).Where(x => x.User.UserName == User.Identity.Name).ToListAsync();
return View(rates);
}
}
Razor View:
#model IEnumerable<Rate>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Index</h1>
UserName: #User.Identity.Name related Rates data:
<table class="table table-bordered">
<tr>
<th>Id</th>
<th>Rate</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#item.Id</td>
<td>#item.rate</td>
</tr>
}
</table>
Here is the test result:
Related
Let's suppose I have these 2 entities:
public class Person
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long id_person {get;set;}
[Column(TypeName = "varchar(255)")]
[StringLength(255)]
public String name {get;set;}
}
public class InterestCenter
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long id_interest {get;set;}
[Column(TypeName = "varchar(255)")]
[StringLength(255)]
public String name {get;set;}
}
I want to set a many to many relationship between this 2 entities. This mean a Person can have many interest centers.
Here is what I've done:
public class PersonHasInterestCenter
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long id {get;set;}
[ForeignKey("person")]
public long id_person {get;set;}
public virtual Person person { get; set; }
[ForeignKey("interestcenter")]
public long id_interest {get;set;}
public virtual InterestCenter interestcenter { get; set; }
}
Now I want to create a controller action and cshtml razor view in order to edit and save a Person. What I want to do is to display a set of checkboxes with all available interst centers.
Here is what I've done:
[HttpPost]
public async Task<IActionResult> MyAction(long id, [Bind("id_person,name")] Person p)
{
ViewBag.interestcenters = mydbcontext.interestcenters;
ViewBag.message = "";
if (p.name == "")
{
ViewBag.message = "You need to set name.";
}
else if (ModelState.IsValid == false)
{
ViewBag.message = string.Join("; ", ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage));
}
else
{
mydb_context.Update(p);
await mydb_context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(p);
}
And here is the associated cshtml razor view:
#model myproject.Person
<form asp-action="MyAction">
<div>#ViewBag.message</div>
<input type="hidden" asp-for="id_person" />
<input asp-for="name" />
#foreach (var name in ViewBag.interestcenters)
{
<input type="checkbox" asp-for="WHAT_SHOULD_I_PUT_THERE" />#item.name
}
<input type="submit">
</form>
Everything works great for create or update person's name but I have a problem with interest center checkboxes. I have also tried to create a view model. But I do not manage to make it work...
Thanks for your help
The simple answer is ... use viewmodels whenever have the chance.
In order to bind those interests you could create something similar to:
public class MyViewModel
{
public long UserId { get; set; }
public List<InterestCenterViewModel> InterestCenters { get; set; }
}
public class InterestCenterViewModel
{
public int Id { get; set; }
public bool IsSelected { get; set; }
public string Name { get; set; }
}
On the get method:
[HttpGet]
public async Task<IActionResult> MyAction(long id)
{
var _InterestCenters = mydbcontext.interestcenters;
// Create your vm here
var model = new MyViewModel
{
UserId = id,
InterestCenters = _InterestCenters.Select(p => new InterestCenterViewModel
{
Id = p.Id,
Name = p.Name
IsSelected = false
}).ToList()
}
return View(model);
}
On your post:
[HttpPost]
public async Task<IActionResult> MyAction(MyViewModel model)
{
// Something was not filled or did not match your requirements
if (!ViewState.IsValid)
{
return View(model);
}
// All good. To your stff here
return Ok();
}
So all you need is to pass the list of interests created using the above model to the view:
<input asp-for="UserId" type="hidden" />
#for(int i = 0; i < MyViewModel.InterestCenters.Count; i++)
{
<input type="checkbox" asp-for="MyViewModel.InterestCenters[i].IsSelected" />#MyViewModel.InterestCenters[i].Name
}
When working with lists you need to use for instead of foreach. The html generated is using that index i instead of the name which is the way to make the difference between items.
Here is a link describing how viewmodels and asp.net works: Microsoft official documentation
I'm new to MVC, and stuck on what should be a pretty straight forward issue. I'm working through this tutorial and got everything pretty much working, except I now want to add a foreign key 'link' (not sure what it's called) but can't seem to get it to work. Here's what I have:
Tables:
Inventory:
Id | SerialNumber | ManufacturerId (foreignkey to Manufactueres->id)
Manufactureres
Id (primary key) | Name
Model (InventoryItem.cs):
public class InventoryItem {
public int Id {get; set; }
public int SerialNumber{ get; set; }
//this starts the trouble, I actually want to interact with the Manufactureres table -> Name column
public int ManufacturerId { get; set; }
}
View (Create.cshtml):
...
//What i really want is a dropdown of the values in the Manufactureres table
#Html.EditorFor(model=> model.ManufacturerId)
This must be a farely common issue when using a relational database there would be many foreign key relationships to be used/shown, but for some reason i can't find a tutorial or issue on stackoverflow that directly corresponds to something so simple. Any guidance, or direction is much appreciated!
Thanks,
I hope I understand your question correctly. Seems like when you want to add a new inventory item then you want a list of all the manufacturers in a dropdown list. I am going to work on this assumption, please let me know if I am off the track :)
Firstly go and create a view model. This view model you will bind to yout view. Never bind domain objects to your view.
public class InventoryItemViewModel
{
public int SerialNumber { get; set; }
public int ManufacturerId { get; set; }
public IEnumerable<Manufacturer> Manufacturers { get; set; }
}
Your domain objects:
public class InventoryItem
{
public int Id { get; set; }
public int SerialNumber{ get; set; }
public int ManufacturerId { get; set; }
}
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
}
Your controller might look like this:
public class InventoryItemController : Controller
{
private readonly IManufacturerRepository manufacturerRepository;
private readonly IInventoryItemRepository inventoryItemRepository;
public InventoryItem(IManufacturerRepository manufacturerRepository, IManufacturerRepository manufacturerRepository)
{
// Check that manufacturerRepository and inventoryItem are not null
this.manufacturerRepository = manufacturerRepository;
this.inventoryItemRepository = inventoryItemRepository;
}
public ActionResult Create()
{
InventoryItemViewModel viewModel = new InventoryItemViewModel
{
Manufacturers = manufacturerRepository.GetAll()
};
return View(viewModel);
}
[HttpPost]
public ActionResult Create(InventoryItemViewModel viewModel)
{
// Check that viewModel is not null
if (!ModelState.IsValid)
{
Manufacturers = manufacturerRepository.GetAll()
return View(viewModel);
}
// All validation is cool
// Use a mapping tool like AutoMapper
// to map between view model and domain model
InventoryItem inventoryItem = Mapper.Map<InventoryItem>(viewModel);
inventoryItemRepository.Insert(inventoryItem);
// Return to which ever view you need to display
return View("List");
}
}
And then in your view you might have the following:
#model MyProject.DomainModel.ViewModels.InventoryItems.InventoryItemViewModel
<table>
<tr>
<td class="edit-label">Serial Number <span class="required">**</span></td>
<td>#Html.TextBoxFor(x => x.SerialNumber, new { maxlength = "10" })
#Html.ValidationMessageFor(x => x.SerialNumber)
</td>
</tr>
<tr>
<td class="edit-label">Manufacturer <span class="required">**</span></td>
<td>
#Html.DropDownListFor(
x => x.ManufacturerId,
new SelectList(Model.Manufacturers, "Id", "Name", Model.ManufacturerId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.ManufacturerId)
</td>
</tr>
</table>
I hope this helps :)
Yes, this is common issue, you need select Manufactureres in action and then send them to view. You can use ViewBag or strontly typed view model.
Examples:
Problem populating dropdown boxes in an ASP.NET MVC 3
Application
Having difficulty using an ASP.NET MVC ViewBag and
DropDownListfor
MVC3 Razor #Html.DropDownListFor
This is what I would recommend you.
1) Create a Manufacturer model class
public class Manufacturer
{
public int Id { get; set; }
public string Name { get; set; }
}
2) Create InventoryItem model class as follows
public class InventoryItem
{
public int Id { get; set; }
public int SerialNumber{ get; set; }
public int ManufacturerId { get; set; }
[ForeignKey("Id ")]
public Manufacturer Manufacturer{get; set;}
public IEnumerable<Manufacturer> Manufacturer {get;set;}
}
3) Make sure DbContext is also updated as follows
public DbSet<InventoryItem> InventoryItem {get;set;}
public DbSet<Manufacturer> Manufacturer{get;set;}
4) Controller
[HttpGet]
public ActionResult Create()
{
InventoryItem model = new InventoryItem();
using (ApplicationDbContext db = new ApplicationDbContext())
{
model.Manufacturer= new SelectList(db.Manufacturer.ToList(), "Id", "Name");
}
return View(model);
}
[HttpPost]
public ActionResult Create(InventoryItem model)
{
//Check the Model State
if(! ModelState.IsValid)
{
using (ApplicationDbContext db = new ApplicationDbContext())
{
model.Manufacturer= new SelectList(db.Manufacturer.ToList(), "Id", "Name");
return View(model);
}
}
using (ApplicationDbContext db = new ApplicationDbContext())
{
InventoryItem dto = new InventoryItem();
dto.SerialNumber= model.SerialNumber;
dto.Id= model.Id;
Manufacturer manudto = db.Manufacturer.FirstOrDefault(x => x.Id== model.Id);
dto.CatName = manudto.CatName;
db.Test.Add(dto);
db.SaveChanges();
}
TempData["SM"] = "Added";
return RedirectToAction("Index");
}
5) Make sure View has dropdownselect option in below format
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.Id, Model.Manufacturer,"Select", new { #class = "form-control" } )
#Html.ValidationMessageFor(model => model.Id, "", new { #class = "text-danger" })
</div>
</div>
Hope this works :D
How to get data from two table or two class in single view in mvc3.
I want to show data from both the table.
I have one parent class and two child class.
i.e
public class GetDocumentParent
{enter code here
public List getDocument { get; set; }
public List getDocumentRevision { get; set; }
}
View:
" %>
<% foreach (var item in Model.getDocument)
{ %>
<tr>
<td>
<%:Html.DisplayFor(ModelState => item.DOCUMENT_NAME)%>
</td>
<td>
<%:Html.DisplayFor(ModelState => item.ActiveDate)%>
</td>
<td>
<%:Html.DisplayFor(ModelState => item.Revision)%>
</td>
<td>
</tr>
<% } %>
==>item.DOCUMENT_NAME and item.ActiveDate from Document Class.
item.Revision from Document_Revision class.
how to show both class's value at the same time in view.
Controller:
var model = new GetDocumentParent
{
getDocument = db.Document.ToList(),
getDocumentRevision = db.DocumentRevisions.ToList()
};
return View(model);
Model:
1.
public class DOCUMENTS
{
public string DOCUMENT_NAME
{
get;
set;
}
public Nullable<System.DateTime> ActiveDate
{
get;
set;
}
}
2.
public class DOCUMENT_REVISIONS
{
public string REVISION
{
get;
set;
}
}
Thanks in advance
Always remember that it is best to have a view model that represents your data that is sent to the view. The view will do what is needed with you view model. The code below can guide you, you must just change it to fit into your scenario.
Lets say that I have a customer and each customer has only 1 address. I would create a view model called CustomerDetailsViewModel to represent this data:
public class CustomerDetailsViewModel
{
public string FirstName { get; set; }
public string Lastname { get; set; }
public int Age { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
}
Your action method to display the customer and customer address details:
public class CustomerController : Controller
{
private readonly ICustomerRepository customerRepository;
public CustomerController(ICustomerRepository customerRepository)
{
// Check customerRepository for nulls
this.customerRepository = customerRepository;
}
public ActionResult Details(int id)
{
// Check that id is not zero or negative
Customer customer = customerRepository.GetById(id);
// Get the customer's address
Address address = customerRepository.GetCustomerAddress(id);
CustomerDetailsViewModel viewModel = new CustomerDetailsViewModel()
{
FirstName = customer.Firstname,
LastName = customer.LastName,
Age = customer.Age,
AddressLine1 = address.AddressLine1,
AddressLine2 = address.AddressLine2,
City = address.City
}
return View(viewModel);
}
}
id above represents your customer's unique identifier. It is used to return a cusotmer:
Customer customer = customerRepository.GetById(id);
and also used to returned a specific customer's address:
Address address = customerRepository.GetCustomerAddress(id);
An ICustomerRepository instance is injected by an IoC container for example Autofac.
In your view you pass this view model as such and can display the data as you please:
#model MyProject.DomainModel.ViewModels.Customers.CustomerDetailsViewModel
<div class="content">
<div class="display-label">First Name: </div>
<div class="display-content">#Model.FirstName</div>
<div class="display-label">Last Name: </div>
<div class="display-content">#Model.LastName</div>
<div class="display-label">Age: </div>
<div class="display-content">#Model.Age</div>
<div class="display-label">Address Line 1: </div>
<div class="display-content">#Model.AddressLine1</div>
<div class="display-label">Address Line 2: </div>
<div class="display-content">#Model.AddressLine2</div>
<div class="display-label">City: </div>
<div class="display-content">#Model.City</div>
</div>
I hope this helps.
What is the problem?
use in controller:
var model = new GetDocumentParent();
model.getDocument = ...//Code that initialize getDocument
model.getDocumentRevision =...//Code that initialize getDocumentRevision
in View:
#Html.EditorFor(m=>m.getDocument);
#Html.EditorFor(m=>m.getDocumentRevision);
I am trying to use dropdownList with two foreign keys which are modelId, and categoryId.
And I am using ViewBag with selectList.
public ActionResult Create()
{
ViewBag.categoryId = new SelectList(db.Category, "categoryId", "name");
ViewBag.modelId = new SelectList(db.Model, "modelId", "name");
return View();
}
//
// POST: /Product/Create
[HttpPost]
public ActionResult Create(Product product)
{
if (ModelState.IsValid)
{
db.Product.Add(product);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.categoryId = new SelectList(db.Category, "categoryId", "name", product.categoryId);
ViewBag.modelId = new SelectList(db.Model, "modelId", "name", product.modelId);
return View(product);
}
And here is my Create.cshtml.
<div class="editor-label">
#Html.LabelFor(model => model.Category)
</div>
<div class="editor-field">
#Html.DropDownList("categoryId", "--Select--")
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Model)
</div>
<div class="editor-field">
#Html.DropDownList("modelId", "--Select--")
</div>
When I press submit button, error come up,
'An item with the same key has already been added'
What is problem? Is it problem with in Model?
Here is my models.
--Prodruct.cs--
public class Product
{
[Key] public int productId { get; set; }
[Required(ErrorMessage = "Please select category")]
public int categoryId { get; set; }
[Required(ErrorMessage = "Please select model")]
public int modelId { get; set; }
[DisplayName("Model name")]
public String model { get; set; }
public virtual Category Category { get; set; }
public virtual Model Model { get; set; }
}
--Category.cs--
public class Category
{
[Key] public int categoryId { get; set; }
public String name { get; set; }
}
--Model.cs--
public class Model
{
[Key] public int modelId { get; set; }
public String name { get; set; }
}
--RentalDB.cs--
public class rentalDB : DbContext
{
public DbSet<Product> Product { get; set; }
public DbSet<Model> Model { get; set; }
public DbSet<Customer> Customer { get; set; }
public DbSet<Order> Order { get; set; }
public DbSet<Cart> Cart { get; set; }
public DbSet<Category> Category { get; set; }
public DbSet<OrderDetails> OrderDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Where it is wrong? Index page in Create can get category data and model data. However, when I submit it, it has error, 'An item with the same key has already been added'.
Could you help me where has got problem?
Thank you.
--added more coding--
I am using this LINQ. Probably here has problem.
How can I add 'Model' entity in here?
var product = from a in db.Product.Include(a => a.Category)
select a;
This is how I would have done it..
I would suggest that you don't send your domain models to the view, but rather create a view model for each view. Doing it this way you will only include what is needed on the screen.
Create a new view model for your Create view:
public class ProductCreateViewModel
{
// Include other properties if needed, these are just for demo purposes
public string Name { get; set; }
public string SKU { get; set; }
public string LongDescription { get; set; }
// This is the unique identifier of your category,
// i.e. foreign key in your product table
public int CategoryId { get; set; }
// This is a list of all your categories populated from your category table
public IEnumerable<Category> Categories { get; set; }
// This is the unique identifier of your model,
// i.e. foreign key in your product table
public int ModelId { get; set; }
// This is a list of all your models populated from your model table
public IEnumerable<Model> Models { get; set; }
}
Category class:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
}
Model class:
public class Model
{
public int Id { get; set; }
public string Name { get; set; }
}
In your Create view you would have the following:
#model MyProject.ViewModels.ProductCreateViewModel
#using (Html.BeginForm())
{
<table>
<tr>
<td><b>Category:</b></td>
<td>
#Html.DropDownListFor(x => x.CategoryId,
new SelectList(Model.Categories, "Id", "Name", Model.CategoryId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.CategoryId)
</td>
</tr>
<tr>
<td><b>Model:</b></td>
<td>
#Html.DropDownListFor(x => x.ModelId,
new SelectList(Model.Models, "Id", "Name", Model.ModelId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.ModelId)
</td>
</tr>
</table>
<!-- Add other HTML controls if required and your submit button -->
}
Your Create action methods:
public ActionResult Create()
{
ProductCreateViewModel viewModel = new ProductCreateViewModel
{
// Here you do database calls to populate your dropdowns
Categories = categoryService.GetAllCategories(),
Models = modelService.GetAllModels()
};
return View(viewModel);
}
[HttpPost]
public ActionResult Create(ProductCreateViewModel viewModel)
{
// Check that viewModel is not null
if (!ModelState.IsValid)
{
viewModel.Categories = categoryService.GetAllCategories();
viewModel.Models = modelService.GetAllModels();
return View(viewModel);
}
// Mapping
Product product = ... // Do your mapping here
// Insert product in database
productService.Insert(product);
// Return the view where you need to be
}
I would also recommend that you use AutoMapper to do the mappings for you between your domain model and view model. I would also recommend that you look at Fluent Validation to take care of your view model validations.
I hope this helps.
UPDATED ANSWER
The service that was used to get all the categories could look like this:
public class CategoryService : ICategoryService
{
private readonly ICategoryRepository categoryRepository;
public CategoryService(ICategoryRepository categoryRepository)
{
// Check if category repository is not null, throw exception if it is
this.categoryRepository = categoryRepository;
}
public IEnumerable<Category> GetAllCategories()
{
return categoryRepository.GetAllCategories();
}
}
categoryRepository is injected by Autofac.
Category service interface:
public interface ICategoryService
{
IEnumerable<Category> GetAllCategories();
}
I currently still use Entity Framework 4.1 code first.
My category repository:
public class CategoryRepository : ICategoryRepository
{
MyContext db = new MyContext();
public IEnumerable<Category> GetAllCategories()
{
return db.Categories
.OrderBy(x => x.Name);
}
}
My category repository interface:
public interface ICategoryRepository
{
IEnumerable<Category> GetAllCategories()
}
public class Test
{
rentalDB db = new rentalDB();
public Product LoadProductById(int pId)
{
return db.Products.Include(p => p.Model).Include(p => p.Category).Where(p => p.productId == pId).SingleOrDefault();
} // To get specific product.
public IEnumerable<Product> LoadAllProducts()
{
return db.Products.Include(p => p.Model).Include(p => p.Category).ToList();
} // To get all products.
}
I have changed your DbSet to Products make it more clear. This is how you load all the references for one product or all products, in order to iterate over them.
i have a model :
public class person
{
public int id{get;set;}
public string name{get;set;}
}
how can i make a drop down list, from list of person in mvc3 razor by this syntax : #Html.DropDownListFor(...) ?
what type must be my persons list?
sorry I'm new in mvc3
thanks all
public class PersonModel
{
public int SelectedPersonId { get; set; }
public IEnumerable<Person> persons{ get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
then in the controller
public ActionResult Index()
{
var model = new PersonModel{
persons= Enumerable.Range(1,10).Select(x=>new Person{
Id=(x+1),
Name="Person"+(x+1)
}).ToList() <--- here is the edit
};
return View(model);//make a strongly typed view
}
your view should look like this
#model Namespace.Models.PersonModel
<div>
#Html.DropDownListFor(x=>x.SelectedPersonId,new SelectList(Model.persons,"Id","Name","--Select--"))
</div>
You should translate that to a List<SelectListItem> if you want to use the build in MVC HtmlHelpers.
#Html.DropDownFor(x => x.SelectedPerson, Model.PersonList)
Alternatively, you can simply make your own in the template:
<select id="select" name="select">
#foreach(var item in Model.PersonList)
{
<option value="#item.id">#item.name</option>
}
</select>