Adding images to ASP.net core - c#

I wanted to add an image as part of the model class and display it on the index view. I'm having problems either classifying the image as a byte[] or iFormFile.
This is what I'm trying to achieve
Create a page to insert a list of employees
In the index page, able to list the employees and see their images as well.
Here's the model.
Employee.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace MvcMovie.Models
{
public class Employee
{
public int ID { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Nationality { get; set; }
[Required]
public string NRIC { get; set; }
[Required]
public string StaffID { get; set; }
[Required]
public int AccessRights { get; set; }
[Required]
public DateTime DOB { get; set; }
[Required(ErrorMessage = "Please Upload a Valid Image File. Only jpg format allowed")]
[DataType(DataType.Upload)]
[Display(Name = "Upload Product Image")]
[FileExtensions(Extensions = "jpg")]
public IFormFile Image { get; set; }
public string ImageName { get; set; }
}
}
This is the section of code of the controller that generates the error.
EmployeeController.cs
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Employee employee, IFormFile Image)
{
if (ModelState.IsValid)
{
if (Image != null && Image.Length > 0)
{
var file = Image;
var uploads = Path.Combine(_environment.WebRootPath, "uploads\\img\\employees");
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse
(file.ContentDisposition).FileName.Trim('"');
System.Console.WriteLine(fileName);
using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
employee.ImageName = Path.Combine(uploads, file.FileName);
}
var imageUrl = Path.Combine(uploads + file.FileName);
}
}
_context.Add(employee);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
else
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
}
return View(employee);
}
Create.cshtml
<form asp-action="Create" enctype="multipart/form-data" asp-antiforgery="true" method="post">
<div>
...
<div class="form-group">
<label asp-for="Image" class="control-label col-md-2"></label>
<div class="col-md-10">
<input asp-for="Image" class="form-control" />
<span class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</form>
I managed to upload the image into the correct folder. However, i have problem with the statement "_context.Add(employee)". It says that I couldn't add an iformfile. I've no issue with the other fields.
I tried changing Employee.Image to a byte array. However, I'm confused how to structure my view to pass this information to the create function.

Like what ar27111994 suggested, I store the image name and extension instead. The image is saved somewhere in wwwroot.
Here's the change
Employee.cs
public class Employee
{
[Key]
public int ID { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Nationality { get; set; }
[Required]
public string NRIC { get; set; }
[Required]
public string StaffIdentity { get; set; }
[Required]
public int AccessRights { get; set; }
[Required]
public DateTime DOB { get; set; }
public string ImageName { get; set; }
}
create.cshtml
<div class="form-group">
<label class="col-md-2 control-label">Employee Image</label>
<div class="col-md-10">
<input class="form-control" type="file" name="pic" accept="image/*"/>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
EmployeeController.cs
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,AccessRights,DOB,FirstName,LastName,NRIC,Nationality,StaffIdentity")]Employee employee)
{
if (ModelState.IsValid)
{
var files = HttpContext.Request.Form.Files;
foreach (var Image in files)
{
if (Image != null && Image.Length > 0)
{
var file = Image;
var uploads = Path.Combine(_environment.WebRootPath, "uploads\\img\\employees");
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse
(file.ContentDisposition).FileName.Trim('"');
System.Console.WriteLine(fileName);
using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create))
{
await file.CopyToAsync(fileStream);
employee.ImageName = file.FileName;
}
}
}
}
_context.Add(employee);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
else
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
}
return View(employee);
}

Related

How to get image from form

