Не удается отправить FileStream в AWS при публикации с параметром маршрута (работает нормально без) - PullRequest
0 голосов
/ 08 сентября 2018

Использование ASP.NET Core v.2.1.2 с AWSSDK для S3 (версия 3.3.20.2)

Один и тот же контроллер, два разных маршрута (один с параметром URL и один без). Методы идентичны, за исключением того, что у аргумента url param есть аргумент. Я хочу загрузить файл, но затем отправить его на S3 (и это прекрасно работает в случае отсутствия параметров).

Простое добавление аргумента id приводит к истечению времени ожидания запроса с ошибкой:

"Your socket connection to the server was not read from or written to within the timeout period. Idle connections will be closed."

Это ошибочный запрос:

curl -X POST \
  http://localhost:5000/api/post/image/4 \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -H 'Postman-Token: c78c7572-8822-4de7-a532-61538df87c85' \
  -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
  -F =@/Users/myusername/Desktop/peace.png

Полагаю, добавление параметра id изменяет HttpContext.Request.Body, но я не вижу этого изменения, когда я запускаю в режиме отладки и добавляю точки останова (поток выглядит точно так же)

Что мне здесь не хватает? Идентичный код, но с удаленным параметром id, работает для обоих маршрутов

Кстати, причина, по которой я хочу использовать параметр id, заключается в том, что после загрузки файла я могу записать идентификатор файла в сообщении как ссылку на запись в AWS

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using BlogApi.Models;
using BlogApi.Services;

namespace BlogApi.Controllers
{
  [Route("api/[controller]")]
  [ApiController]

  public class PostController : ControllerBase
  {
    public string AWS_KEY {get; private set;}
    public string AWS_SECRET {get; private set;}
    private readonly PostContext _context;
    private AmazonUploader uploader { get; set; }

    public PostController(PostContext context)
    {
      _context = context;
      AWS_KEY = "my_key";
      AWS_SECRET = "my_secret";
      uploader = new AmazonUploader(AWS_KEY, AWS_SECRET);
    }

    [HttpPost("image/{id}")]
    public string Image(long id)
    {
      var request = HttpContext.Request;
      var fileStream = request.Body;
      var contentLength = request.ContentLength;
      var contentType = request.ContentType;
      string key = Guid.NewGuid().ToString();

      var length = contentLength.HasValue ? (long)contentLength : 0;
      return uploader.sendMyFileToS3(fileStream, contentType, length, key).Result;
    }

    [HttpPost]
    public string MyFileUpload()
    {
      var request = HttpContext.Request;
      var fileStream = request.Body;
      var contentLength = request.ContentLength;
      var contentType = request.ContentType;
      string key = Guid.NewGuid().ToString();

      var length = contentLength.HasValue ? (long)contentLength : 0;
      return uploader.sendMyFileToS3(fileStream, contentType, length, key).Result;
    }
...

Просто для информации вот код моего класса AmazonUploader

using System;
using System.Diagnostics;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.S3.Transfer;
using Microsoft.Extensions.Configuration;

namespace BlogApi.Services
{
  public class AmazonUploader
  {
    private IAmazonS3 client;
    private const string bucketName = "my_bucket"; 
    private static readonly RegionEndpoint bucketRegion = RegionEndpoint.EUWest2;

    public AmazonUploader(string AWS_KEY, string AWS_SECRET) {
      client = new AmazonS3Client(AWS_KEY, AWS_SECRET, bucketRegion);
    }

    public async Task<ListObjectsResponse> ListingObjectsAsync()
    {            
        ListObjectsRequest request = new ListObjectsRequest
        {
            BucketName = bucketName
        };
        return await client.ListObjectsAsync(request);
    }
    public async Task<string> sendMyFileToS3(System.IO.Stream inputStream, string contentType, long contentLength, string key)
    {
      PutObjectRequest request = new PutObjectRequest
      {
        BucketName = bucketName,
        Key = key,
        ContentType = contentType,
        InputStream = inputStream 
      };
      request.Headers.ContentLength = contentLength;
      PutObjectResponse awsResponse = await client.PutObjectAsync(request);
      if (awsResponse.HttpStatusCode == HttpStatusCode.OK) {
          return key;
      } else {
          return "error";
      }
    }
  }
}

1 Ответ

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

Я только что нашел проблему, которая была

a) Я допустил ошибку и каким-то образом Почтальон добавил дополнительный заголовок Content-Type: application / x-www-form-encoded

б) даже если бы я не добавил этот заголовок по ошибке, фактический тип контента был неправильным - я отправлял как multipart / form-data, что не работает - мне нужно было отправить его как двоичный файл. Если я выберу эту опцию для Тела запроса в Почтальоне, это сработает.

...