C# Missing content-type boundary
Asked Answered
H

1

8

I'm using RestEase client library to make requests from one service to another. The interface of it looks like this

public interface IImportService1ApiClient
{
    [Put]
    [Header("Content-Type", "multipart/form-data")]
    Task<CreateValidationJobResponse> ImportZip([Body] byte[] zipByteArray);
}

And the endpoint (.Net Core 1.1, Web Api):

    [HttpPut()]
    [Consumes("multipart/form-data")]
    public async Task<IActionResult> ImportZip()
    {
         var zipFile = HttpContext.Request.Form.Files.FirstOrDefault();
     ...

So I'm able to make a request, but when I'm trying to get file from froms file collection I'm getting an exception

System.IO.InvalidDataException: Missing content-type boundary.

StackTrace:

 Connection id "0HL8CNQ0E4M94": An unhandled exception was thrown by the application.
System.IO.InvalidDataException: Missing content-type boundary.
   at Microsoft.AspNetCore.Http.Features.FormFeature.GetBoundary(MediaTypeHeaderValue contentType, Int32 lengthLimit)
   at Microsoft.AspNetCore.Http.Features.FormFeature.<InnerReadFormAsync>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Http.Features.FormFeature.ReadForm()
   at RODIX.Tacs.Services.Import.Api.Controllers.TacsLegacyImportController.<ImportZip>d__3.MoveNext() in C:\Users\borov\Source\Repos\Rodix.Tacs\Rodix.Tacs\services\RODIX.ImportService\src\RODIX.Tacs.Services.Import.Api\Controllers\TacsLegacyImportController.cs:line 32
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeActionMethodAsync>d__27.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextActionFilterAsync>d__25.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.<InvokeAsync>d__20.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationMiddleware.<Invoke>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Frame`1.<RequestProcessingAsync>d__2.MoveNext()

But when doing the same thing with Postman everything is ok. So what is boundary actually is, why I'm missing it and how to add it if it's really needed?

Hebner answered 6/10, 2017 at 13:3 Comment(3)
Perhaps this comment could be helpful.Margaritamargarite
@Margaritamargarite When headers content type is not set - request will not past [Consumes("multipart/form-data")] attribute and I'll get missing content type exceptionHebner
@Margaritamargarite You are right. We need to not modify that headerCounterglow
E
0

If you are just uploading a file, why not just grab the Request.Body Stream instead:

[HttpPost()]
[Consumes("application/zip")]
[Consumes("application/octet-stream")]
public async Task<IActionResult> ImportZip()
{
    using (var stream = new MemoryStream())
    {
        await Request.Body.CopyToAsync(stream);
    }

    // do whatever with the file...
}

I think you can also define it like so:

[HttpPost()]
[Consumes("application/zip")]
[Consumes("application/octet-stream")]
public async Task<IActionResult> ImportZip([FromBody] Stream bodyStream)
{
    using (var stream = new MemoryStream())
    {
        await bodyStream.CopyToAsync(stream);
    }

    // do whatever with the file...
}
Emee answered 20/11, 2018 at 12:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.