I've made a website and can't get image from form. When I inputted all dates and chose image and click on "Submit", image doesn't get from form. I need to get image from form and convert to array of bytes to write in database.
This is my code:
[HttpPost]
public IActionResult Post([FromForm] Products product)
{
Images image = new Images();
if (ModelState.IsValid && product != null && !(string.IsNullOrEmpty(product.Name)) && product.price != 0 && !(string.IsNullOrEmpty(product.description)) && product.CategoryId != 0)
{
//insert
string query = #"insert into dbo.Product values('" + product.Name + #"'," + product.price + #",'" + product.description + #"',"+ product.CategoryId + #")";
DataTable table = new DataTable();
string sqlDataSource = _configuration.GetConnectionString("CommandsConnection");
SqlDataReader myReader;
using (SqlConnection myCon = new SqlConnection(sqlDataSource))
{
myCon.Open();
using (SqlCommand myCommand = new SqlCommand(query, myCon))
{
myReader = myCommand.ExecuteReader();
table.Load(myReader);
myReader.Close();
myCon.Close();
}
}
//select
string query2 = #"select id from dbo.Product where Name= '" + product.Name + #"'";
DataTable table2 = new DataTable();
string sqlDataSource2 = _configuration.GetConnectionString("CommandsConnection");
SqlDataReader myReader2;
using (SqlConnection myCon = new SqlConnection(sqlDataSource2))
{
myCon.Open();
using (SqlCommand myCommand = new SqlCommand(query2, myCon))
{
myReader2 = myCommand.ExecuteReader();
table2.Load(myReader2);
myReader2.Close();
myCon.Close();
}
}
foreach (DataRow item in table2.Rows)
{
image.id = (int)item["id"];
}
//var file = Convert.ToByte(product.image);
image.image = (byte[])(new ImageConverter()).ConvertTo(file, typeof(byte[]));
Console.WriteLine(image.image);
var client = new MongoClient("mongodb://localhost:27017/");
var database = client.GetDatabase("cmscart");
var collection = database.GetCollection<Images>("images");
collection.InsertOne(image);
return View();
}
else
{
return Content("Bed");
}
}
When I click on submit I have a null in product.image. I choose all dates from form and write it in SQL DB and after it, I take id for this data and assign id to image.id and need to take image from product.image and assign to image.image but before it converted to bytes array and after all write to MongoDB.
These are the models:
public class Products
{
public int id { get; set; }
public string Name { get; set; }
public double price { get; set; }
public string description { get; set; }
public string image { get; set; }
public int CategoryId { get; set; }
}
public class Images
{
[BsonId]
public ObjectId _id { get; set; }
[BsonElement("id")]
public int id { get; set; }
[BsonElement("image")]
public byte[] image { get; set; }
}
Image property in Products model should be of type IFormFile.
public IFormFile image { get; set; }//public string image { get; set; }
Also, don't forget to add enctype="multipart/form-data" attribute to your form.
<form asp-action="Create" enctype="multipart/form-data">
Following is the complete sample code in ASP.NET Core 3.1.
View
#model MVC_Core_Example.Controllers.Products
#{
ViewData["Title"] = "Create";
}
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="image" class="control-label"></label>
<input asp-for="image" class="form-control" />
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
Controller
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace MVC_Core_Example.Controllers
{
public class Products
{
public int id { get; set; }
public string Name { get; set; }
public double price { get; set; }
public string description { get; set; }
public IFormFile image { get; set; }//public string image { get; set; }
public int CategoryId { get; set; }
}
public class ImageController : Controller
{
public IActionResult Create()
{
return View(new Products());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Products product)//IFormCollection collection
{
return View(product);
}
}
}
When I click on submit I have a null in product.image.
The issue is related to the image data type in the Product class, and the image upload method (using tag helper or directly using html file upload element).
In asp.net core application, we could upload the files via the IFormFile. More detail information, check Upload files in ASP.NET Core.
Then, when upload image to the action method, we could use the following methods:
Using Tag Helper:
<input asp-for="Image" class="form-control" type="file" />
If using this element, remember add type="file" in the input element, you could find the image content from the ProductViewModel model.
Directly using html file upload element:
<input id="file" type="file" name="file" />
If using this method, you have to add a IFormFile parameter in the action method and get the image content based on the name attribute.
[Note] Using both of the above methods, we have to add enctype="multipart/form-data" attribute in the form tag.
More details information, you could check the following sample code:
Create a ProductViewModel to collect information and upload image:
//required using Microsoft.AspNetCore.Http;
public class ProductViewModel
{
public int id { get; set; }
public string Name { get; set; }
public double price { get; set; }
public string description { get; set; }
public IFormFile Image { get; set; }
}
Then, in the AddProduct.cshtml page, use the following code to upload image:
#model WebApplication.Models.ProductViewModel
#{
ViewData["Title"] = "AddProduct";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
<div class="col-md-4">
<form asp-action="AddProduct" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#*other fields*#
<div class="form-group">
<label asp-for="Image" class="control-label"></label>
#*<input id="file" type="file" name="file" />*#
<input asp-for="Image" class="form-control" type="file" />
<span asp-validation-for="Image" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
Controller code:
[HttpPost]
public async Task<IActionResult> AddProductAsync(ProductViewModel productvm, IFormFile file)
{
if (ModelState.IsValid)
{
//If you are using `<input id="file" type="file" name="file" />` to submit the image, you could get the image from the file.
if (productvm.Image.Length > 0)
{
using (var memoryStream = new MemoryStream())
{
await productvm.Image.CopyToAsync(memoryStream);
// Upload the file if less than 2 MB
if (memoryStream.Length < 2097152)
{
var product = new Product()
{
imageContent = memoryStream.ToArray()
};
//_dbContext.Products.Add(product);
//await _dbContext.SaveChangesAsync();
}
else
{
ModelState.AddModelError("File", "The file is too large.");
}
}
}
}
return View();
}
The screenshot as below:

