3

I would appreciate if anyone could help me with this. I have input file control in a form in a view and when someone picks a picture and clicks the submit button on the form, that file has to be saved in /Pictures folder in the application and file path needs to be saved in SQL database as string (like: /Pictures/filename).

Models class part:

[Table("Automobil")]
public partial class Automobil
{   .....
    [Required]
    [StringLength(30)]
    public string Fotografija{ get; set; }
    ......

View (Create) file part:

@using (Html.BeginForm("Create", "Automobili", FormMethod.Post, new { enctype = "multipart/form-data" }))

....
<div class="form-group">
            <div class="editor-field">
                @Html.TextBoxFor(model => model.Fotografija, new { type = "file" })
                @Html.ValidationMessageFor(model => model.Fotografija, "", new { @class = "text-danger" })
            </div>
        </div>
....

Controller part:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "AutomobilID,Marka,Model,Godiste,Zapremina_motora,Snaga,Gorivo,Karoserija,Fotografija,Opis,Cena,Kontakt")] Automobil automobil)
    {
        if (ModelState.IsValid)
        {
                db.Automobils.Add(automobil);
                db.SaveChanges();
                return RedirectToAction("Index");
        }

        return View(automobil);
    }

What do I need to do so the photo(Fotografija) could be saved in the application folder Pictures, and file path in SQL base (like /Pictures/filename)?

Thank you in advance for helping the beginner.

Oggie
  • 71
  • 1
  • 6
  • 1
    Don't put the full path in the database - just put the filename. This way you won't need to make any data changes should you relocate or rename the containing folder, you would only need to change the code in a single place (assuming you structured your code correctly) – Rory McCrossan Aug 27 '16 at 15:09
  • When I just use the code above I get the validation error that the picture has to have up to 30 characters. Also, it doesn't save the picture itself in the application. – Oggie Aug 27 '16 at 15:15
  • remove `[StringLength(30)]` – Oluwafemi Aug 27 '16 at 15:41
  • It still doesn't work. If I remove the [StringLength(30)] the code goes through but the picture is saved in SQL database under the name "System.Web.HttpPostedFileWrapper", and picture file is not saved in the application. So there must be something that I'm missing for saving url in the database, and obviously, the code for saving the picture file in the application is missing. – Oggie Aug 27 '16 at 15:50
  • Почему бы тебе не задать свой вопрос на русском форуме? – Sleepy Panda Aug 27 '16 at 17:52
  • [Maybe this one?](http://stackoverflow.com/a/35906154/5460854) – CodeMaster Aug 28 '16 at 12:45

2 Answers2

1

Looks like your Fotografija property is string type where you want to save the unique file name. You do not want to use that field to get the file from the browser. Let's use another input field for that.

@using (Html.BeginForm("Index", "Home", FormMethod.Post, 
                                                   new { enctype = "multipart/form-data" }))
{
  <div class="form-group">
        <div class="editor-field">
            @Html.TextBoxFor(model => model.Model)
            @Html.ValidationMessageFor(model => model.Model)
        </div>
    </div>
    <!-- TO DO : Add other form fields also -->

    <div class="form-group">
        <div class="editor-field">
           <input type="file" name="productImg" />
        </div>
    </div>
    <input type="submit" />
}

Now update your HttpPost action method to have one more parameter of type HttpPostedFileBase. The name of this parameter should be same as the input file field name we added (productImg)

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "AutomobilID,Marka,Model,Godiste,
          Zapremina_motora,Snaga,Gorivo,Karoserija,Opis,Cena,Kontakt")] Automobil automobil, 
                                           HttpPostedFileBase productImg)
{
    if (ModelState.IsValid)
    {
        if(productImg!=null)
        {
          var fileName = Path.GetFileName(productImg.FileName);
          var directoryToSave = Server.MapPath(Url.Content("~/Pictures"));

           var pathToSave = Path.Combine(directoryToSave, fileName);
           productImg.SaveAs(pathToSave);
           automobil.Fotografija= fileName;
        } 

        db.Automobils.Add(automobil);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(automobil);
}

You have to remove any validation data annotation decoration(Ex : [Required], [MinLength] etc) on the Fotografija field.

I also strongly suggest you to update the fileName before saving to be a unique one to avoid collision/overwriting of existing files. You can add the DateTime current value to the file name (Before the extension) to make it unique

Shyju
  • 214,206
  • 104
  • 411
  • 497
  • Thank you a lot for taking your time to assist me. I appreciate that a lot. It work now. if you have a bit more time, could you tell me what to do now without annotations for Fotografija property? Should I make restrictions for productImg instead (and where to put them)? Thanks a lot. – Oggie Aug 27 '16 at 18:44
  • You can keep `MaxLength` to control the table column length. The property is only used for storing the file name. – Shyju Aug 27 '16 at 19:02
  • Thanks again. Enjoy the day. – Oggie Aug 27 '16 at 19:19
  • Hello again Shyju, I am now on the edit part. Could you assist me with that please? I posted the basic code above, your first answer. Didn't know how to put it in the comment. – Oggie Aug 28 '16 at 11:44
  • I'm trying to make this work and the only thing now that I do not know how to do is how to make the edit page to have file stored in the input control when I click edit. So somehow I need to make "productImg" to have my file stored there when I'm on the edit page. – Oggie Aug 28 '16 at 16:55
  • I'm trying to make this work for 2 days now, but no success. I would really appreciate your help. When I go to the edit page, the input-file field(productImg as you named it) is empty by default but on the preview img that I've put I can see that the picture is there, so it retrieves the information from Fotografija filed(fie path). But the problem is, when I change some properties and click to save them, I get the error and information that Fotografija property cannot be null. – Oggie Aug 31 '16 at 11:50
  • First, how is it null when it shows me the preview picture, which means that Fotografija field has information? Second, what to put in the edit part of the controller so that the picture stays the same if I do not upload a new one? – Oggie Aug 31 '16 at 11:51
  • For the edit screen it does not make sense to show the input file field name. Actually you are rendering the edit screen from server. The file control usually select file from users client computer (The path is local to that users computer). You may simply show a link to the attachment with a remove link ( See how gmail work, when you create a new email you can select, but when you try to edit it from your drafted emails, you just have a link with remove option) – Shyju Aug 31 '16 at 13:53
  • Also for your second question, in your edit httppost action method if the `productImg` param is null, do not overwrite the file/db record info. You can do that with an `if` condition. Also **do not ask new questions in comments. You should ask a new question with relevant minimal details** – Shyju Aug 31 '16 at 13:54
  • Thank you for all the help so far. And sry, didn't know that I have to ask a new question if it's about the same case. I managed to make the website work. – Oggie Aug 31 '16 at 17:49
0

The code that I have in controller is the basic one:

// GET: Automobili/Edit/5
    public ActionResult Edit(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        Automobil automobil = db.Automobils.Find(id);
        if (automobil == null)
        {
            return HttpNotFound();
        }
        return View(automobil);
    }

    // POST: Automobili/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit([Bind(Include = "AutomobilID,Marka,Model,Godiste,Zapremina_motora,Snaga,Gorivo,Karoserija,Fotografija,Opis,Cena,Kontakt")] Automobil automobil)
    {
        if (ModelState.IsValid)
        {
            db.Entry(automobil).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(automobil);
    }

How to change it to be compatible with the create code above?

Thank you.

Oggie
  • 71
  • 1
  • 6