0

I have been sitting at my desk for several days, reading through Google searches, trying to get my ASP.Net Core application to upload files to physical location, and store the filename in the database. However whenever I try to upload a file, the IFormFile always returns a null. I'm fairly new to this.

Here is the view code

<div class="col-md-4">
    <form method="post" enctype="multipart/form-data" asp-controller="Quiz" asp-action="Create"  >
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        
        <div class="form-group">
            <label asp-for="QuizTitle" class="control-label"></label>
            <input asp-for="QuizTitle" class="form-control" />
            <span asp-validation-for="QuizTitle" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="Category" class="control-label"></label>
            <input asp-for="Category" class="form-control" />
            <span asp-validation-for="Category" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="Author" class="control-label"></label>
            <input asp-for="Author" class="form-control" />
            <span asp-validation-for="Author" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="QuizPdf" class="control-label"></label>
            <input asp-for="QuizPdf" class="form form-control">
            <span asp-validation-for="QuizPdf" class="text-danger"></span>
            </div>
        
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary mt-3" />
        </div>
    </form>

The controller code

public IActionResult Create()
    {
        return View();
    }

    // POST: Quiz/Create
    // To protect from overposting attacks, enable the specific properties you want to bind to.
    // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]

    public async Task<IActionResult> Create([FromForm]IFormFile PostedFile, QuizDetailsModel quizDetailsModel)
    {
        if (ModelState.IsValid)
        {
            if (quizDetailsModel.QuizPdf != null)
            {
                string folder = "files/pdfs/";
                folder += quizDetailsModel.QuizPdf.FileName;

                quizDetailsModel.QuizPdfUrl = folder;

                string serverFolder = Path.Combine(_webHostEnvironment.WebRootPath, folder);

                await quizDetailsModel.QuizPdf.CopyToAsync(new FileStream(serverFolder, FileMode.Create));
            }
            _context.Add(quizDetailsModel);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(quizDetailsModel);
    }

and the model code

public class QuizDetailsModel
{
    public int Id { get; set; }
    [Required(ErrorMessage = "Please enter a quiz title.")]
    [Display(Name = "Title")]
    public string QuizTitle { get; set; }
    [Required(ErrorMessage = "Please select a category.")]
    public string Category { get; set; }
    [Required(ErrorMessage = "Please enter a quiz author")]
    public string Author { get; set; }
    [Display(Name = "Upload quiz pdf.")]
    [Required]
    [NotMapped]
    public IFormFile? QuizPdf { get; set; }
    public string QuizPdfUrl { get; set; }
    [Display(Name = "Date Added")]
    [DisplayFormat(DataFormatString = "{0:MMMM dd, yyyy")]
    [DataType(DataType.Date)]
    public DateTime DateAdded { get; set; } = DateTime.Now;

    public List<QuestionsAnswersModel> QuestionsAnswers { get; set; } = new List<QuestionsAnswersModel>();

Screenshot of code

titch2019
  • 3
  • 2

3 Answers3

1

The parameter is called PostedFile, the field name is called QuizPdf do you think those are the same?

Update your code like below. remove [FromForm] no need this and also change your parameter name PostedFile to QuizPdf

public async Task<IActionResult> Create(IFormFile QuizPdf , QuizDetailsModel quizDetailsModel)

{

  //clarify code

}

It will definitely resolve your issue.

Pritom Sarkar
  • 2,154
  • 3
  • 11
  • 26
0

Share my recent research on files and improve my previous imperfect answer, sorry I solved it so late.@titch2019

Below is the demo:

MultipleFile:

public class MultipleFile
    {
        [Key]
        public string Name { get; set; }
        public List<IFormFile> Photo { get; set; }
    }

Index:

@model MultipleFile

 <form asp-action="Index"  enctype="multipart/form-data" >
             <div class="form-group">
                <label asp-for="Photo" class="control-label"></label>
                <input type="file"   asp-for="Photo" class="form-control"  multiple />
                <span asp-validation-for="Photo" class="text-danger"></span>
            </div>
             <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
              </form>

MutiController:

public class MutiController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public IActionResult Index(MultipleFile multipleFile, List<IFormFile> Photo)
        {
            return View();
        }
    }

Result:

enter image description here

Qing Guo
  • 6,041
  • 1
  • 2
  • 10
-1

When I change your model, it work. You can refer to it.

 public class QuizDetailsModel
    {
        public int Id { get; set; }
        [Required(ErrorMessage = "Please enter a quiz title.")]
        [Display(Name = "Title")]
        public string QuizTitle { get; set; }
        [Required(ErrorMessage = "Please select a category.")]
        public string Category { get; set; }
        [Required(ErrorMessage = "Please enter a quiz author")]
        public string Author { get; set; }
        [Display(Name = "Upload quiz pdf.")]
        [Required]
        //[NotMapped]
        public string QuizPdf { get; set; }
        public string QuizPdfUrl { get; set; }
        [Display(Name = "Date Added")]
        //[DisplayFormat(DataFormatString = "{0:MMMM dd, yyyy")]
        [DataType(DataType.Date)]
        public DateTime DateAdded { get; set; }

        //public List<QuestionsAnswersModel> QuestionsAnswers { get; set; } = new List<QuestionsAnswersModel>();
    }

Option 1: In create view , add type="file".

          <form asp-action="Create" >
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            ...
            <div class="form-group">
                <label asp-for="QuizPdf" class="control-label"></label>
                <input asp-for="QuizPdf" type="file"class="form-control" />
                <span asp-validation-for="QuizPdf" class="text-danger"></span>
            </div>
           ...
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
         </form>

Result: enter image description here

Option 2: In create view , add type="file", method="post" enctype="multipart/form-data"

      <form asp-action="Create"  method="post" enctype="multipart/form-data" >
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                ...
            <div class="form-group">
                <label asp-for="QuizPdf" class="control-label"></label>
                <input asp-for="QuizPdf" type="file"class="form-control" />
                <span asp-validation-for="QuizPdf" class="text-danger"></span>
            </div>
                   ...
             <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>

result: enter image description here

Qing Guo
  • 6,041
  • 1
  • 2
  • 10
  • That worked, however how do I go about resolving `if(ModelState.IsValid)`, as this is currently showing as false, even though there is now clearly data in the `IFormFile`. When I fill in all the fields in the view and click create, the QuizPdf field deletes the contents and states that it can not be empty!! – titch2019 Apr 19 '22 at 13:55
  • I think you used Option2. Using ASP.NET MVC’s model binding, it’s easy to capture text and number fields from forms. MVC’s DataAnnotations allow for a variety of types, like DateTime and Text, but not for a File type. While a file upload isn’t as “built-in” as the text and number types, it’s perfectly possible to take some simple steps to add a file upload. Like add `enctype="multipart/form-data"`. You can read [this](https://stackoverflow.com/questions/1342506/why-is-form-enctype-multipart-form-data-required-when-uploading-a-file) to know more. – Qing Guo Apr 20 '22 at 02:07
  • Because you set `Required` , so when the modelbinding don't bind the file to the model, `if(ModelState.IsValid)` is false. Maybe you can remove the `Required`, and you can add some logic instead. – Qing Guo Apr 20 '22 at 02:12