简体   繁体   中英

ASP.NET Core file upload form binding problems

I try to bind my view's form to upload method of controller, using tons of tutorials, for example:

So, as I understand, if I create a controller and view, all should work. The controller:

(async is disabled here, but in both cases result is the same)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace ExcelParser.Controllers
{
    public class HomeController : Controller
    {
        static HttpClient httpClient = new HttpClient();

        // GET: /<controller>/
        public IActionResult Index()
        {
            if (httpClient.BaseAddress == null)
            {
                httpClient.BaseAddress = new Uri("http://localhost:51313");
            }
            var response = httpClient.GetAsync("api/file").Result;
            ViewBag.Templates = response.Content.ReadAsAsync<IEnumerable<string>>().Result;

            return View();
        }

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

        /*[HttpPost]
        public async Task<IActionResult> UploadFile(IFormFile file)
        {
            Console.WriteLine("======UPLOAD======");
            Console.WriteLine(file.FileName);
            string msg = "i go there";
            return RedirectToAction("Index");
        }*/

        [HttpPost]
        public IActionResult UploadFile(IFormFile file)
        {
            Console.WriteLine("======UPLOAD======");
            Console.WriteLine(file.FileName);
            string msg = "i go there";
            return RedirectToAction("Index");
        }

    }
}

The view AddFile.cshtml:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>AddFile</title>
</head>
<body>
    <form asp-controller="Home" asp-action="UploadFile" method="post"
          enctype="multipart/form-data">

        <input type="file" name="file" />
        <button type="submit">Upload File</button>
    </form>
</body>
</html>

So, I place breakpoint in controller's string msg = "i go there"; and go to webpage http://myhost:port/addfile . So, the view AddFile is rendered, but when I select a file and push the submit button, nothing happens. So, the problem that my controller doesn't receive a call for UploadFile action. I tried many examples and tutorials, and the result is the same - binding doesn't work. I use ASP.NET Core 2.2


Checked html code in browser (Chrome 72 for Win). I expected element attributes will be transformed by Razor. The code from browser:

<html><head>
    <meta name="viewport" content="width=device-width">
    <title>AddFile</title>
</head>
<body>
    <form asp-controller="Home" asp-action="UploadFile" method="post" enctype="multipart/form-data">

        <input type="file" name="file">
        <button type="submit">Upload File</button>
    </form>


</body></html>

So, it seems Razor doesn't work, and the async method UploadFile is not fired.

[HttpPost]
        public async Task<IActionResult> UploadFile(IFormFile file)
        {
            Console.WriteLine("======UPLOAD======");
            Console.WriteLine(file.FileName);
            await Task.Run(() =>
            {
                Thread.Sleep(2000);
                Console.WriteLine("======ASYNC======");
            });
            string msg = "i go there";
            return RedirectToAction("Index");
        }

So, maybe I lost some references? This is my .cspjoj file:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <UserSecretsId>bf953a4d-5fe0-4538-aeb5-27f9b4437de6</UserSecretsId>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="EPPlus" Version="4.5.3.1" />
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.0" />
  </ItemGroup>

  <ItemGroup>
    <Folder Include="wwwroot\Upload\" />
  </ItemGroup>

  <ItemGroup>
    <None Include="wwwroot\Templates\test.xlsx" />
  </ItemGroup>

</Project>

When I push submit button, a watch REST queries in the Network (Dev Tools) tab, it runs.... addfile POST query with URL https://localhost:44351/home/addfile . But why it happens, I can't found.

UPD0. Added and tried [HttpPost] method attribute. No result

UPD1. Added html from browser and references from csproj file.

If you don't specify which HTTP verbs are valid for an action, MVC will only match it for GET requests. Since you are making a POST request in your form, it cannot find a matching action (it is looking for POST Home/UploadFile but only finding GET Home/UploadFile ).

Adding the HttpPost attribute to your action will fix it.

[HttpPost]
public IActionResult UploadFile(IFormFile file)
{
     ...
}

A little side note: I would recommend that you use HttpClientFactory instead of creating the HttpClient yourself. It is more efficient and also a lot cleaner than having the client configuration code in your action.

Addition to my previous answer:

The asp-action attribute of your form element is referencing the UploadFileAsync method, which does not exist in your controller, since it is actually called UploadFile (without async). Fixing this should get you one step further.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM