Nyprez
Nyprez

Reputation: 316

Pass back HttpPostedFileBase from view → controller → back to view

My application allow user to upload upload a single image by selecting images with: @Html.TextBoxFor(m => m.Image, new {type = "file"}). If there was any validation error, I lose its selected file. Therefore I need to temporary save it via If(!ModelState.IsValid) code block:

public ActionResult Create(MyModel model) {
    if (!ModelState.IsValid)
    {
         if(model.Image != null && model.Image.ContentLength > 0) {
         var displayName = Path.GetFileName(model.Image.FileName);
         var fileExtension = Path.GetExtension(displayName);
         var fileName = string.Format("{0}{1}", Guid.NewGuid(), fileExtension);
         var path = Path.Combine(Server.MapPath("~/App_Data/Files"), fileName);
         model.Image.SaveAs(path);
         model.displayName = displayName;
         model.FilePath = path;
         return View(model);
     }
 }

I use @Html.HiddenFor(m => m.FilePath) in view.

model.Image type is HttpPostedFileBase. I must somehow re-gain users selected Image as HttpPostedFileBase after !ModelState.IsValid, in order to be able to save it in database. Any chance to pass back info inside @Html.TextBoxFor(m => m.Image, new {type = "file"})?

How I later convert HttpPostedFileBase to byte[], in order to store image-data in database.

I don't know how to do it with the tools I have.

Edit: model property:

public string displayName { get; set; }
public string FilePath { get; set; }
public HttpPostedFileBase Image { get; set; }

Upvotes: 2

Views: 2335

Answers (1)

user3559349
user3559349

Reputation:

You cannot set the value of a file input for security reasons (it can only be set by the user selecting a file in the browser).

In the view, you will need a conditional check to display the file name and path (initially it will be null)

@if (Model.displayName != null)
{
    <div>@Model.displayName</div> // let the user know that its been uploaded
    @Html.HiddenFor(m => m.FilePath)
}

Then in the controller, if ModelState is valid, you need to conditionally check the value of FilePath. In the case where you submit and ModelState is invalid, the value of FilePath will now contain the path to the save file when the user re-submits. But in the case where ModelState is valid on the initial submit, the value of FilePath will be null

You controller code needs to be (note, this assumes MyModel is actually a view model, and you have an associated data model containing a property public byte[] Image { get; set; } for saving the file in the database table

public ActionResult Create(MyModel model)
{
    if (!ModelState.IsValid)
    {
        .... // code as above to save temporary file and return the view
    }
    // Initialize an instance of your data model
    var dataModel = new .... // assumes this contains a property byte[] Image
    if (model.FilePath == null)
    {
        // The code above has never run so read from the HttpPostedFileBase property
        if(model.Image != null && model.Image.ContentLength > 0) {
        {
            MemoryStream target = new MemoryStream();
            model.Image.InputStream.CopyTo(target);
            dataModel.Image = target.ToArray();
        }
    }
    else
    {
        // Read from the temporary file
        dataModel.Image = System.IO.File.ReadAllBytes(filename);
        .... // Delete the temporary file
    }
    // Map other properties of your view model to the data model
    // Save and redirect
}

Upvotes: 1

Related Questions