ModelState.isValid always false.. .net core Razor page

Every time I get ModelState.isvalid = false. and the employee.ID is null. On the page-html I use asp-for in a hidden so it should match against id, but still comes out null, anyone have an idea?
public Employees Employees {get; set;}
public async Task<IActionResult> OnPost()
{
//if (!ModelState.IsValid)
//{
// var errors = ModelState.SelectMany(x => x.Value.Errors.Select(z => z.Exception));
//}
if (ModelState.IsValid)
{
var dbEmpy = await _db.Employees.FindAsync(Employees.ID);
dbEmpy.FirstName = Employees.FirstName;
dbEmpy.LastName = Employees.LastName;
dbEmpy.Salary = Employees.Salary;
dbEmpy.isCEO = Employees.isCEO;
dbEmpy.isManager = Employees.isManager;
dbEmpy.ManagerId = Employees.ManagerId;
await _db.SaveChangesAsync();
return RedirectToPage("ListEmpolyee/index");
}
return RedirectToPage();
}
}
and page
<div class="border container" style="padding:20px;">
<form method="post">
<input type="hidden" asp-for="Employees.ID" />
<span class="text-danger" asp-validation-summary="ModelOnly"></span>
<div class="form-group row">
<div class="col-4">
<label asp-for="Employees.FirstName"></label>
</div>
</div>
public class Employees
{
[Key]
public int ID { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public decimal Salary { get; set; }
public bool isCEO { get; set; }
public bool isManager { get; set; }
public int? ManagerId { get; set; }
}

ModelState invalid because <select> gives just id but other attribute is required

I have a Model CargoType with id , name and few others. When adding new cargo type to database all of them are required, but when i'm adding new object of Cargo which have amount and cargoType for which i use <select> to choose from existing ones. Id is what is really choosen in this select but then because CargoType.Name is null, ModelState.isValid is false.
Cargo model:
public class Cargo
{
public int Id { get; set; }
public int Amount { get; set; }
[Required]
public CargoType CargoType { get; set; }
}
CargoType model:
public class CargoType
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public int Height { get; set; } //in millimeters
public int Width { get; set; } //in millimeters
public int Length { get; set; } //in millimeters
public bool StackingAllowed { get; set; }
}
Part of the View:
Order have List<Cargo> Cargo
#model TransportationManagementSystem.Models.Order
[...]
#for (int i = 0; i < 2; i++)
{
<div class="form-group">
<label asp-for="Cargo[i].Amount" class="control-label"></label>
<input asp-for="Cargo[i].Amount" class="form-control" />
<span asp-validation-for="Cargo[i].Amount" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Cargo[i].CargoType" class="control-label"></label>
<select asp-for="Cargo[i].CargoType.Id" class="form-control" asp-items="ViewBag.CargoTypes"></select>
<span asp-validation-for="Cargo[i].CargoType" class="text-danger"></span>
</div>
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,PickUpAddress,DropOffAddress,PickUpTime,DropOffTime,OrderState,Cargo")] Order order)
{
if (order.Cargo != null)
{
foreach (var cargo in order.Cargo)
{
var cargoType = await _context.CargoTypes.FindAsync(cargo.CargoType.Id);
cargo.CargoType = cargoType;
}
}
//ModelState.Clear();
if (ModelState.IsValid)
{
_context.Add(order);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(order);
}
How should i go about this?

The property is of an interface type ('IFormFile') MVC Core

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; }
}
}

Asp.net MVC C# One Form, Two Model

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.

Categories

Resources