Search code examples
javascriptasp.net-mvcasp.net-core

I can't import IFormFile object with JavaScript


I am developing a project with .Net Core and I am trying to get the data on the form with JavaScript to create a post. While Content, which is a string expression, and SelectedIds, which is an int array, normally arrive, ContentPhoto, which I received as a File, creates a problem for the controller side (becomes null) when it is received. console.log() While it can be written to the console with the () expression, it is transmitted to the Controller as null.

Below is my design code:

<form class="post-text ms-3 w-100" asp-action="PostCreate" asp-controller="Home" enctype="multipart/form-data">
    <div class="d-flex align-items-center">
        <div class="user-img">
            <img src="~/front/assets/images/user/1.jpg" alt="userimg" class="avatar-60 rounded-circle img-fluid">
        </div>

        <input type="text" id="ContentText"  class="form-control rounded" placeholder="Write something here..." style="border:none;">
    </div>
    <hr>
    <div class="col-lg-12">
        @foreach (var tag in ViewBag.Tags as List<GetTagsQueryResult>)
        {
            <button type="button" class="tagButton" data-tag-id="@tag.Id" id="@tag.Id">@tag.Name</button>
        }
    </div>
    <hr>

    <div class="photonewDiv" id="photonewDiv" style="display: none;align-items: center;">
        <img id="uploadedImage" src="" alt="yourPost" class="img-fluid" style="display: none;border-radius: .75rem !important;max-height:95% !important;max-width:95%">
        <hr>
    </div>

    <ul class="d-flex flex-wrap align-items-center list-inline m-0 p-0">

        <li class="col-md-6 mb-3">
            <div class="bg-soft-primary rounded p-2 pointer me-3" id="fileUploadDiv">
                <a href="#">Photo/Video</a>
                <img src="~/front/assets/images/small/07.png" alt="icon" class="img-fluid">
            </div>
        </li>

        <input type="file" name="ContentPhoto" id="fileInput" style="display: none;">

        <li class="col-md-6 mb-3">
            <div class="bg-soft-primary rounded p-2 pointer me-3"><a href="#"></a><img src="~/front/assets/images/small/08.png" alt="icon" class="img-fluid"> Tag Friend</div>
        </li>
        <li class="col-md-6 mb-3">
            <div class="bg-soft-primary rounded p-2 pointer me-3"><a href="#"></a><img src="~/front/assets/images/small/09.png" alt="icon" class="img-fluid"> Feeling/Activity</div>
        </li>
        <li class="col-md-6 mb-3">
            <div class="bg-soft-primary rounded p-2 pointer me-3"><a href="#"></a><img src="~/front/assets/images/small/12.png" alt="icon" class="img-fluid"> Gif</div>
        </li>
    </ul>
    <button type="button" onclick="send()" class="btn btn-primary d-block w-100 mt-3">Post</button>
</form>

JavaScript:

function send() {
  var content = document.getElementById("ContentText").value;

  var fileInput = document.getElementById("fileInput");
  var selectedFile = fileInput.files[0];

  var selectedButtons = document.querySelectorAll(".tagButton.selected");
  var selectedButtonsIds = [];
  for (var i = 0; i < selectedButtons.length; i++) {
    selectedButtonsIds.push(parseInt(selectedButtons[i].getAttribute("id")));
  }

  console.log(content);
  console.log(selectedFile);
  console.log(selectedButtonsIds);

  var formData = new FormData();
  formData.append("Content", content);
  formData.append("ContentPhoto", selectedFile);
  formData.append("PostTagsId", selectedButtonsIds);

  fetch("/Home/PostCreate2", {
    method: "POST",
    processData: false,
    contentType: false,
    headers: {
      "Content-Type": "multipart/form-data",
    },
    body: formData,
  })
    .then((response) => response.json())
    .then((data) => {
      if (data === true) {
        toastr.success("Post Create Process Is Success!");
      } else {
        toastr.error("Error! " + data);
      }
    });
}

Controller: (just to check if the data is coming.)

[HttpPost]
public async Task<IActionResult> PostCreate2(string Content, IFormFile? ContentPhoto, int[] PostTagsId)
{
    return Json(false);
}

I tried importing it as model instead of FormData but the problem persists.

The design is the same.

JavaScript:

function send() {
  var content = document.getElementById("ContentText").value;
  var selectedFile = document.getElementById("fileInput").files[0];
  var selectedButtons = document.querySelectorAll(".tagButton.selected");
  var selectedButtonsIds = [];
  for (var i = 0; i < selectedButtons.length; i++) {
    selectedButtonsIds.push(
      parseInt(selectedButtons[i].getAttribute("data-tag-id")),
    );
  }

  var model = {
    Content: content,
    ContentPhoto: selectedFile,
    PostTagsId: selectedButtonsIds,
  };

  console.log(model);

  fetch("/Home/PostCreate2", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(model),
  })
    .then((response) => response.json())
    .then((data) => {
      if (data === true) {
        toastr.success("Post Create Process Is Success!");
      } else {
        toastr.error("Error! " + data);
      }
    });
}

Controller:

[HttpPost]
public async Task<IActionResult> PostCreate2([FromBody] CreatePostCommand model)
{
    // Model verilerini kullanarak işlemler yapabilirsiniz
    return Json(false);
}

Solution

  • There is some of the point you have to check in your code:

    1)When submitting a FormData object with fetch, don't set the Content-Type header manually, let the browser handle it.

    2)When you append an array to FormData, you need to use [] to make sure that the server recognizes it as an array of values.

    3)JSON cannot handle binary data and date types, so it is not possible to send the file(binary data) in JSON

    Here is the updated code:

    function send() {
        var content = document.getElementById("ContentText").value;
        var fileInput = document.getElementById("fileInput");
        var selectedFile = fileInput.files[0];
        var selectedButtons = document.querySelectorAll(".tagButton.selected");
        var selectedButtonsIds = [];
    
        for (var i = 0; i < selectedButtons.length; i++) {
            selectedButtonsIds.push(parseInt(selectedButtons[i].getAttribute("id")));
        }
    
        var formData = new FormData();
        formData.append("Content", content);
        if (selectedFile) {
            formData.append("ContentPhoto", selectedFile);
        }
        selectedButtonsIds.forEach(id => formData.append("PostTagsId", id));
    
        fetch("/Home/PostCreate2", {
            method: "POST",
            body: formData
        })
        .then((response) => response.json())
        .then((data) => {
            if (data === true) {
                toastr.success("Post Create Process Is Success!");
            } else {
                toastr.error("Error! " + data);
            }
        });
    }
    

    Just make sure that the parameter names match the keys that you've used in FormDataand on the controller side, check the action method signature matches the keys used in FormData.