Submitting two HTML forms with one submit button i

2019-07-29 09:23发布

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>&nbsp;</td>
            <td><input type="submit" name="submit" value="Upload"/></td>
        </tr>
</table>
    }

4条回答
闹够了就滚
2楼-- · 2019-07-29 09:44

how the image will be uploaded if the car is not saved yet ?

查看更多
狗以群分
3楼-- · 2019-07-29 09:51

You can add the input file field in the other form and merge both action method's code into one.

@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>
      <label>File</label> 
      <input type="file" name="File" id="File"/>

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

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).

[Authorize(Roles = "Administrator")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Car car)
{
    if (ModelState.IsValid)
    {
      if (car.File.ContentLength > 0)
      {
         var fileName = Path.GetFileName(car.File.FileName);
         var path = Path.Combine(Server.MapPath("~/Images/Cars"), fileName);
         picture.File.SaveAs(path);
         car.Photo = fileName;
      }
      db.Cars.Add(car);
      db.SaveChanges();
      return RedirectToAction("Index");
    }
    return View(car);
}

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.

var fileName = Path.GetFileName(car.File.FileName);
fileName = Path.GetFileNameWithoutExtension(fileName) +
                            "_" +
                   Guid.NewGuid().ToString().Substring(0, 4) + Path.GetExtension(fileName);
var path = Path.Combine(Server.MapPath("~/Images/Cars"), fileName);
//continue with saving

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)

查看更多
beautiful°
4楼-- · 2019-07-29 09:56

You can use the command name in your <input> tag as shown below:

@Html.BeginForm()
{
  @Html.AntiForgeryToken()

  <!-- Your Razor code for the input form goes here  -->

  <!-- Now your Upload button -->
  <table>
    <tr>
        <td>File:</td>
        <td><input type="file" name="File" id="File"/></td>
    </tr>

        <tr>
            <td>&nbsp;</td>
            <td><input type="submit" name="commandName" value="Upload"/></td>
        </tr>
  </table>

  <!-- Finally, your form submit button -->
   <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" name="commandName" value="Create" class="btn btn-default"/>
        </div>
   </div>

}

And in your controllers' action method accept it as a parameter.

public ActionResult Create(Car car, string commandName)
{
    if(commandName.Equals("Create"))
    {
      // Call method to create new record...
    }
    else if (commandName.Equals("Upload"))
    {
      // Call another method to upload picture..
    }
}

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?

查看更多
做个烂人
5楼-- · 2019-07-29 10:05

Have a look at this.

It looks like it might help you combine your two forms (and controller actions) into one

查看更多
登录 后发表回答