C# 缺少内容类型边界
Posted
技术标签:
【中文标题】C# 缺少内容类型边界【英文标题】:C# Missing content-type boundary 【发布时间】:2018-03-18 07:11:03 【问题描述】:我正在使用 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();
...
所以我可以提出请求,但是当我尝试从 froms 文件集合中获取文件时出现异常
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 做同样的事情时,一切都很好。 那么边界实际上是什么,为什么我会错过它以及如果真的需要它如何添加它?
【问题讨论】:
也许this comment 会有所帮助。 @NightOwl888 未设置标头内容类型时 - 请求不会超过 [Consumes("multipart/form-data")] 属性,我会收到缺少内容类型异常 @NightOwl888 你是对的。我们不需要修改该标题 【参考方案1】:如果您只是上传文件,为什么不直接获取 Request.Body 流:
[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...
【讨论】:
以上是关于C# 缺少内容类型边界的主要内容,如果未能解决你的问题,请参考以下文章
如何以编程方式设置内容类型?获取 org.jvnet.mimepull.MIMEParsingException:缺少开始边界
提供的“HttpContent”实例无效。它没有带有“边界”参数的“多部分”内容类型标头
C# ASP.NET ASP.NET#命名空间"System.Data"中不存在类型或命名空间名称"Linq"(是否缺少程序集引用?)