ASP.NET Core - Entity Framework Core: Access relationship when posting a typed form - asp.net-core

I am posting a form in ASP.NET Core. I have an HTML element that shows a list of colors. The values of the select's options are mapped to ids in the color table. The problem is that I want to access the name of color in the back-end but I am getting a null reference. How can I remedy this in a good way?
Model
Carro
{
[Column("id_color")]
public int IdColor { get; set; }
[ForeignKey("IdColor")]
public Color Color { get; set;}
}
[Table("color")]
public class Color
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("color_name")]
public string ColorName{ get; set; }
}
}
My select html element is using a typed Car form.
#model Car
<form asp-route="store_car" enctype="multipart/form-data">
<div>
<label>Cor</label>
<select asp-for="IdColor" class="form-control" id="selectCoresCarro"></select>
</div>
My Action
[HttpPost]
[Route("/carros/anunciar", Name = "store_car")]
public IActionResult CadastrarCarro(Car car){
car.Color.ColorName; // Color is undefined.
}
Can someone give a good solution for this. I didn't want to write code to query the database.

Related

Problem when submit a form with select tag helper asp.net core 6

I want to use select tag helper to choose a role for creating account in my web app.
The following is my code
[HttpGet]
public ActionResult Create()
{
var model = new AccountCreateViewModel()
{
Roles = new SelectList(_roleManager.Roles, "Id", "Name").ToList()
};
return View(model);
}
The following is the code in view of the select.
<div class="form-floating">
<select asp-for="RoleId" asp-items="#Model.Roles" class="form-select"></select>
<label asp-for="RoleId"></label>
<span asp-validation-for="RoleId" class="text-danger"></span>
</div>
<input type="submit" class="w-100 btn btn-lg btn-primary" />
The following is my model
public class AccountCreateViewModel
{
public RegisterModel.InputModel Input { get; set; } = new();
[StringLength(50)]
[Required]
public string FullName { get; set; }
[DataType(DataType.Date)]
public DateTime? BirthDate { get; set; } = null;
[StringLength(80)]
public string Address { get; set; }
[Required]
[Display(Name = "Role")]
public string RoleId { get; set; }
public List<SelectListItem> Roles { get; set; }
}
However, after I submit the form, then the controller check the model state, and it is invalid. I have debugged and all the fields is valid except Roles.
So, someone can give me a solution for this situation?
model state debugging
Apply [ValidateNever] attribute to remove validate of the Roles on the server side. When applied to a property, the validation system excludes that property.
public class AccountCreateViewModel
{
...
[ValidateNever]
public List<SelectListItem> Roles { get; set; }
}
Consider that a SelectList takes an object of type IEnumerable as the first argument in the constructor. Make sure that you give it an IEnumerable or List in this section:
Roles = new SelectList(_roleManager.Roles, "Id", "Name").ToList()
This code may help you:
Roles = new SelectList(_roleManager.Roles.ToList(), "Id", "Name")
If _roleManager.Roles returns an IEnumerable or List, you don't need the .ToList()

ASP.NET Core filter a list using a multi-select List Box

I have a standard razor page using the "List" template that I have added a dropdown to filter which records are shown. I used the code example from here: https://learn.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/search?view=aspnetcore-3.1
Using the tutorial's "Search by Genre" section.
I have it working but would like users to be able to select multiple items from the list to use as filters. I added "multiple" to the select tag and I can select multiple items, but it only processes the first item selected.
How can I have multiple items added to the filter so that all selected values are displayed on the list?
After adding "multiple" to the select tag, you need to modify the received model MovieGenre. For example:
public class IndexModel : PageModel
{
[BindProperty(SupportsGet = true)]
public string SearchString { get; set; }
public SelectList Genres { get; set; }
[BindProperty(SupportsGet = true)]
public List<string> MovieGenre { get; set; }
public void OnGet()
{
// Transfer data here.
Genres = new SelectList(new List<Genre> {
new Genre{id=1,GenreName="Genre1"},
new Genre{id=2,GenreName="Genre2"},
new Genre{id=3,GenreName="Genre3"},
},"id", "GenreName");
}
}
public class Genre
{
public int id { get; set; }
public string GenreName { get; set; }
}
In Index.cshtml:
<form>
<select asp-for="MovieGenre" asp-items="Model.Genres" multiple>
<option value="">All</option>
</select>
<input type="submit" value="Filter" />
</form>
Then, it will get Multiple MovieGenre.
result:

Null viewmodel passed to controller

