5

I'm having trouble ironing out the file/image upload in ASP.NET MVC 6. Most tutorials appear to be outdated, and even some of the new ones seem to reference things that don't make sense.

In my view:

<div class="form-group">
    @using (Html.BeginForm("Create", "PostNin", FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        <label asp-for="NinImageString" class="control-label"></label>
        <input type="file" name="files" class="form-control" />
    }

    @*<input asp-for="NinImageString" class="form-control" />
    <span asp-validation-for="NinImageString" class="text-danger"></span>*@
</div>
<div class="form-group">
    <label asp-for="NinImageCaption" class="control-label"></label>
    <input asp-for="NinImageCaption" class="form-control" />
    <span asp-validation-for="NinImageCaption" class="text-danger"></span>
</div>

And then in my controller:

// GET: PostNins/Create
public IActionResult Create()
{
    return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,NinFk,NinDigit,NinImageString,NinImageCaption,NinNote")] PostNin postNin, IFormFile files)
{
    // need code here
        
    if (ModelState.IsValid)
    {
        _context.Add(postNin);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }

    return View(postNin);
}

My understanding is that I have to use IFormFile to pull this off.

I would like to upload an image with a caption, and store it into the application folder NinImages where I can access it later. I suppose I have questions about that too, but that's for another question.

My understanding is that I have to somehow save a copy of the image into the directory system, under wwwroot, then save the path of the file as a string to the database.

SOLUTION:

My new controller looks like below. As a note, the fileTime is only to assign a unique value to each upload, to avoid duplicates. This works in this case because only one file can be uploaded at a time.

[HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("Id,NinFk,NinDigit,NinImageString,NinImageCaption,NinNote")] PostNin postNin, IFormFile uploadFile)
    {


        if (uploadFile != null && uploadFile.Length > 0)
        {
            var fileTime = DateTime.UtcNow.ToString("yyMMddHHmmss");
            var fileName = fileTime + Path.GetFileName(uploadFile.FileName);
            var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/NinFileUploads", fileName);

            postNin.NinImageString = filePath;
            _context.PostNins.Add(postNin);
            _context.SaveChanges();

            using (var fileStream = new FileStream(filePath, FileMode.Create))
            {
                await uploadFile.CopyToAsync(fileStream);
            }
            //if (ModelState.IsValid)
            //{
            //    _context.Add(postNin);
            //    await _context.SaveChangesAsync();
            //    return RedirectToAction(nameof(Index));
            //}
            return RedirectToAction(nameof(Index));

        }
        return View(postNin);
Nick Fleetwood
  • 471
  • 1
  • 5
  • 22
  • 4
    Does any of the answers here help? https://stackoverflow.com/questions/35379309/how-to-upload-files-in-asp-net-core If not, what error are you getting? And I don't know if this is a typo but this is wrong `enctype = "multipart/form-date"` it should be "multipart/form-data". – Jasen Sep 09 '20 at 19:59
  • Good catch on typo, thanks. Some of them are helpful, but not complete or they are doing something different. – Nick Fleetwood Sep 10 '20 at 04:27

3 Answers3

4

Here is a demo work:

PostNin Class:

public class PostNin
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string ImagePath { get; set; }
    }

Controller:

public async Task<bool> Create(PostNin postNin,IFormFile upload)
        {     
                if (upload != null && upload.Length > 0)
                {                
                    var fileName = Path.GetFileName(upload.FileName);
                    var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/images", fileName);
                    postNin.ImagePath = filePath;
                    _context.PostNins.Add(postNin);
                    _context.SaveChanges();
                    using (var fileSrteam = new FileStream(filePath, FileMode.Create))
                    {
                        await upload.CopyToAsync(fileSrteam);
                    }
                    return true;
                }
                return false;
        }

Result: enter image description here

Yiyi You
  • 16,875
  • 1
  • 10
  • 22
  • ooh, its close. Why did you use "bool" instead of "IActionResult"? I attempted to use your code but got an error, "Could not find a part of the path". See updated question – Nick Fleetwood Sep 10 '20 at 15:57
  • This worked perfectly. Thank you. I have a follow-up question about naming the uploaded files, which is why I haven't marked answered yet. I appreciate your help. Also, I just wanted to point out that your code and images were incredibly detailed and helpful. – Nick Fleetwood Sep 10 '20 at 17:20
2

You need to set the name attribute for the input element same as Create method parameter, in this solution name attribute and Create method parameter set to uploadFile

HTML

<input type="file" name="uploadFile" class="form-control" />

CS

Create([Bind("Id,NinFk,NinDigit,NinImageString,NinImageCaption,NinNote")] PostNin postNin, IFormFile uploadFile)
Saeed Gholamzadeh
  • 932
  • 1
  • 6
  • 22
1

change the name of the file upload control to files

<input type="file" name="files" class="form-control" />

add [FromForm] before IFormFile files first and try if it works

Create([Bind("Id,NinFk,NinDigit,NinImageString,NinImageCaption,NinNote")] PostNin postNin, [FromForm]IFormFile files)

if it not working try to add new IFormFile files property to PostNin class or create a new class as a model for this action and add [FromForm] before it on the action parameter.

public class PostNinModel {
....
public IFormFile files { get; set; }
...
}

Create([FromForm] PostNinModel postNin)
fligant
  • 712
  • 2
  • 7
  • 20
  • 1
    I have updated the file upload control and added [FromForm] on action parameter. No IDE errors. but now what? How should I "try it"? – Nick Fleetwood Sep 10 '20 at 03:14
  • is the file been sent to the action? you can check this using breakpoint then you can save the file check this https://stackoverflow.com/questions/39322085/how-to-save-iformfile-to-disk – fligant Sep 10 '20 at 05:23