C#缺少内容类型边界

时间:2017-10-06 13:03:50

标签: c# .net-core boundary media-type

我使用RestEase客户端库从一个服务向另一个服务发出请求。 它的界面看起来像这样

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

端点(.Net Core 1.1,Web Api):

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

所以我能够提出请求,但是当我试图从文件集中获取文件时,我得到了一个异常

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

堆栈跟踪:

 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()

但是当与Postman做同样的事情时,一切都还可以。 那么边界实际上是什么,为什么我会错过它以及如果真的需要它如何添加呢?

1 个答案:

答案 0 :(得分:0)

如果您只是上传文件,为什么不直接获取Request.Body Stream:

[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...
}

我想您也可以这样定义它:

[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...
}