Загрузка файла в WebAPI - PullRequest
       10

Загрузка файла в WebAPI

0 голосов
/ 11 сентября 2018

Окружающая среда

  • C # 7,2
  • .NET core 2.0 / 2.1
  • Kestrel

Я пытаюсь загрузить файл через веб-интерфейс. Это казалось достаточно простым, но я, должно быть, упускаю что-то тривиальное.

Я искал в Интернете, но я не нашел полный работающий пример для загрузки.

Я пытался подключить фрагменты, показывающие, как это сделать, но не смог получить полностью работающее решение.

Я создал свой собственный простой тестовый проект. Вот ключевые части.

Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseStaticFiles();
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();
    }
}

ValuesController

[Produces("application/json")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    public ValuesController() { }

    [HttpPost("upload")]
    public async Task<IActionResult> Upload(IFormFile file)
    {
        try
        {
            using (Stream strm = file?.OpenReadStream())
            {
                return Ok($"File uploaded had {file?.Length ?? -1} bytes");
            }
        }
        catch (Exception ex)
        {
            return BadRequest(ex);
        }
    }
}

Если я вызываю этот веб-метод из почтальона (должен поддерживать это), используя:

http://localhost:5000/api/values/upload

Заголовок: Content-Type: multipart / form-data; border = "border"

Body: Данные формы с 1 параметром с именем 'file' и отправленные в виде файла, а не текста.

Kestrel отвечает:

System.IO.IOException: Неожиданный конец потока, возможно, содержимое уже прочитано другим компонентом.

Я также пытался с простой HTML-формой:

<form method="post" enctype="multipart/form-data" action="http://localhost:5000/api/values/upload">
<div>
    <p>Upload one or more files using this form:</p>
    <input type="file" name="files" />
</div>
<div>
     <input type="submit" value="Upload" />
</div>
</form>

Этот подход фактически превращает его в веб-метод, но параметр IFormFile всегда равен нулю.

Похоже, почтальон находит веб-метод, отправляет данные и что поток читается несколько раз. Я нашел несколько ссылок на атрибут DisableFormValueModelBinding, но, похоже, это не помогло. Кажется странным, что мне нужен собственный атрибут, чтобы использовать IFormFile, который предоставляет MS.

Что касается формальности, я не понимаю, почему файл не отправляется.

Если кто-нибудь может указать мне рабочий пример для загрузки или посмотреть, что я пропускаю, это будет оценено.

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Ваш вопрос говорит о двух проблемах, где вторая просто связана с первой, что само по себе является для вас настоящей проблемой.

  1. System.IO.IOException: неожиданный конец потока, возможно, содержимое уже прочитано другим компонентом.

    Это происходит потому, что вы явно устанавливаете заголовок Content-Type при использовании Почтальона (подтверждается в комментариях). Это означает, что запрос, отправляемый на конечную точку ASP.NET Core, является неполным, что приводит к ошибке, показанной выше. Вместо этого просто удалите этот заголовок и позвольте Почтальону позаботиться об этом за вас.

  2. Этот подход фактически превращает его в веб-метод, но параметр IFormFile всегда равен нулю.

    Экземпляр IFormFile здесь null просто потому, что name, используемый в форме HTML (files) и имя параметра IFormFile (file) , не совпадают . Все, что вам нужно сделать здесь, это использовать, например. file в обоих местах.

0 голосов
/ 11 сентября 2018
[HttpPost("UploadFiles")]
public async Task<IActionResult> Post(List<IFormFile> files)
{
    long size = files.Sum(f => f.Length);

    // full path to file in temp location
    var filePath = Path.GetTempFileName();

    foreach (var formFile in files)
    {
        if (formFile.Length > 0)
        {
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await formFile.CopyToAsync(stream);
            }
        }
    }

Попробуйте это

https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.1

    // process uploaded files
    // Don't rely on or trust the FileName property without validation.

    return Ok(new { count = files.Count, size, filePath});
}
...