2

I have a basic asp.net c# application which has a form to submit some data to database, This form has an upload button to upload a file.

Initially, there was a problem that: i was not able to submit a form without uploading a file, it was giving an error as [object reference not set to an instance of an object], which means uploading a file was a must before submitting the form, So to resolve that issue i made some changes in my controller.

Now it submits the form even if i don't upload anything, but the new problem is that when i upload a file and submit then it still submits the form successfully but it does not upload the actual file.

This is the model:

  public class Events
{
    public int Id { get; set; }
    public string title { get; set; }
    public string amount { get; set; }
    public string Finance_Approval { get; set; }
    public DateTime date_time { get; set; }

    public string file_one { get; set; }
    [NotMapped]
    public HttpPostedFileBase file1 { get; set; }
}

This is the controller:

    public ActionResult Index()
    {  
        return View();
    }


   public ActionResult Request(Events e)
    {
        if (e.file_one==null)
        {
            _context.evt.Add(e);
            _context.SaveChanges();

            return Content("Added");
        }

        else
        {
            string filename = Path.GetFileNameWithoutExtension(e.file1.FileName);
            string extension = Path.GetExtension(e.file1.FileName);
            filename = filename + DateTime.Now.ToString("yymmssfff") + extension;
            e.file_one = "PM_Files/" + filename;
            filename = Path.Combine(Server.MapPath("~/PM_Files/"), filename);
            e.file1.SaveAs(filename);

            _context.evt.Add(e);
            _context.SaveChanges();

            return Content("Added");
        }

    }

And this is the razor view:

@using (Html.BeginForm("Request", "Requester", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <div class="form-group">
        @Html.LabelFor(a => a.title)
        @Html.TextBoxFor(a => a.title, new { @class = "form-control" })
    </div>
    <div class="form-group">
        @Html.LabelFor(a => a.amount)
        @Html.TextBoxFor(a => a.amount, new { @class = "form-control" })
    </div>
    <div class="form-group">
        <label>Select the file word or pdf etc</label>
        <input type="file" name="file1" />
    </div>    
    <button class="btn btn-primary">Request</button>
}
Tân
  • 1
  • 15
  • 56
  • 102
John Kamaal
  • 129
  • 8
  • 1
    Your file is being uploaded, but you do not have a form control for `file_one` so its always `null` - you `else` block will never be executed –  Nov 14 '18 at 04:52
  • You need this one: `@Html.TextBoxFor(a => a.file_one, new { @class = "form-control", @readonly = "readonly" })` to store the file name. In your current code this textbox doesn't exist, hence the filename is never captured. – Tetsuya Yamamoto Nov 14 '18 at 04:55
  • @StephenMuecke you mean to say that i have to add the form-control class in upload button and it will resolve the issue – John Kamaal Nov 14 '18 at 04:56
  • No. You do not have a `` element for `file_one` (nor should you). What you need to check is if `e.file1` is `null`, not e.file_one` (and you also check the `ContentLength`) –  Nov 14 '18 at 04:59
  • `if (e.file_one==null)` => this is your problem, because you're checking against `file_one` string. You should check against file existence, i.e. `HttpPostedFileBase`. – Tetsuya Yamamoto Nov 14 '18 at 04:59
  • `if (e.file1 != null && e.file1.ContentLength > 0) { // save the file and set the value of file_one }; //add to context and save changes` –  Nov 14 '18 at 05:01
  • But you should not be using data models in your view - refer [What is ViewModel in MVC?](https://stackoverflow.com/questions/11064316/what-is-viewmodel-in-mvc) (and delete that `[NotMapped]` property from your data model) –  Nov 14 '18 at 05:02
  • @TetsuyaYamamoto thank you, but when i remove the [Not Mapped] from the model and then add a migration then it generates and error as: Value cannot be null. Parameter name: entitySet, And when i write the [Not Mapped] and add a migration, everything works fine. So what will be the long term consequences if i don't remove the [Not Mapped] as everything is working fine at the moment. But since this application is going to grow bigger so do i have to remove it and take care of the errors somehow? – John Kamaal Nov 14 '18 at 05:58
  • You should note that the data model and viewmodel should be separated, i.e. you should not use `HttpPostedFileBase` inside entity class (in case of Code First/CF is used), but inside the viewmodel class. The CF migration process only affects data model and not the viewmodel. – Tetsuya Yamamoto Nov 14 '18 at 06:03
  • @TetsuyaYamamoto hmmm right, & as I don't have any viewmodel at the moment but taking your comments into consideration, I will be using viewmodels for razor views (cshtml files) later on. So overall am i on the right track or still you feel something is missing in a bigger picture? So considering the codefirst approach, is my code ok or you still feel i should reomove things from it? – John Kamaal Nov 14 '18 at 06:19

1 Answers1

1

The exact problem is you're checking null against file_one string property, which always has null value because no form control associated with it inside view page. You should check against HttpPostedFileBase instead:

[HttpPost]
public ActionResult Request(Events e)
{
    if (e.file1 != null && e.file1.ContentLength > 0)
    {
        // save the file

        return Content("Added");
    }

    else
    {
        // do something else

        return Content("Added");
    }
}

If standard HttpPostedFileBase check above does not work, you should try Request.Files to get the file info:

[HttpPost]
public ActionResult Request(Events e)
{
    if (Request.Files.Count > 0)
    {
        foreach (string files in Request.Files)
        {
             if (!string.IsNullOrEmpty(files))
             {
                 // save the file
             }
        }

        return Content("Added");
    }

    else
    {
        // do something else

        return Content("Added");
    }
}

Notes:

1) The form uses FormMethod.Post, therefore the controller action should use [HttpPost] attribute.

2) [NotMapped] attribute is only used for data models to exclude entity mapping to column in database - it is not used in viewmodels, just remove it.

Tetsuya Yamamoto
  • 24,297
  • 8
  • 39
  • 61