-1

I've found some code to do this and tried to implement it into my project, but so far it has been unsuccessful. I don't get any errors, but I don't see any images being stored in my images directory inside visual studio.

View:

  @using (Html.BeginForm())
{
    <span>Please enter your story here:</span>
    <textarea id="testimonial" name="testimonial"></textarea>
    <button type="submit">Submit</button>
    <input type="file" name="file" />
}

Controller:

[HttpPost]
    public ActionResult Create(Testimonials testimonials)
    {
        if (Request.Files.Count > 0)
        {
            var file = Request.Files[0];

            if (file != null && file.ContentLength > 0)
            {
                var fileName = Path.GetFileName(file.FileName);
                var path = Path.Combine(Server.MapPath("~/Images/"), fileName);
                file.SaveAs(path);
            }
        }


        TestimonialsContext testContext = new TestimonialsContext();
        testContext.testimonialContext.Add(testimonials);
        testContext.SaveChanges();
        return RedirectToAction("Index");
    }

The part below the if block works fine. That just saves the content of a textarea to the database. Any thoughts? Do I need to make any changes to my model?

model:

[Table("Testimonials")]
public class Testimonials
{
    public int Id { get; set; }
    public string Testimonial { get; set; }
}

context class:

public class TestimonialsContext:DbContext
{
    public DbSet<Testimonials> testimonialContext { get; set; }
}
tereško
  • 58,060
  • 25
  • 98
  • 150
Jordan Carter
  • 1,276
  • 3
  • 19
  • 43
  • Hi everyone, I opened the file in file explorer and saw the images there. Strange how it doesn't update in visual studio... – Jordan Carter Mar 09 '16 at 23:50
  • In visual studio click on the folder (Images) and then click on "Show All Files" at the solution explorer options. It will show all files even if they are not added to the project. You need to click on "Refresh" to show newly added files. – TejSoft Mar 09 '16 at 23:56
  • Your file will not be sent to the server because you have not added the `enctype="multipart/form-data"` attribute to the form –  Mar 10 '16 at 00:21
  • @StephenMuecke Thank you, I did that. Now, I am wondering how I could add this file path to my database in the same table as the testimonial. Right now all I am getting is System.Web.HttpPostedFileWrapper. How can I pass in the path string to add it to the database at the same time as the testimonial? By the way, I updated my code to reflect changes I have made to make this work so far. – Jordan Carter Mar 10 '16 at 00:45
  • You cant just change the original question and I have rolled back the changes (my previous comment would not make sense and no one can add an answer). If you have a new question, then ask a new question. –  Mar 10 '16 at 00:50
  • But why do you want to save the file in the database? (your current implementation of saving to a file server is better). You just need to add additional fields in your table for the file properties - e.g. `FileDisplayName`, `FilePath` etc –  Mar 10 '16 at 00:50
  • @StephenMuecke Ok that's fine, but there seems to be a formatting error, and I am unable to edit the post to fix that. I need to save the file path to the database so that way I can use it later to fill src tags of images dynamically created on the page. – Jordan Carter Mar 10 '16 at 00:52
  • And you should not be saving the file as `file.FileName` (if a user uploads a file with the same name as another user, then it will be overwritten. Instead use a `Guid` (or other unique identifier) to generate the file name. –  Mar 10 '16 at 00:53
  • @StephenMuecke fantastic, thank you. – Jordan Carter Mar 10 '16 at 01:10

1 Answers1

4

Your file is not being posted because you do not have the necessary enctype attribute on the form. Change the view to use

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

You will now get the file and save it, but there is no relationship to your Testimonials object so you cannot retrieve it. You will need to add additional fields in your Testimonials table to store the file properties (or a separate table if a Testimonials can have multiple images). I also recommend you save the file to your server with a unique identifier (e.g. a Guid to prevent accidental overwriting if 2 users upload files with the same name). You revised model might be

public class Testimonials
{
    public int Id { get; set; }
    public string Testimonial { get; set; }
    public string ImagePath { get; set; }
    public string ImageDisplayName { get; set; }
}

I would also recommend using a view model for the view that includes the above properties plus public HttpPostedFileBase Image { get; set; } so that you can strongly bind to the model and add validation attributes (for example a [FileSize] attribute assuming you do not want to allow users to upload 2GB files). Your controller method would then be

[HttpPost]
public ActionResult Create(TestimonialVM model)
{
    // ModelState.IsValid check omitted
    Testimonials testimonials = new Testimonials();
    // map view model properties to the data model
    ....
    if (model.Image != null && model.Image.ContentLength > 0)
    {
        string displayName = model.Image.FileName;
        string fileExtension = Path.GetExtension(displayName);
        string fileName = string.Format("{0}.{1}", Guid.NewGuid(), fileExtension)
        string path = Path.Combine(Server.MapPath("~/Images/"), fileName)
        model.Image.SaveAs(path);
        // Update data model
        testimonials.ImagePath = path;
        testimonials.ImageDisplayName = displayName;
    }
    TestimonialsContext testContext = new TestimonialsContext();
    testContext.testimonialContext.Add(testimonials);
    testContext.SaveChanges();
    return RedirectToAction("Index");
}
  • Hey man, sorry for taking so long to get back to you. So far my problem is with "file.SaveAs(path). The name 'file' does not exist in the current context. I tried adding semicolons after the two lines above it, but still to no avail...Thanks for all your help though. – Jordan Carter Mar 20 '16 at 16:24
  • Sorry, its `model.Image.SaveAs(path);` :) - see update –  Mar 20 '16 at 21:08
  • Now I get "String or binary data would be truncated.The statement has been terminated." I was having issues with your way, so I modified my original way to include your edits. Rather than using the testimonialVM, I just kept the original method and rather than using "model.Image" I referred to it as the object created in the parameter (public ActionResult Create(Testimonials testimonials, HttpPostedFileBase Testimonial_ImgName)). I'm curious, do we need to declare the ImagePath = path and ImageDisplayNAme = displayName when the changes are being saved anyway a few lines down? – Jordan Carter Mar 20 '16 at 22:11
  • Ok, so I realized the error was my table was not allowing enough characters. Odd, I thought varchar(100) would be enough. Thanks for all your help you rock! – Jordan Carter Mar 20 '16 at 22:15
  • There is no difference between `file.SaveAs(path);` in your code and `model.Image.SaveAs(path);` in my answer so that error has nothing to do with with the code I have shown. –  Mar 20 '16 at 22:16
  • The reason for the 2 properties (display name and path) is that your ensuring the path is always unique when saving the file (so no risk of ever overwriting an existing file), but you can also return the view or display another view and show the user the name of the file they uploaded (it would not mean much to them if your displayed a file name with a `Guid`). –  Mar 20 '16 at 22:19
  • Yeah, I realized it was an error in my table not allowing enough characters. – Jordan Carter Mar 20 '16 at 22:20