I have two models like below.
public class Bill
{
public int Id { get; set; }
public string InvoiceNumber { get; set; }
public Int64 Amount { get; set; }
public int? NewPaymentId { get; set; }
public virtual NewPayment RelPayment { get; set; }
}
public class NewPayment
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LstName { get; set; }
public DateTime PaymentDate { get; set; }
public Int64 ProvisionNumber { get; set; }
public Int64 CreditCardNumber { get; set; }
public int ExpMonth { get; set; }
public int ExpYear { get; set; }
public int Cv2 { get; set; }
public Int64 Amount { get; set; }
public string UserId { get; set; }
public string CustomerNote { get; set; }
}
Customer is going to pay his invoices via credit card in my application.
I had one view which i posted the NewPayment model to the action. But now, i need to send also which invoices will be paid. So i need to create one more form for the Bill model i think ? But i cant figure out how can i pass two model to same action and i dont know the NewPaymentId before executing the payment method.
REGARDING TO THE COMMENTS :
My combine model as below :
public class Payment
{
public IEnumerable<Bill> Bill { get; set; }
public NewPayment NewPayment { get; set; }
}
And my view as below :
#model IEnumerable<ModulericaV1.Models.Bill>
<form class="form-no-horizontal-spacing" id="NewPayment" action="/NewPayment/AddInvoice" method="post">
<div class="row column-seperation">
<div class="col-md-6">
<h4>Kart Bilgileri</h4>
<div class="row form-row">
<div class="col-md-5">
<input name="FirstName" id="FirstName" type="text" class="form-control" placeholder="Kart Üzerindeki Ad">
</div>
<div class="col-md-7">
<input name="LastName" id="LastName" type="text" class="form-control" placeholder="Kart Üzerindeki Soyad">
</div>
</div>
<div class="row form-row">
<div class="col-md-12">
<input name="CreditCardNumber" id="CreditCardNumber" type="text" class="form-control" placeholder="Kart Numarası">
</div>
</div>
<div class="row form-row">
<div class="col-md-5">
<input name="ExpYear" id="ExpYear" type="text" class="form-control" placeholder="Son Kullanma Yıl (20..)">
</div>
<div class="col-md-7">
<input name="ExpMonth" id="ExpMonth" type="text" class="form-control" placeholder="Son Kullanma Ay (1-12)">
</div>
</div>
<div class="row form-row">
<div class="col-md-5">
<input name="Cv2" id="Cv2" type="text" class="form-control" placeholder="Cv2">
</div>
<div class="col-md-7">
<input name="Amount" id="Amount" type="text" class="form-control" placeholder="Miktar TL ">
</div>
</div>
<div id="container">
<input id="Interests_0__Id" type="hidden" value="" class="iHidden" name="Interests[0].Id"><input type="text" id="InvoiceNumber_0__InvoiceNumber" name="[0].InvoiceNumber"><input type="text" id="Interests_0__InterestText" name="[0].Amount"> <br><input id="Interests_1__Id" type="hidden" value="" class="iHidden" name="Interests[1].Id"><input type="text" id="InvoiceNumber_1__InvoiceNumber" name="[1].InvoiceNumber"><input type="text" id="Interests_1__InterestText" name="[1].Amount"> <br>
</div>
<input type="button" id="btnAdd" value="Add New Item" />
<button class="btn btn-danger btn-cons" type="submit"> Ödemeyi Gerçekleştir</button>
</form>
</div>
</div>
In my controller, i am getting payment model as null.
public ActionResult AddInvoice(Payment payment) {
foreach (var item in payment.Bill)
{
var Billing = new Bill();
Billing.Amount = item.Amount;
Billing.InvoiceNumber = item.InvoiceNumber;
db.Bill.Add(Billing);
db.SaveChanges();
}
return View();
}
}
i complete Marko with an example
public class CombineModel
{
public Bill Bill{ get; set; }
public NewPayment NewPayment{ get; set; }
}
You appear to already have the solution in your model. Your bill object can hold a reference to a related new payment. You can either lazy read the new payment from database or you could assign a new newpayment object to the bill before sending to the view.
View models are good practice, but you might be happy levering the model you have naturally as I just described.
Update
Sorry, this should be:
The other way around - Pass in NewPayment
Add public IEnumarable<Bill> Bills {get; set;} to NewPayment model
And that way, you can access the Bills associated with the given payment.
Code first stuff:
You should decorate Bill's RelPayment with [ForeignKey("NewPaymentID"], so EF (I assume you are using Entity Framework), knows how to wire up the relationship.
You will also likely need to add the following Bills = new List<Bill>(); into a NewPayment constructor.
If you don't like Zakos Solution you can make tuple :
var tuple= new Tuple<Bill,NewPayment>(obj1,obj2);
And in view you will have :
#model Tuple<Bill,NewPayment>
But you should use #Zakos solution.
So you can use ViewModel, take this ViewModel:
public class PaymentBillViewModel
{
public int BillId { get; set; }
public int PaymentId { get; set; }
public string InvoiceNumber { get; set; }
public Int64 Amount { get; set; }
public int? NewPaymentId { get; set; }
public virtual NewPayment RelPayment { get; set; }
public int Id { get; set; }
public string FirstName { get; set; }
public string LstName { get; set; }
public DateTime PaymentDate { get; set; }
public Int64 ProvisionNumber { get; set; }
public Int64 CreditCardNumber { get; set; }
public int ExpMonth { get; set; }
public int ExpYear { get; set; }
public int Cv2 { get; set; }
public Int64 Amount { get; set; }
public string UserId { get; set; }
public string CustomerNote { get; set; }
}
actually put what you need in your View. then in the post action cast the ViewModel to the related Model:
[HttpPost]
public ActionResult Sample(PaymentBillViewModel model)
{
if (ModelState.IsValid)
{
var obj=new NewPayment
{
LstName= model.LstName,
Amount=model.Amount,
//... cast what else you need
}
}
return View();
}
you can use Automapper on casting, for more info about using Automapper take a look at this article.
Related
I'm working on a small library website where you should be able to post a comment to each individual book. The problem is in my view that I can't say "Asp-for='BookComment.Name'" since my BookComment is a list in my Book Model
My Book Model
public class Book
{
[Key]
public int BookID { get; set; }
[Required]
[Column(TypeName = "Varchar(75)")]
public string Title { get; set; }
[Required]
[Column(TypeName = "Varchar(75)")]
public string Author { get; set; }
[Required]
[Column(TypeName = "Varchar(13)")]
public string Isbn { get; set; }
[Required]
[Column(TypeName = "Varchar(50)")]
public string Publisher { get; set; }
public int Sites { get; set; }
public DateTime ReleaseDate { get; set; }
public string Summary { get; set; }
public string Picture { get; set; }
public DateTime AddedDate { get; set; }
public int Stars { get; set; }
public List<BookCategory> BookCategory { get; set; } = new List<BookCategory>();
public List<BookComment> BookComment { get; set; } = new List<BookComment>();
}
BookComment Model:
public class BookComment
{
[Key]
public int BookCommentID { get; set; }
[Required]
public int BookID { get; set; }
[Column(TypeName = "Varchar(50)")]
public string Name { get; set; }
[Column(TypeName = "Varchar(100)")]
public string Email { get; set; }
public string Review { get; set; }
public DateTime Date { get; set; }
public decimal Stars { get; set; }
}
My Book Controller
public class BookController : Controller
{
private readonly ApplicationDbContext _db;
public BookController(ApplicationDbContext db)
{
_db = db;
}
public IActionResult Book(int? id)
{
var book = _db.Books.Include(o => o.BookComment).FirstOrDefault(p => p.BookID == id);
return View(book);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Book(BookComment comment)
{
_db.bookComments.Add(comment);
_db.SaveChanges();
return RedirectToAction("Book");
}
}
Snippet of my form
#model LibraryNew.Models.Book
<h5 class="mt-4">Tilføj en anmeldelse</h5>
<p>Din email vil ikke blive offentliggjort</p>
<form asp-action="Book" method="post"></form>
<div class="my-3">
<div class="form-group">
<label for="exampleFormControlSelect1">Antal stjerner:</label>
<select class="form-control col-md-1" id="exampleFormControlSelect1">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="1">5</option>
</select>
</div>
</div>
<div class="form-group">
<label for="exampleFormControlInput1">Email address</label>
<input type="email" class="form-control" id="exampleFormControlInput1" placeholder="name#example.com">
</div>
<div class="form-group">
<label for="exampleFormControlInput1">Email address</label>
<input type="email" class="form-control" id="exampleFormControlInput1" placeholder="name#example.com">
</div>
<div class="form-group">
<label for="exampleFormControlTextarea1">Example textarea</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea>
</div>
I can't say <select asp-for="BookComment.Stars"
Any help is appreciated. If any further information is needed please let me know!
In your view code try replacing #model LibraryNew.Models.Book with #model LibraryNew.Models.BookComment so you can have access to it in asp-for since what you are trying to do is post a single BookComment to add it to a book in your controller.
It looks like what is needed is to be able to use different models in a single page to achieve this you can create a single class that contains the models you will need for a single page for example
public class BookLibrary
{
public Book Book { get; set; }
public BookComment BookComment { get; set; }
public Author Author{ get; set; }
}
then in your view code you use #model LibraryNew.Models.BookLibrary and in your asp-for you will be able to access BookComment by using Model.BookComment
I have some problem.
I have next model:
public class DocumentViewModel
{
public string Nazvanie { get; set; }
public Author DocumentAutors { get; set; }
}
public class Author
{
public long Id { get; set; }
public List<IPerson> Authors { get; set; }
}
public interface IPerson
{
long Id { get; set; }
}
public class PersonUL : IPerson
{
public long Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
public class PersonIP : IPerson
{
public long Id { get; set; }
public string FirstName { get; set; }
public string SecondNAme { get; set; }
public string PostAddress { get; set; }
}
In .cshtml
#model DocumentViewModel
#if (Model.DocumentAutors.Authors != null && Model.DocumentAutors.Authors.Count > 0)
{
for (int i = 0; i < Model.DocumentAutors.Authors.Count; i++)
{
if (Model.DocumentAutors.Authors is PersonUL )
{
<div class="form-group">
<label asp-for="#Model.DocumentAutors.Authors[i].Name" class="col-md-10 control-label"></label>
<div class="col-md-10">
<input asp-for="#Model.DocumentAutors.Authors[i].Name" class="form-control" />
<span asp-validation-for="#Model.DocumentAutors.Authors[i].Name" class="text-danger"></span>
</div>
</div>
}
}
}
Model.DocumentAutors.Authors[i] don't contain "Name" field, because it's interface. I need cast it, but if i write
if (Model.DocumentAutors.Authors is PersonUL )
{
PersonUL ul = (PersonUL)Model.DocumentAutors.Authors[i];
<div class="form-group">
<label asp-for="#ul.Name" class="col-md-10 control-label"></label>
<div class="col-md-10">
<input asp-for="#ul.Name" class="form-control" />
<span asp-validation-for="#ul.Name" class="text-danger"></span>
</div>
</div>
}
i will get html with wrong name like this
<input class="form-control" type="text" id="Name" name="Name" value="566">
instead
<input class="form-control" type="text" id="DocumentAutors.Authors[0].Name" name="DocumentAutors.Authors[0].Name" value="566">
and ModelBinder will not bint this field into Authors List.
Is there a solution for this problem or should I make one generic model for PersonUL and PersonIP with all fields, which I don't really like it?
I am sorry but IMHO I don't see any advantages in the interface. It only makes the code more confused.
Why you don't try
public class Author
{
public long Id { get; set; }
public List<PersonIP> IpAuthors { get; set; }
public List<PersonUL> UlAuthors { get; set; }
}
or even better
public class DocumentViewModel
{
public string Nazvanie { get; set; }
public long AuthorId { get; set; }
public List<PersonIP> IpAuthors { get; set; }
public List<PersonUL> UlAuthors { get; set; }
}
Let's say I have this view model. Bear in mind, this is a view model. Not the domain/entity model.
public class Cart
{
public string Name { get; set; }
public int Qty { get; set; }
public decimal Price { get; set; }
public decimal TotalPrice { get; set; }
}
How do I scaffold to create CRUD Razor Page ?
Here is a demo ,you could refer to :
OrderItem Entity model and Cart View model, the View Model is related to the presentation layer of our application. They are defined based on how the data is presented to the user rather than how they are stored.
public class OrderItem
{
public int Id { get; set; }
public int Qty { get; set; }
public decimal Price { get; set; }
public decimal TotalPrice { get; set; }
public Product Product { get; set; }
}
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
}
public class Cart
{
public string Name { get; set; }
public int Qty { get; set; }
public decimal Price { get; set; }
public decimal TotalPrice { get; set; }
}
public class RazorPagesDbContext:DbContext
{
public RazorPagesDbContext(DbContextOptions<RazorPagesDbContext> options):base(options)
{ }
public DbSet<Product> Product { get; set; }
public DbSet<OrderItem> OrderItem { get; set; }
}
The CreateOrder Razor Page
#page
#model RazorPages2_2.Pages.Carts.CreateOrderModel
#{
ViewData["Title"] = "CreateOrder";
}
<h1>CreateOrder</h1>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Cart.Name" class="control-label"></label>
<input asp-for="Cart.Name" class="form-control" />
<span asp-validation-for="Cart.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Cart.Price" class="control-label"></label>
<input asp-for="Cart.Price" class="form-control" />
<span asp-validation-for="Cart.Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Cart.Qty" class="control-label"></label>
<input asp-for="Cart.Qty" class="form-control" />
<span asp-validation-for="Cart.Qty" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Cart.TotalPrice" class="control-label"></label>
<input asp-for="Cart.TotalPrice" class="form-control" />
<span asp-validation-for="Cart.TotalPrice" 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-page="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
The CreateOrder page model, the Cartproperty uses the [BindProperty] attribute to opt-in to model binding. When the Create form posts the form values, the ASP.NET Core runtime binds the posted values to the Cart model then put the values into the entity model.
public class CreateOrderModel : PageModel
{
private readonly RazorPagesDbContext _context;
public CreateOrderModel(RazorPagesDbContext context)
{
_context = context;
}
public IActionResult OnGet()
{
var product = _context.Product.FirstOrDefault();
Cart = new Cart
{
Name = product.ProductName,
Price = product.Price,
Qty = 2,
TotalPrice = product.Price * 2
};
return Page();
}
[BindProperty]
public Cart Cart { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var product = _context.Product.SingleOrDefault(p => p.ProductName == Cart.Name);
OrderItem orderItem = new OrderItem
{
Price = Cart.Price,
Qty = Cart.Qty,
TotalPrice = Cart.TotalPrice,
Product = product
};
_context.OrderItem.Add(orderItem);
await _context.SaveChangesAsync();
return RedirectToPage("../Index");
}
}
Result:
You could refer to the offocial doc about the Razor pages to create the page you want .
CODE BEHIND :
public class IndexModel : PageModel
{
private readonly ApplicationDbContext _db;
public IndexModel(ApplicationDbContext db)
{
_db = db;
}
public IEnumerable<Cart> Carts { get; set; }
public async Task OnGet()
{
Books = await _db.Carts.ToListAsync();
}
}
You need :
public class ApplicationDbContext:DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
{
}
public DbSet<Cart> carts { get; set; }
}
for the View :
#model CardList.IndexModel
My question is: How to build html markup in razor pages and the LINQ queries (in the backend) to bring a checkbox list of all my SubCategoies in the EDIT and CREATE views.
Allowing me to create a product with multiple subcategories and also updating them at any time in the EDIT view.
Using .Net EF Core 2.2, Razor Pages.
Main class (Product):
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Category Category { get; set; }
public List<ProductSubcategory> SubCategories { get; set; }
}
Product has a many-to-many relationship with Subcategory:
public class SubCategory
{
public int Id { get; set; }
public string Name { get; set; }
public List<ProductSubcategory> SubCategories { get; set; }
}
So the join table (entity) is ProductSubcategory:
public class ProductSubcategory
{
public int ProductId { get; set; }
public Product Product { get; set; }
public int SubCategoryId { get; set; }
public SubCategory SubCategory { get; set; }
}
The Edit (and create) Product view:
<h2>Editar: #Model.Product.Name</h2>
<form method="post">
<input type="hidden" asp-for="Product.Id" />
<div class="form-group">
<label asp-for="Product.Name"></label>
<input asp-for="Product.Name" class="form-control" />
<span class="text-danger" asp-validation-for="Product.Name"></span>
</div>
<div class="form-group">
<label asp-for="Product.Description"></label>
<textarea asp-for="Product.Description" class="form-control"></textarea>
<span class="text-danger" asp-validation-for="Product.Description"></span>
</div>
<div class="form-group">
<label asp-for="Product.Category"></label>
<select class="form-control" asp-for="Product.Category" asp-items="Model.Categories"></select>
<span class="text-danger" asp-validation-for="Product.Category"></span>
</div>
<div class="form-group">
//Code to allow the subcategory selection.
//preferable as checkboxes
//() subcat1 (x)subcat2 ()subcat3
//() subcat4 ()subcat5 (x)subcat6
</div>
<button type="submit" class="btn btn-primary">Salvar</button>
</form>
The Edit.cshtml.cs PageModel
public class EditModel : PageModel
{
private readonly IProductData _ProductData;
private readonly IHtmlHelper _HtmlHelper;
[BindProperty]
public Product Product { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
public string MessageCreate { get; set; }
public EditModel(IProductData _productData, IHtmlHelper _htmlHelper)
{
_ProductData = _productData;
_HtmlHelper = _htmlHelper;
}
public IActionResult OnGet(int? productId)
{
Categories = _HtmlHelper.GetEnumSelectList<Category>();
if (productId.HasValue)
{
Product = _ProductData.GetById(productId.Value);
}
else
{
MessageCreate = "Criar novo Produto";
Product = new Product();
}
if (Product == null)
{
return RedirectToPage("./NotFound");
}
return Page();
}
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
Categories = _HtmlHelper.GetEnumSelectList<Category>();
return Page();
}
if (Product.Id > 0)
{
_ProductData.Update(Product);
}
else
{
_ProductData.Create(Product);
}
_ProductData.Commit();
TempData["Message"] = "Produto salvo!!!";
//PRG POST-REDIRECT-GET
return RedirectToPage("./Detail", new { productId = Product.Id });
}
}
The checkbox is used to represent a boolean property. I see you don't have a bool property so I suppose you need to add a Boolean property in SubCategories class like:
public bool IsChecked { get; set; } // added this property
Then you need to add a property to your PageModel(Edit or Create) to represent the data and ensured that posted values will be bound to it:
[BindProperty]
public List<Subcategory> SubCategories { get; set; } = new List<Subcategory>();
At the end all you need is to get the model binder to associate each checkbox with a specific Subcategory. The following code shows my example in .cshtml file:
#for (var i = 0; i < Model.SubCategories.Count(); i++)
{
<input asp-for="SubCategories[i].IsChecked" />
}
I'm trying to make a form that i could save a file(image) , but it shows me an error:
InvalidOperationException: The property 'Product.Image' is of an interface type ('IFormFile'). If it is a navigation property manually configure the relationship for this property by casting it to a mapped entity type, otherwise ignore the property from the model.
Apply
I dont know how to fix it , here's the code:
Product.cs
public class Product
{
public Product()
{
OrderDetails = new HashSet<OrderDetails>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int? CategoryId { get; set; }
public decimal? Price { get; set; }
public int? Quantity { get; set; }
public string ImagePath { get; set; }
public virtual ICollection<OrderDetails> OrderDetails { get; set; }
public virtual Category Category { get; set; }
}
ProductFormViewModel.cs
public class ProductFormViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int? CategoryId { get; set; }
public decimal? Price { get; set; }
public int? Quantity { get; set; }
public IFormFile Image { get; set; }
}
Create Action
[HttpGet]
public IActionResult Create()
{
var categories = _repository.GetCategories().ToList();
var categoriesModel = categories.Select(p => new
{
p.Id,
p.Name
});
ViewBag.Categories = new SelectList(categoriesModel, "Id", "Name");
return View();
}
[HttpPost]
public IActionResult Create(ProductFormViewModel product)
{
var file = product.Image; // **it returns NULL**
var upload = Path.Combine(_environment.ContentRootPath, "wwwroot\\uploads", product.Name);
if (!Directory.Exists(upload))
Directory.CreateDirectory(upload);
var filePath = Path.Combine(upload, file.FileName);
if (file.Length > 0)
{
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
file.CopyTo(fileStream);
}
}
var producti = new Product();
producti.CategoryId = product.CategoryId;
producti.Description = product.Description;
producti.Name = product.Name;
producti.Price = product.Price;
producti.Quantity = product.Quantity;
producti.ImagePath = filePath;
_repository.AddProduct(producti);
_repository.SaveChanges();
return RedirectToAction("Index","Products");
}
Create.cshtml
#model ProductFormViewModel
<br />
<br />
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
</div>
<div class="panel-body">
<form class="form-group" asp-action="Create" asp-controller="Products" method="post">
<input type="hidden" asp-for="Id"/>
<div class="col-md-12">
<div class="form-group col-md-6">
<label asp-for="Name" class="control-label col-md-3"></label>
<input asp-for="Name" type="text" class="form-control col-md-3"/>
</div>
<div class="form-group col-md-6">
<label asp-for="CategoryId" class="control-label col-md-3"></label>
<select asp-for="CategoryId" asp-items="#ViewBag.Categories" class="form-control col-md-3">
<option hidden disabled selected >Select One</option>
</select>
</div>
<div class="form-group col-md-6">
<label asp-for="Description" class="control-label col-md-3"></label>
<textarea asp-for="Description" class="form-control" rows="4"></textarea>
</div>
<div class="form-group col-md-6">
<label asp-for="Price" class="control-label col-md-3"></label>
<input type="text" asp-for="Price" class="form-control col-md-3"/>
</div>
<div class="form-group col-md-6">
<label asp-for="Quantity" class="control-label col-md-3"></label>
<input type="text" asp-for="Quantity" class="form-control col-md-3"/>
</div>
<div class="form-group col-md-12">
<label class="control-label">Select Image</label>
<input asp-for="Image" type="file" class="btn-file"/>
</div>
<div class="form-group col-md-12 text-center">
<input type="submit" class="btn btn-success" value="Save"/>
</div>
</div>
</form>
</div>
</div>
</div>
IFormFile is a type used by the ASP.NET Core framework and it does not have a sql server type equivalent.
For your domain model store it as byte[] and when you work with views, is ok for you to use the IFormFile type.
ProductModel:
public class Product
{
public Product()
{
OrderDetails = new HashSet<OrderDetails>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int? CategoryId { get; set; }
public decimal? Price { get; set; }
public int? Quantity { get; set; }
public string ImagePath { get; set; }
public virtual ICollection<OrderDetails> OrderDetails { get; set; }
public virtual Category Category { get; set; }
}
ProductViewModel:
public class ProductViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int? CategoryId { get; set; }
public decimal? Price { get; set; }
public int? Quantity { get; set; }
public IFormFile Image { get; set; }
}
Controller method:
[HttpGet]
public IActionResult Create()
{
var categories = _repository.GetCategories().ToList();
var categoriesModel = categories.Select(p => new
{
p.Id,
p.Name
});
ViewBag.Categories = new SelectList(categoriesModel, "Id", "Name");
return View();
}
[HttpPost]
public IActionResult Create(ProductViewModel model)
{
// Save the image to desired location and retrieve the path
// string ImagePath = ...
// Add to db
_repository.Add(new Product
{
Id = model.Id,
ImagePath = ImagePath,
// and so on
});
return View();
}
Also specify to the form enctype="multipart/form-data" in your view.
using System.ComponentModel.DataAnnotations.Schema;
namespace model{
public class ProductViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int? CategoryId { get; set; }
public decimal? Price { get; set; }
public int? Quantity { get; set; }
[NotMapped]
public IFormFile Image { get; set; }
}
}