11

I have a very simple MVC5 application that has a product page for the client that I also am utilizing the basic CRUD operations that have been scaffolded out in MVC 5.

I have a Model called Cakes.cs because the client sells cakes. Pretty simple. Here is the code for that model:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;

    namespace TastyCakes.Models
    {
        public class Cakes
        {
            public int CakesID { get; set; }
            public string Name { get; set; }
            public string Description { get; set; }
            public decimal Price { get; set; }

            public string CakeImage
            {
                get { return Name.Replace(" ", string.Empty) + ".jpg"; }
            }
        }
    }

As you can see I am using a calculated property to create an image name for each cake. I only need 1 image for each cake. Now when I go to Edit a cake on my CRUD pages. I would like to add a simple Image upload that will upload an image (No need for resizing or thumbnails) But I would like to impose the calculated property name. In other words: no matter what the user has named their photo, my upload code will rename it to whatever the Cakes.Name is (minus any spaces) +".jpg" and save it to "~Images/Cakes".

I am only requiring the upload to be on the actual Edit page, so the cake will already have been created at this point. All of the information needed for renaming the file should be available and easy to utilize from the Edit page. Below is my Edit page code:

Edit Page:

@model TastyCakes.Models.Cakes

<div class="row">
    <div class="large-12 columns">
    <hgroup class="title">
        <h1>Edit Cakes</h1>
    </hgroup>

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

        <div class="form-horizontal">
            <hr />
            @Html.ValidationSummary(true)
            @Html.HiddenFor(model => model.CakesID)

            <div class="medium-12 column">
                @Html.LabelFor(model => model.Name)
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
            </div>

            <div class="medium-12 column">
                @Html.LabelFor(model => model.Description)
                @Html.EditorFor(model => model.Description)
                @Html.ValidationMessageFor(model => model.Description)
            </div>

            <div class="medium-12 column">
                @Html.LabelFor(model => model.Price)
                @Html.EditorFor(model => model.Price)
                @Html.ValidationMessageFor(model => model.Price)
            </div>

            <div class="medium-12 column">
                <input type="submit" value="Save" class="tiny button" /> 
                @Html.ActionLink("Back to List", "Index", null, new { @class = "tiny button" })
            </div>
        </div>
    }

    @section Scripts {
        @Scripts.Render("~/bundles/jqueryval")
    }
    </div>
</div>

I have reviewed a few html5 & ASP.Net 4 solutions, but this is too much. What I want is very simple. Any ideas or a kick in the right direction would be very much appreciated. I am using this code not only for a clients website but to include in a fictional website used to teach very basic MVC concepts.

Eric Bishard
  • 5,201
  • 7
  • 51
  • 75
  • I have tried integrating the code at this tutorial but had trouble getting it to work, there is n instruction, just code, so I probably did something wrong or maybe the code needs to be changed for mvc5 right now I have no implementation. http://www.dotnet-tricks.com/Tutorial/mvc/WKNQ120113-How-to-upload-a-file-in-MVC4.html – Eric Bishard Mar 25 '14 at 02:23
  • Looking for a solution, tutorial, etc.. – Eric Bishard Mar 25 '14 at 02:23
  • checkout my answer http://stackoverflow.com/a/40990080/4251431 – Basheer AL-MOMANI Dec 06 '16 at 07:50

2 Answers2

22

You'll need to:

  • add an input of type file to your form,
  • have the attribute on your form element enctype = "multipart/form-data"

Then add an HttpPostedFileBase to your model with the same name as the name of the input. Then the HttpPostedFileModelBinder will populate the model property from the uploaded file before the action is invoked. Note, I think you should probably add in the model id somewhere, perhaps as a path element, to guaranteed uniqueness in the image path so that images don't accidentally get overwritten.

There's a reasonably complete discussion of this at http://www.prideparrot.com/blog/archive/2012/8/uploading_and_returning_files

public class Cakes
{
    ...

    public HttpPostedFileBase UploadedFile { get; set; }

}

[HttpPost]
public ActionResult Edit(Cakes cake) // I'd probably use a view model here, not the domain model
{
      if (ModelState.IsValid)
      {
           if (cakes.UploadedFile != null)
           {
               cakes.UploadedFile.SaveAs(Path.Combine("path-to-images-for-this-cake", cakes.CakeImage));
           }

           ....
      }
}
Michal Hosala
  • 5,570
  • 1
  • 22
  • 49
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • The link you gave me is perfect. I have actually been on that website before and find it reputable. I thank you for you push in the right direction and additional input on the ID to make the file unique! When I get this working and implement it in my tutorial I will post the finished code or tutorial for anyone else who runs across this question! – Eric Bishard Mar 25 '14 at 04:17
  • 1
    I have also found this tutorial that I will look at as well. http://sampathloku.blogspot.com/2014/02/dropzonejs-with-aspnet-mvc-5.html Unlike the other tutorials I found it has a step by step guide on how to use with VS 2013. Again I appreciate your help immensely. – Eric Bishard Mar 25 '14 at 05:09
  • Just a quick note on the DropzoneJS link I provided above. If anyone is interested they should still go through the pride parrot tutorial first because the DropdownJS tutorial simply shows you how to install the files and implement in a controller, but leaves the saving part wide open, which is a good thing, but you need to know what your options are and how to implement them and the Pride Parrot tutorial explains that aspect well. – Eric Bishard Mar 25 '14 at 05:10
  • Thanks for the answer tvanfosson. Just earned my first silver badge for this question! – Eric Bishard Jul 20 '14 at 16:16
  • @tvanfosson! This was awesome and I was able to resolve file upload issue using your solution. – AT-2017 Sep 24 '16 at 18:42
1

The code that was supplied here eventually went into building this small demo that allows you to upload images to the file system and use them dynamically without storing any values to the database; however you will have the string to the images file location as part of your Model class which uses a convention and naming of the uploaded file to display.

I would like to upload this to github and see if I can't get some others to help me work out a better solution that uses this idea. Thinking of making it work with MongoDB too.

ASP.NET MVC 5 Image Upload & Delete w/ Calculated Property

Eric Bishard
  • 5,201
  • 7
  • 51
  • 75