First of all sorry for my bad English. I am new to ASP.NET MVC and currently I am doing small "Rent-a-car" project on it.
I want to make a form where administrator of the page can add Cars on page with details like name
, year of production
and picture
. Following some tutorials I made a form to create a car with name and year of production and I made separately a form where administrator can upload a picture of the car.
Now I have two HTML forms with two submit buttons, one for creating a car and second for uploading an image of the car. I want to combine those two forms into one where Administrator could type name of the car, year of production, select a picture which he want's to upload and then submitting all that with one button.
I have no idea how to do that so please review my code below and tell me what changes do I have to make, I will appreciate any help
This is my Car model:
public class Car
{
[Key]
public int CarID { get; set; }
public string Model { get; set; }
public int YearOfProduction { get; set; }
public string Price { get; set; }
public string Photo { get; set; }
public string AlternateText { get; set; }
[NotMapped]
public HttpPostedFileBase File { get; set; } //for image upload
}
This is my Create (car) Action Method in the "Cars" controller:
[Authorize(Roles = "Administrator")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "CarID,Model,YearOfProduction")] Car car)
{
if (ModelState.IsValid)
{
db.Cars.Add(car);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(car);
}
This is my Upload (image of the car) Action Method in the "Cars" controller:
[HttpPost]
public ActionResult Upload(Car picture)
{
if (picture.File.ContentLength > 0)
{
var fileName = Path.GetFileName(picture.File.FileName);
var path = Path.Combine(Server.MapPath("~/Images/Cars"), fileName);
picture.File.SaveAs(path);
}
return RedirectToAction("Index");
}
This is my HTML form for creating a car:
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Car</h4>
<hr/>
@Html.ValidationSummary(true, "", new {@class = "text-danger"})
<div class="form-group">
@Html.LabelFor(model => model.Model, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(model => model.Model, new {htmlAttributes = new {@class = "form-control"}})
@Html.ValidationMessageFor(model => model.Model, "", new {@class = "text-danger"})
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.YearOfProduction, htmlAttributes: new {@class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(model => model.YearOfProduction, new {htmlAttributes = new {@class = "form-control"}})
@Html.ValidationMessageFor(model => model.YearOfProduction, "", new {@class = "text-danger"})
</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>
</div>
}
This is my HTML form for uploading an image of the car:
@using (Html.BeginForm("Upload", "Cars", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr>
<td>File:</td>
<td><input type="file" name="File" id="File"/></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" name="submit" value="Upload"/></td>
</tr>
</table>
}
how the image will be uploaded if the car is not saved yet ?
You can add the input file field in the other form and merge both action method's code into one.
and the action method, save the file to disk and store the filename in your db table records so that you can retrieve this file later (for view purposes).
Also, you may consider generating a unique file name so that you won't overwrite the existing files on disk if user is updating the file with same name for different records.
You can use this code to generate a random file name.
Also remember, the best way to prevent over posting is by using a view model with properties needed for your view. You can create a view model and use that to transfer data from view to action method. In that case, you can totally remove the property (decorated with
[NotMapped]
from your entity class)You can use the command name in your
<input>
tag as shown below:And in your controllers' action method accept it as a parameter.
If you research, there is another elegant generic solution, where you can just apply a multiple-button attribute on the Action method and it will automatically call the controller action. However, you need to be careful about getting values in that case ( *It's out of scope for this question). You can refer: How do you handle multiple submit buttons in ASP.NET MVC Framework?
Have a look at this.
It looks like it might help you combine your two forms (and controller actions) into one