C# 模型绑定无法与asp.net核心webapi控制器操作方法中的流类型参数一起工作。(即使使用自定义streaminputformatter)
我想上传文件到asp net核心web api控制器的操作方法。我正在以“应用程序/八位字节流”的形式发送内容类型。我已经创建了名为StreamInputFormatter的自定义输入格式化程序。正在调用streaminputformatter,但未调用控制器中的操作方法?我也犯了同样的错误 “InvalidOperationException:此流不支持超时。” StreamInputFormatter:C# 模型绑定无法与asp.net核心webapi控制器操作方法中的流类型参数一起工作。(即使使用自定义streaminputformatter),c#,asp.net-web-api,.net-core,C#,Asp.net Web Api,.net Core,我想上传文件到asp net核心web api控制器的操作方法。我正在以“应用程序/八位字节流”的形式发送内容类型。我已经创建了名为StreamInputFormatter的自定义输入格式化程序。正在调用streaminputformatter,但未调用控制器中的操作方法?我也犯了同样的错误 “InvalidOperationException:此流不支持超时。” StreamInputFormatter: public class StreamInputFormatter : IInputFo
public class StreamInputFormatter : IInputFormatter
{
public bool CanRead(InputFormatterContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var contentType = context.HttpContext.Request.ContentType;
if (contentType == "application/octet-stream")
{
return true;
}
return false;
}
public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var memoryStream = new MemoryStream();
context.HttpContext.Request.Body.CopyTo(memoryStream);
return InputFormatterResult.SuccessAsync(memoryStream);
}
}
公共类StreamInputFormatter:IIInputFormatter
{
公共bool可读取(InputFormatterContext)
{
if(上下文==null)
{
抛出新ArgumentNullException(nameof(context));
}
var contentType=context.HttpContext.Request.contentType;
if(contentType==“应用程序/八位字节流”)
{
返回true;
}
返回false;
}
公共任务ReadAsync(InputFormatterContext上下文)
{
if(上下文==null)
{
抛出新ArgumentNullException(nameof(context));
}
var memoryStream=新的memoryStream();
context.HttpContext.Request.Body.CopyTo(memoryStream);
返回InputFormatterResult.SuccessAsync(memoryStream);
}
}
控制器动作方法:
[HttpPost("{documentType}")]
public async Task<IActionResult> CreateJob(string documentType, [FromBody]Stream template)
{
}
[HttpPost(“{documentType}”)]
公共异步任务CreateJob(字符串documentType,[FromBody]流模板)
{
}
听起来您出现此错误是因为DefaultObjectValidator
对不受支持的流
属性进行了迭代(有关一些信息,请参阅此)
要跳过流模型验证,可以添加
services.AddMvc(options =>
{
...
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Stream)));
});
请参阅您的配置。对于查找此完整示例的任何人,以下内容可能会有所帮助: Startup.cs
services.AddMvc(options =>
{
options.InputFormatters.Add(new StreamInputFormatter());
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Stream)));
});
StreamInputFormatter.cs
public class StreamInputFormatter : IInputFormatter
{
// enter your list here...
private readonly List<string> _allowedMimeTypes = new List<string>
{ "application/pdf", "image/jpg", "image/jpeg", "image/png", "image/tiff", "image/tif", "application/octet-stream" };
public bool CanRead(InputFormatterContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var contentType = context.HttpContext.Request.ContentType;
if (_allowedMimeTypes.Any(x => x.Contains(contentType)))
{
return true;
}
return false;
}
public Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// enable stream rewind or you won't be able to read the file in the controller
var req = context.HttpContext.Request;
req.EnableRewind();
var memoryStream = new MemoryStream();
context.HttpContext.Request.Body.CopyTo(memoryStream);
req.Body.Seek(0, SeekOrigin.Begin);
return InputFormatterResult.SuccessAsync(memoryStream);
}
}
公共类StreamInputFormatter:IIInputFormatter
{
//在这里输入您的列表。。。
私有只读列表_allowedMimeTypes=新列表
{“application/pdf”、“image/jpg”、“image/jpeg”、“image/png”、“image/tiff”、“image/tif”、“application/octet-stream”};
公共bool可读取(InputFormatterContext)
{
if(上下文==null)
{
抛出新ArgumentNullException(nameof(context));
}
var contentType=context.HttpContext.Request.contentType;
if(_allowedMimeTypes.Any(x=>x.Contains(contentType)))
{
返回true;
}
返回false;
}
公共任务ReadAsync(InputFormatterContext上下文)
{
if(上下文==null)
{
抛出新ArgumentNullException(nameof(context));
}
//启用流回放,否则您将无法读取控制器中的文件
var req=context.HttpContext.Request;
req.EnableRewind();
var memoryStream=新的memoryStream();
context.HttpContext.Request.Body.CopyTo(memoryStream);
请求Body.Seek(0,SeekOrigin.Begin);
返回InputFormatterResult.SuccessAsync(memoryStream);
}
}
然后控制器:
public class FileController : BaseController
{
[HttpPost("customer/{customerId}/file", Name = "UploadFile")]
[SwaggerResponse(StatusCodes.Status201Created, typeof(UploadFileResponse))]
[Consumes("application/octet-stream", new string[] { "application/pdf", "image/jpg", "image/jpeg", "image/png", "image/tiff", "image/tif"})]
public async Task<IActionResult> UploadFile([FromBody] Stream file, [FromRoute] string customerId, [FromQuery] FileQueryParameters queryParameters)
{
// file processing here
}
}
公共类FileController:BaseController
{
[HttpPost(“customer/{customerId}/file”,Name=“UploadFile”)]
[SwaggerResponse(StatusCodes.Status201Created,typeof(UploadFileResponse))]
[使用(“应用程序/八位字节流”,新字符串[]{“应用程序/pdf”,“图像/jpg”,“图像/jpeg”,“图像/png”,“图像/tiff”,“图像/tif”})]
公共异步任务上载文件([FromBody]流文件,[FromRoute]字符串customerId,[FromQuery]文件queryParameters queryParameters)
{
//这里的文件处理
}
}
您在哪里使用了StreamInputFormatter?对于Startup.cs中的中间件?你能分享代码吗?你试过字节数组吗?[FromBody]byte[]Template每当您的复杂类型验证无法帮助您使用SuppressChildValidationMetadataProvider时,最好跳过它返回InputFormatterResult.SuccessAsync(context.HttpContext.Request.Body)代码>在不复制流的情况下对我有效。