ASP.NET Core控制器如何绑定HTTP请求体中的二进制数据?
问题根源
IFormFile 默认仅支持解析 multipart/form-data 格式的请求体,你直接发送Raw二进制流时,ASP.NET Core 2.1 默认没有对应的模型绑定逻辑,所以参数始终为null。
解决方案:自定义Raw请求体模型绑定
步骤1:实现自定义模型绑定器
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ModelBinding; using System; using System.IO; using System.Threading.Tasks; public class RawRequestBodyModelBinder : IModelBinder { public async Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); var request = bindingContext.HttpContext.Request; if (request.ContentLength == null || request.ContentLength == 0) { bindingContext.Result = ModelBindingResult.Failed(); return; } // 支持绑定到byte数组、Stream、IFormFile三种类型参数 if (bindingContext.ModelType == typeof(byte[])) { using var ms = new MemoryStream(); await request.Body.CopyToAsync(ms); bindingContext.Result = ModelBindingResult.Success(ms.ToArray()); } else if (bindingContext.ModelType == typeof(Stream)) { bindingContext.Result = ModelBindingResult.Success(request.Body); } else if (bindingContext.ModelType == typeof(IFormFile)) { var formFile = new FormFile(request.Body, 0, request.ContentLength.Value, bindingContext.FieldName, bindingContext.FieldName) { Headers = request.Headers, ContentType = request.ContentType }; bindingContext.Result = ModelBindingResult.Success(formFile); } else { bindingContext.Result = ModelBindingResult.Failed(); } } }
步骤2:注册绑定器(两种方式二选一即可)
方式1:全局注册(推荐,所有对应类型参数都生效)
先实现绑定器提供者:
public class CustomModelBinderProvider : IModelBinderProvider { public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context.Metadata.ModelType == typeof(byte[]) || context.Metadata.ModelType == typeof(Stream) || context.Metadata.ModelType == typeof(IFormFile)) { return new RawRequestBodyModelBinder(); } return null; } }
在Startup.cs的ConfigureServices中注册:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { // 插入到绑定器列表首位,优先级最高 options.ModelBinderProviders.Insert(0, new CustomModelBinderProvider()); }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
方式2:单独给参数指定绑定器(无需修改全局配置)
直接在控制器参数上加标记即可:
public IActionResult Test([ModelBinder(typeof(RawRequestBodyModelBinder))] IFormFile file)
步骤3:控制器直接使用入参
现在你原来的控制器逻辑就可以正常运行,不需要手动读取Request.Body:
[HttpPost] [Consumes("image/png", "image/bmp", System.Net.Mime.MediaTypeNames.Application.Pdf, System.Net.Mime.MediaTypeNames.Image.Tiff)] [Route("test")] public IActionResult Test(IFormFile file) { // file已正常赋值,不会为空 var bitmap = new System.Drawing.Bitmap(file.OpenReadStream()); bitmap.Save(".\\file.bmp"); return Ok("Image height: " + bitmap.Height.ToString()); }
注意事项
- 调用方式和你现在用Postman发送Raw二进制的逻辑完全兼容,不需要修改请求格式,符合不能使用
multipart-form的业务限制 - 如果不需要封装为
IFormFile,直接把参数类型改为byte[]或Stream也可以正常绑定
内容的提问来源于stack exchange,提问作者lorenzoKyne
相关产品推荐
相关产品推荐