I have a basic 'create' view scaffolded from a domain model, so it is typed to the model
#model TblProduct
<form asp-controller="Product" asp-action="Create">
...
<input asp-for="Artist" class="form-control" />
...
I'm trying to add functionality and use a view model instead, and I'm starting with a very basic viewmodel with only that domain model within it:
public class ProductViewModel
{
public TblProduct P { get; set; }
}
Now I've changed the 'create' view to use the view model instead
#model ProductViewModel
<form asp-controller="Product" asp-action="Create">
...
<input asp-for="P.Artist" class="form-control" />
...
So I expect the model to be valid given that (aside from editing the variable names) I'm populating all the same fields from the form, and effectively no other fields have been added to the model.
An error occurs when I post the form, I pass a ProductViewModel parameter to the create method but on inspection it is null. However ModelState.IsValid is true. So the code tries to write to the db and fails.
public async Task<IActionResult> Create([Bind("ID,Artist,ProductTitle... (long list removed)...] ProductViewModel productAndItems)
{
var prod = productAndItems.P;
if (ModelState.IsValid)
{
_context.Add(prod);
...FAIL
Any idea what I should be checking here - what am I missing?
How do I get the view (typed to a viewmodel) to pass the model data to the controller? And if it's null, how can ModelState.IsValid be true? In the example above I have debugged, the parameter passed in productAndItems is null.
Your current Bind attribute is looking for the following properties ID,Artist,ProductTitle... (White-list) and it's not finding them so therefore it's ignore everything and treating it is as a (Black-list) item.
You can either decorate your ProductViewModel with the Bind attribute as follows:
[Bind(Include = "P")]
public class ProductViewModel
{
public TblProduct P { get; set; }
}
This will of course mean all the properties in the TblProduct will be bound when submitting
If you do not want all of the properties to be bound on submit for TblProduct then you can decorate the TblProduct with the Bind attribute as follows
public class ProductViewModel
{
public TblProduct P { get; set; }
}
[Bind(Include = "ID,Artist,ProductTitle")]
public class TblProduct
{
public int ID { get; set; }
public string Artist { get; set; }
public string ProductTitle { get; set; }
public string ProductSubTitle { get; set; } //we will not include this in our (White-list)
//more props
}
More reading at MSDN
you need to add a name attribute to your form so the controller will pick it up.

How to access many to many object in .NET MVC via Razor

Using EF 7 I have an object that references a many to many table, using code first method.
public class EventUser
{
public string UserId { get; set; }
public User User { get; set; }
public int EventId { get; set; }
public Event Event { get; set; }
public string AdditionalInfo { get; set; }
}
I can pull a list of these when knowing EventId and display them in Razor. I want to link to each one of these objects back to the controller so a user could edit the AdditionalInfo field. Since the object doesn't have just one Id field, how can I send the appropriate data to the controller to access this object, since just using one Id will not be enough.
At this point, I can achieve this using:
<a asp-action="EditEventUser" asp-route-EventId="EventUser.EventId" asp-route-UserId="EventUser.UserId">Edit Event User</a>
But, I would like to know if I am ignorant about some other way this can be achieved in a cleaner way (if there is such a way).

ASP.NET MVC 4 database scaffolding self referential model

I have a constructed a model using code first in C#. The model literally represents a container element for a website building application, in other words, the model defines a Div tag or some such HTML element. Like a Div tag which can contain multiple child elements, I have tried to represent this in my model, but the scaffolding to the DB, does not give me what I'd expect.
I should get a new many to many joins table, but instead I only get a single column in the DB which expects a single int data type.
Here is the model:
public class ElementContainer
{
public int ElementContainerID { get; set; }
public int PageId { get; set; }
public int? ParentElementContainerID { get; set; }
public string ElementContainerName { get; set; }
public ElementType ElementType { get; set; }
public string ElementClass { get; set; }
public PageAsset PageAsset { get; set; } // content of container
public List<ElementContainer> NestedContainers { get; set; }
}
The last line is the self-referential attribute which just appears as a column called ElementContainer_ElementContainerID
Thanks in advance!
I agree with Bahman, DB first is easier.
While I haven't tried to do what you are trying, your code looks like a self-Join that would do exactly what you describe.
This is a One-to-Many relationship. EF Navigation will pull a List of all nested children containers.
If you want to create a many-to-many relationship with EF Code-First, you should create another Entity
public class ContainerChildren
{
public int ElementContainerID { get; set; }
public List<ElementContainer> NestedContainers { get; set; }
}
this reference should help you to get the exact idea http://blogs.msdn.com/b/wriju/archive/2011/05/14/code-first-ef-4-1-building-many-to-many-relationship.aspx