0

I am trying to upload file from desktop client to server using api. In our project, we are using Refit to create api.

I am trying to implement it according to Refit manual. https://github.com/reactiveui/refit#multipart-uploads

This is Api interface method:

        [Multipart]
        [Post("/Projects/SaveProjectFile")]
        Task<IApiResponse> SaveFileAsync([AliasAs("projectFile")] StreamPart stream, [Query] string projectId);

This is how I use it in code:

        public async Task SaveProjectToCloudAsync()
        {
            using (var fileStream = new FileStream(_pdProject.currentFilePath, FileMode.Open))
            {
                var streamPart = new StreamPart(fileStream, "project.pd");
                var response = await _projectApi.SaveFileAsync(streamPart, _projectToSave.Id);
            }
        }

And this is my api controller (It is not fished. I am just testing getting a file):

        [HttpPost]
        public async Task<IActionResult> SaveProjectFileAsync(IFormFile projectFile, [FromQuery] string projectId)
        {
            await using var saveFileStream = System.IO.File.OpenWrite($"{projectId}_{DateTime.Now.ToString().Replace(":",".")}.pd");
            await projectFile.CopyToAsync(saveFileStream);
            return Ok();
        }

And my data gets to the controller. The problem is: during debug I can see that the server receives IFormFile with correct name of the file (project.pd), but there is no data. Length is zero. As a result it saves an empty file.

I cannot understand what am I doing wrong here, and googling did not help. I would highly appreciate any help you can give me.

2 Answers2

0

There is no problem with the code you provided. The reason why you did not receive the file may be because of your path problem. You did not obtain the file through the corresponding path.

Please check if the length of fileStream is 0: enter image description here

If the length of the fileStream is not 0, you should receive the file correctly: enter image description here

Please double check whether you can get the corresponding file correctly through _pdProject.currentFilePath.

I used MVC to call the Api and kept the file in wwwroot:

public class HomeController : Controller
{
    private readonly ISaveFile _projectApi;
    private readonly IWebHostEnvironment _webHostEnvironment;

    public HomeController(ISaveFile saveFile,IWebHostEnvironment webHostEnvironment)
    {
        _projectApi = saveFile;
        _webHostEnvironment = webHostEnvironment;
    }
    public async Task<IActionResult> Test()
    {
        var path = Path.Combine(_webHostEnvironment.WebRootPath, "img1.jpg");
        using (var fileStream = new FileStream(path, FileMode.Open))
        {
            var streamPart = new StreamPart(fileStream, "img1.jpg");
            var response = await _projectApi.SaveFileAsync(streamPart, "project.pd");
        }
        return View();
    }
}

As you can see, the file path is correct and the parameters of the Api are correct.

Chen
  • 4,499
  • 1
  • 2
  • 9
0

my colleague and I had this issue yesterday. We initially fudged it and used BytePart but this requires reading the whole stream into memory.

Eventually, the solution was quite simple although bizarrely undocumented. Simply make certain your stream is at the start position before sending.

Refit method -

[Multipart]
[Post("/api/Image/{id}/{extension}")]
Task<string> UploadImage(string id, string extension, [AliasAs("file")] StreamPart stream);

Call from service -

public async Task<string> UploadFile(StreamUploadDto item)
{
    var file = item.Stream;
    file.Seek(0, SeekOrigin.Begin);
    var result = await _imageApi.UploadImage(item.Id, item.Extension, new StreamPart(file, item.Id, "image/jpg", "file")); 
    return result;
}

Rich Bryant
  • 865
  • 10
  • 27