0

I have a web application, where I want to save images in my database. In my Application.Web I have a folder called images. The uploaded images should be saved there. I want to save the images in my database as a path like \images\user1.jpg.

My Create.cshtml, which I've generated from the controller, looks like this:

@model Application.Dal.User
@using (Html.BeginForm()) {
    @Html.LabelFor(model => model.Picture)
    @Html.EditorFor(model => model.Picture)
    <input type="submit" value="Create" class="btn btn-default" />
}

Now it looks like this: enter image description here

The user would have to write a path in the textfield, which is obviously wrong. I want the user to select an image, like this:

<input type="file" name="image" accept="image/*" id="inputImage" value="model => model.Picture)"/>

Which turns the field into (Choose file): enter image description here

Well, thats what I want but how do I bind the selected image to model => model.Picture? I tried to put "model => model.Picture" in the value attribut of the input but it doesn't work. And if it would work, how can I make sure that the picture will be saved in the image folder?

I've looked at this page: https://forums.asp.net/t/2021506.aspx?Upload+audio+file+and+save+to+Database+in+ASP+NET+MVC+using+Codefirst+EF+ but this doesn't really explain how I can bind the picture to model => model.Picture.

1
  • @Html.TextBoxFor(model => model.Picture, new { type = "file" }) to generate the html (where Picture is typeof HttpPostedFileBase in your view model) and you need to add the enctype = "multipart/form-data" attribute to the form Commented Jan 16, 2018 at 21:53

2 Answers 2

4

I have actually done similar in a recent project.

In your view you can create an input tag of type file, which it looks like you have already done.

<input name="attachment" type="file">

Then in your controller, you can use the HttpPostedFileBase class to to pass it back to your code and save it.

[HttpPost]
public ActionResult Save(HttpPostedFileBase Attachment)
    {
        //do stuff
        SaveFile(Attachment)
    }

This method returns an enum which I will attach later on. I use an enum here in a similar effect to boolean except I can return more than two options.

public FileUploadState SaveFile(HttpPostedFileBase Attachment)
{
    if(Attachment != null)
    {
        try //attempt to save file to file system
        {
            var fileName = Path.GetFileName(Attachment.FileName);
                    //path as parameter can be changed to any desired valid path
            var path = Path.Combine((@"C:\Images"), fileName);
            Attachment.SaveAs(path);
            return FileUploadState.Uploaded;
        }
        catch //implement your own error handling here 
        {
            //error handling
            return FileUploadState.Failed;
        }
    }
    else
    {
        return FileUploadState.NoFileSelected;
    }
}

Enum: In computer programming, an enumerated type is a data type consisting of a set of named values called elements, members, enumeral, or enumerators of the type. More info on Enums

public enum fileUploadState
{
    Uploaded,
    NoFileSelected,
    Failed
}

Then to access these attachments, later on you can put this code in. Assuming you are reading filenames from a database.

In your controller:

readFileName = get filename from DB;
ViewBag.Attachment = readFileName;

In your view create a link for your user to click to open the attachment: target = "_blank" opens in a new tab

@Html.ActionLink("First Attachment: " + (string)ViewBag.Attachment, "DownloadAttachment", new { @FileName = (string)ViewBag.Attachment }, new { target = "_blank" })}

Back to your controller: Assuming you use the same Attachment class I created. I created the attachment class with a valid constructor to store useful information about the files, i.e. filenames, paths (incase different), byte content.

    public ActionResult DownloadAttachment(string FileName)
    {
        //path as parameter can be changed to wherever the file exists
        Attachment attach = new Attachment(FileName, @"C:\Images");
        //when attachment is created, byte content is read
        var cd = new System.Net.Mime.ContentDisposition
        {
            FileName = attach.FileName,
            Inline = true,
        };
        Response.AppendHeader("Content-Disposition", cd.ToString());
        //return content
        return File(attach.FileData, attach1.contentType);
    }

Attachment Class:

public class Attachment
{
    public string FileName { get; set; }
    public string FilePath { get; set; }
    public byte[] FileData { get; set; }
    public string contentType { get; set; }

    public Attachment(string fileName, string filePath)
    {
        this.FileName = fileName;
        this.FilePath = filePath + @"\"+ fileName ;
        this.FileData = System.IO.File.ReadAllBytes(FilePath);
        this.contentType = MimeMapping.GetMimeMapping(FilePath);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

The latter <input> method is the correct way to do it.

Razor would look like this:

@using (Html.BeginForm("YourAction", "YourController", null, FormMethod.Post, 
new { enctype = "multipart/form-data" }))
{    
    @Html.LabelFor(model => model.Picture)
    <input type="file" name="file" multiple="multiple" />
    <input type="submit" value="Save" />
}

The upload information is stored in the Request.Files on the POST.

You can access it with something like this:

List<string> picture = new List<string>();

for (int i = 0; i < Request.Files.Count; i++)
{
    HttpPostedFileBase file = Request.Files[i];

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

db.SaveChanges();

Edit: Is Picture just the path of the picture? If so, let me know and I can update my code to reflect your model better.

4 Comments

Thanks for your post. I will have a look at this. Picture is a property of model. So I guess the path of my image has to be saved in model.Picture
I get the error that Request.Files is not known. What could be the reason for this?
@BlueCat For the Request.Files.Count or var file = Request.Files[i]? Make sure you have using System.Web.Mvc; and maybe change var file to be explicit with HttpPostedFileBase file = Request.Files[i];.
@BlueCat I forgot that the Begin.Form needs to be updated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.