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:
Related
I have a problem where numbers i export from my server with decimal numbers are using the decimal sign instead of a point making it not appear on the screen as shown on the images
image of screen
image of Elements
and here if i replace in manualy with a dot
image of screen
i dont know whats happening since it should be imposible for a double to have a comma in it.
i have tried changing around the double to a string and that works but it only avoids the problem, and i dont want to be able to save text in price.
View code:
#model Produkt
#{
<form asp-action="sparaProdukt" method="post">
<div id="in">
<h2>ID:</h2>
<h1>#Model.id</h1>
</div>
<input type="hidden" name="id" value="#Model.id">
<div id="in">
<label for="Name">name:</label>
<input type="text" id="produktnamn" name="produktnamn" value="#Model.produktnamn">
</div>
<div id="in">
<label for="Supplier">Supplier:</label>
<input type="text" id="Supplier" name="tillverkare" value="#Model.tillverkare">
</div>
<div id="in">
<label for="Info">Info:</label>
<input type="Info" id="Info" name="produktinfo" value="#Model.produktinfo">
</div>
<div class="field">
<div class="wrapper">
<label for="Price">Price:</label>
<input type="number" id="Price" name="pris" class="Price" value="#Model.pris" step="0.01" min="0" lang="en">
<span>| kr</span>
</div>
</div>
<button type="submit">Confirm</button>
</form>
}
Model code:
using Webbshop.Models;
using MySql.Data;
using MySql.Data.MySqlClient;
namespace Webbshop.Models
{
public class Produkt
{
public string produktnamn { get; set; } = "";
public string produktinfo { get; set; } = "";
public string tillverkare { get; set; } = "";
public double pris { get; set; } = 0;
public long id { get; set; } = 0;
public static bool sparaProdukt(Produkt p)
{
string conStr = "server=|removed|;user=|removed|;port=|removed|;database=|removed|;password=|removed|";
MySqlConnection conn = new MySqlConnection(conStr);
MySqlCommand MyCom = new MySqlCommand("UPDATE Produkt set produktnamn = #PRNAMN, tillverkare = #TILL, pris = #PRIS where id = #ID ", conn);
MyCom.Parameters.AddWithValue("#PRNAMN", p.produktnamn);
MyCom.Parameters.AddWithValue("#TILL", p.tillverkare);
MyCom.Parameters.AddWithValue("#PRIS", p.pris);
MyCom.Parameters.AddWithValue("#ID", p.id);
conn.Open();
int rader = MyCom.ExecuteNonQuery();
MyCom.Dispose();
conn.Close();
if (rader == 0) return false; else return true;
}
}
Controller code:
using Microsoft.AspNetCore.Mvc;
using Webbshop.Models;
namespace Webbshop.Controllers
{
public class ProduktController : Controller
{
List<Produkt> allaP = new List<Produkt>();
Produkt P = new Produkt();
public IActionResult Index()
{
return View(Produkt.getAllProdukt());
}
public IActionResult newProdukt()
{
return View();
}
public IActionResult redigeraProdukt(int id)
{
Produkt p = Produkt.getSingleProduktById(id);
return View(p);
}
public IActionResult sparaProdukt(Produkt p)
{
Produkt.sparaProdukt(p);
return View("Index");
}
}
}
When i redirect to the Edit.cshtml page, only the HttpGet seems to be working. The HttpPost is not working. Which means that when I make changes and click on the Edit button on the Edit form, the HttpPost Edit is supposed to be invoked to call the PUT API. But the HttpGet Edit is called instead... What have I done wrong?
The HttpGet to retrieve the existing info
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
await ViewBags();
HttpResponseMessage response = await GlobalVariables.WebApiClient.GetAsync("article/detail/" + id.ToString());
if (response.IsSuccessStatusCode)
{
var authorTagArticle = new AuthorTagArticle();
authorTagArticle = response.Content.ReadAsAsync<AuthorTagArticle>().Result;
var articleForm = new ArticleForm();
articleForm.ArticleId = authorTagArticle.Article.ArticleId;
articleForm.ArticleTitle = authorTagArticle.Article.ArticleTitle;
articleForm.ArticleContent = authorTagArticle.Article.ArticleContent;
articleForm.CreatedOn = authorTagArticle.Article.CreatedOn;
articleForm.ImagePath = authorTagArticle.Article.ImagePath;
articleForm.AuthorIds = authorTagArticle.Author.Select(e => e.UserId).ToArray();
articleForm.TagIds = authorTagArticle.Tag.Select(e => e.TagId).ToArray();
return View(articleForm);
}
else
{
TempData["error"] = "Error - Unable to open Edit Article Menu";
return RedirectToAction("Index", "Home");
}
}
The HttpPost Edit method: to call the PUT API
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, ArticleForm articleForm)
{
if (id != articleForm.ArticleId)
{
return NotFound();
}
//If Image is Updated
var content = Request.Form.Files;
const long MaxLength = 10485760; // 10MB
string oldImagePath = articleForm.ImagePath;
if (content.Count() > 0 && content.First().ContentType.Contains("image") && content.First().Length < MaxLength)
{
articleForm.ImagePath = "article/" + content.First().FileName;
}
else
{
ModelState.AddModelError("Image", "Please select a valid image less than 10MB");
}
if (ModelState.IsValid)
{
try
{
Article article = new Article();
article.ArticleId = articleForm.ArticleId;
article.ArticleTitle = articleForm.ArticleTitle;
article.ArticleContent = articleForm.ArticleContent;
article.CreatedOn = articleForm.CreatedOn;
article.ImagePath = articleForm.ImagePath;
HttpResponseMessage response = await GlobalVariables.WebApiClient.PutAsJsonAsync("article/edit/" + id, article);
if (response.IsSuccessStatusCode)
{
TempData["success"] = "Article Updated!";
return RedirectToAction("Index", "Article");
}
else
{
TempData["error"] = "Error - Unable to edit article!";
return RedirectToAction("Index", "Home");
}
}
catch (DbUpdateConcurrencyException) { }
}
return View(articleForm);
}
Edit.cshtml
#model SCANews_UI.Models.ArticleForm
#{ ViewData["Title"] = "Edit"; }
<h1>Edit Article</h1>
<div class="card" style="width: 70rem;">
<div class="card-body">
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="ArticleId" />
<div class="form-group">
<label asp-for="ArticleTitle" class="control-label"></label>
<input asp-for="ArticleTitle" class="form-control">
<span asp-validation-for="ArticleTitle" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ArticleContent" class="control-label"></label>
<textarea asp-for="ArticleContent" id="testCK" class="form-control"></textarea>
<span asp-validation-for="ArticleContent" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ImagePath" class="control-label"></label>
<br />
<img style="max-width: 100%; height: 200px;" src="#Model.ImagePath" class="rounded img-thumbnail" alt="Article Image" id="existingImage">
<input hidden asp-for="ImagePath" class="form-control" />
<div class="custom-file">
<input type="file" asp-for="ImagePath" onchange="readURL(this)" class="custom-file-input form-control" name="Image" id="customFile">
<label class="custom-file-label" for="customFile">Choose file</label>
</div>
<span asp-validation-for="ImagePath" class="text-danger"></span>
<!-- Uploaded image area-->
<div class="image-area mt-4"><img id="imageResult" src="#" alt="" class="img-fluid rounded shadow-sm mx-auto d-block"></div>
</div>
<div class="form-group">
<input type="submit" value="Edit" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/js/ckeditor/ckeditor.js"></script>
<script>
var contentTextArea = document.getElementById("testCK")
CKEDITOR.replace(contentTextArea);
</script>
<script type="text/javascript">
$(".custom-file-input").on("change", function () {
var fileName = $(this).val().split("\\").pop();
$(this).siblings(".custom-file-label").addClass("selected").html(fileName);
});
</script>
<script>
//Show Image
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#imageResult')
.attr('src', e.target.result);
};
reader.readAsDataURL(input.files[0]);
}
var beforeImage = document.getElementById('existingImage');
beforeImage.style.display = 'none';
}
$(function () {
$('#customFile').on('change', function () {
readURL(input);
});
});
</script>
<script type="text/javascript">
//Show Image Name
document.querySelector('.custom-file-input').addEventListener('change', function (e) {
var name = document.getElementById("customFile").files[0].name;
var nextSibling = e.target.nextElementSibling
nextSibling.innerText = name
})
</script>
ArticleForm model
public class ArticleForm
{
public int ArticleId { get; set; }
[Required, Column(TypeName = "varchar(150)")]
[DisplayName("Article Title")]
public string ArticleTitle { get; set; }
[Required, Column(TypeName = "text")]
[DisplayName("Article Content")]
public string ArticleContent { get; set; }
public DateTime CreatedOn { get; set; }
[Column(TypeName = "text")]
[DisplayName("Image")]
public string ImagePath { get; set; }
public int[] AuthorIds { get; set; }
public int[] TagIds { get; set; }
}
Article Model
public class Article
{
public int ArticleId { get; set; }
public string ArticleTitle { get; set; }
public string ArticleContent { get; set; }
public DateTime CreatedOn { get; set; }
public string ImagePath { get; set; }
}
AuthorTagArticle Model
public class AuthorTagArticle
{
public Article Article { get; set; }
public List<User> Author { get; set; }
public List<Tag> Tag { get; set; }
}
GlobalVariables
public class GlobalVariables
{
public static HttpClient WebApiClient = new HttpClient();
static GlobalVariables()
{
//local testing
WebApiClient.BaseAddress = new Uri("https://localhost:44361/api/");
//lambda APIs
WebApiClient.DefaultRequestHeaders.Clear();
WebApiClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
}
}
Try to edit your code as following: <form asp-controller="{Your controller}" asp-action="Edit" method="post">
Also you can read some info about Tag Helpers here
How do i get an IFormFile Instance using a file path?. The file, in this case is an Image stored in the wwwroot folder.
I'll give you a little bit of context of what i am trying to achieve:
I want to update a product so in order to do that i have to display the product information on the view, including it's file name next to the <input type="file" class="form-control-file" asp-for="File">. So the user knows,it has already an image, and of course i won't have problem doing the HTTP Post Request because no file was selected (In case the user doesn't want to update the image). The problem is that product class doesn't have an IFormFile property, it only has it's image name, and the view model is responsible of having the IForm File. So again how do i convert the image name or path into a IFormFile before sending the productViewModel as a parameter to the View?
Here's my view,view model and my product class:
Update.cshtml
<form enctype="multipart/form-data" method="post" asp-controller="Product" asp-action="Update">
<div class="form-group">
<label asp-for="Name"></label>
<input type="text" class="form-control" asp-for="Name" placeholder="Cereal, Ice cream, Tuna, etc...">
<span class="text-danger" asp-validation-for="Name"></span>
</div>
<div class="form-group">
<label asp-for="File"></label>
<input type="file" class="form-control-file" asp-for="File">
</div>
<button class="btn btn-success">Save Changes</button>
</form>
ProductViewModel.cshtml
public class ProductViewModel
{
public string Name { get; set; }
public IFormFile File { get; set; }
}
Product.cshtml
public class Product
{
public string Name { get; set; }
public string ImageName { get; set; }
}
Here is a demo to change path to IFormFile in Action:
Controller:
public IActionResult GetFile() {
Product product = new Product { Name = "product1", ImageName = "red.PNG" };
string path = "./wwwroot/images/" + product.ImageName;
using (var stream = System.IO.File.OpenRead(path))
{
ProductViewModel productViewModel = new ProductViewModel
{
Name = product.Name,
File = new FormFile(stream, 0, stream.Length, null, Path.GetFileName(stream.Name))
};
return Ok();
}
}
Result:
I have a List of objects in my Model, how can I make a form for it?
I want to have select box and number input box to add objects and be able to keep adding more before posting form.
If it was just public Cargo cargo I would just make a select box to choose cargo type and input box for amount and that's it. But it's a list so I want to add as much cargo as I want and then post a form. I already have input fields for address (like city, street etc.) in my form but I'm stuck with this list.
Order model (Form model):
public class Order
{
public int Id { get; set; }
public Address PickUpAddress { get; set; }
public Address DropOffAddress { get; set; }
[...]
public List<Cargo> Cargo { get; set; }
}
Cargo model:
public class Cargo
{
public int Id { get; set; }
public int Amount { get; set; }
public CargoType CargoType { get; set; }
}
My solution
I implemented this function manually without any JS code.
The code is very simple. You can refer to my code here directly.
Solving process
We have to insert the order table before we can insert the cargo table. Otherwise, we can't connect the two tables.
We need these three form models.We use the cargocount field to link the two order pages with the cargo page.
public class CargoViewModel
{
public int OrderId { get; set; }
public int Amount { get; set; }
public string CargoType { get; set; }
//Other use
public int CargoCount { get; set; }
public List<CargoViewModel> Cargos { get; set; }
}
public class OrderViewModel
{
public int OrderId { get; set; }
public string PickUpAddress { get; set; }
public string DropOffAddress { get; set; }
public int CargoCount { get; set; }
public List<CargoViewModel> Cargos { get; set; }
}
public class OrdersViewModel
{
public List<OrderViewModel> Orders { get; set; } = new List<OrderViewModel>();
}
When we create an order page, we need to provide the data of cargocount. When we submit the order page, we will save the existing data to the order table, jump to the cargo page, and generate cargocount input tags.
Next, submit the list form.
Submit page code
<form asp-controller="Order" asp-action="CreateCargo" method="post">
#if (Model.CargoCount != 0)
{
for (int itemCount = 0; itemCount < Model.CargoCount; itemCount++)
{
<div class="row">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="form-group" style="width:300px; height:auto; float:left; display:inline">
<label asp-for="#Model.Cargos[itemCount].Amount" class="control-label"></label>
<input asp-for="#Model.Cargos[itemCount].Amount" class="form-control" />
<span asp-validation-for="#Model.Cargos[itemCount].Amount" class="text-danger"></span>
</div>
<div class="form-group" style="width:300px; height:auto; float:left; display:inline">
<label asp-for="#Model.Cargos[itemCount].CargoType" class="control-label"></label>
<input asp-for="#Model.Cargos[itemCount].CargoType" class="form-control" />
<span asp-validation-for="#Model.Cargos[itemCount].CargoType" class="text-danger"></span>
</div>
</div>
</div>
}
}
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
Background data processing code
[HttpPost]
public async Task<IActionResult> CreateCargo(CargoViewModel model)
{
var orderId = await _context.Order.Select(o => o.OrderId).MaxAsync();
var cargos = model.Cargos;
foreach (var item in cargos)
{
var cargo = new Cargo
{
OrderId = orderId,
Amount = item.Amount,
CargoType = item.CargoType
};
await _context.AddAsync(cargo);
await _context.SaveChangesAsync();
}
return RedirectToAction(nameof(Index));
}
Using JS implementation
We need this form models.
public class OrderAndCargoViewModel
{
public int OrderId { get; set; }
public string PickUpAddress { get; set; }
public string DropOffAddress { get; set; }
public List<CargoViewModel> Cargos { get; set; }
}
Next, submit the table form. Submit page code.
<div style="float:right;">
<table id="tb">
<tr>
<th> <label class="control-label">ID</label></th>
<th> <label asp-for="#Model.Cargos.FirstOrDefault().Amount" class="control-label"></label> </th>
<th><label asp-for="#Model.Cargos.FirstOrDefault().CargoType" class="control-label"></label></th>
</tr>
#{
var countId = 0;
for (var itemCount = 0; itemCount < 3; itemCount++)
{
<tr id="trs">
<td>#(++countId)</td>
<td><input asp-for='#Model.Cargos[itemCount].Amount' class= 'form-control' /></td>
<td><input asp-for='#Model.Cargos[itemCount].CargoType' class='form-control' /></td>
</tr>
}
}
</table>
</div>
<input id="btnAdd" value="Add" type="button" class="btn btn-primary" onclick="btnAddClick()">
JS Code.
#section scripts{
<script src="~/js/jquery-3.4.1/jquery-3.4.1.js" type="text/javascript"></script>
<script src="~/js/jquery-3.4.1/jquery-ui-1.12.1.js" type="text/javascript"></script>
<script src="~/js/jquery-3.4.1/jquery.unobtrusive-ajax.js" type="text/javascript"></script>
<script>
var btnAddClick = function () {
var trLen = $("#tb tr[id='trs']").length;
var $lastTr = $("#tb tr[id='trs']").last();
var tr = "<tr id='trs'>";
tr += "<td>" + (trLen + 1) + "</td>";
tr += "<td><input class='form-control' type='number' data-val='true' data-val-required='The Amount field is required.' id='Cargos_"+trLen+"__Amount' name='Cargos["+trLen+"].Amount' value=''></td>";
tr += "<td><input class='form-control' type='text' id='Cargos_"+trLen+"__CargoType' name='Cargos["+trLen+"].CargoType' value=''>";
tr += "</tr>";
$(tr).insertAfter($lastTr);
}
</script>
}
Controller Code.
[HttpPost]
public async Task<IActionResult> CreateOrderAndCargo(OrderAndCargoViewModel model)
{
var order = new Order()
{
PickUpAddress = model.PickUpAddress,
DropOffAddress = model.DropOffAddress
};
await _context.AddAsync(order);
await _context.SaveChangesAsync();
var orderId = await _context.Order.Select(o => o.OrderId).MaxAsync();
var cargos = model.Cargos;
foreach (var item in cargos)
{
var cargo = new Cargo
{
OrderId = orderId,
Amount = item.Amount,
CargoType = item.CargoType
};
await _context.AddAsync(cargo);
await _context.SaveChangesAsync();
}
return RedirectToAction(nameof(Index));
}
Click here to view source codes.
Reference page
About'#'.
JS operation.
It will solve the problem if you use more than one related model in View pages and give a list parameter in actions..
An example;
View;
<input type="text" name="name" id="name1" />
<input type="text" name="name" id="name2" />
Action
public actionresult post(string [] name)
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);
}