WebAPI读取MIME多部分主体部分错误

本文关键字:主体部 错误 多部 读取 MIME WebAPI | 更新日期: 2023-09-27 18:02:53

我的团队最近重构了一个Web API服务,将一些重复的代码移到了静态方法中。一种方法与从请求中提取上传的文件有关。该方法在单元测试中工作,但在负载下抛出异常。部分代码是在一个SO帖子中发现的,但我担心,总的来说,我们没有正确使用它。下面是代码:

internal static string ExtractFile(HttpRequestMessage request)
{
    if (request.Content.IsMimeMultipartContent())
    {
        string uploadRoot = ServiceHelper.GetUploadDirectoryPath();
        var provider = new MultipartFormDataStreamProvider(uploadRoot);
        try
        {
            Task.Factory
            .StartNew(() => provider = request.Content.ReadAsMultipartAsync(provider).Result,
                CancellationToken.None,
                TaskCreationOptions.LongRunning, // guarantees separate thread
                TaskScheduler.Default)
            .Wait();
        }
        catch(System.AggregateException ae)
        {
            if(log.IsErrorEnabled)
            {
                foreach(var ex in ae.InnerExceptions)
                {
                    log.Error("ReadAsMultipartAsync task error.", ex);
                }
            }
            var errorResponse = request.CreateErrorResponse(HttpStatusCode.InternalServerError, "An error occurred while extracting the uploaded file from the request.");
            throw new HttpResponseException(errorResponse);
        }
        var fileData = provider.FileData.First();
        var localName = fileData.LocalFileName;
        var content = File.ReadAllText(localName);
        if (log.IsDebugEnabled)
        {
            var embeddedName = fileData.Headers.ContentDisposition.FileName;
            log.DebugFormat("File {0} was successfully uploaded as '{1}'.", embeddedName, localName);
        }
        return content;
    }
    else
    {
        log.Error("Invalid request received. Request must be in a multipart/form-data request.");
        var errorResponse = request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Request must be a multipart/form-data request and contain one file.");
        throw new HttpResponseException(errorResponse);
    }
}

浏览日志,我看到如下错误:

先。读取MIME多部分主体部分时出错。--> System.Net.HttpListenerException: I/O操作已被中止,因为线程退出或应用程序请求

HttpListenerRequest处理

先。读取MIME多部分主体部分时出错。System.IO.IOException --> System.Net.HttpListenerException:一个操作被尝试在一个不存在的网络连接上

此web服务作为自托管的OWIN Windows服务运行。上传的文件很小(3k到4k)。

我无法通过一次上传重新创建这个问题。与服务通信的客户端使用任务来发布文件,但它通常不会同时运行超过4或5个任务。我和我的团队对。net任务相对来说还是新手。其中一个开发人员想知道TaskCreationOptions。LongRunning参数实际上弊大于利。有什么建议吗?

更新:

我试着切换出任务。工厂代码:

var task = Task.Run(async () => await request.Content.ReadAsMultipartAsync(provider));
task.Wait();
provider = task.Result;

我仍然有一些问题,但这似乎工作得更好。不知道为什么。

WebAPI读取MIME多部分主体部分错误

我也有同样的问题,通过在web.config

中添加以下代码来解决
<system.web>
    <httpRuntime maxRequestLength="30000000" />
</system.web>
<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="30000000" />
      </requestFiltering>
    </security>
</system.webServer>

来源:http://stackoverflow.com/questions/20942636/webapi-cannot-parse-multipart-form-data-post

在分析日志时,我意识到我们的客户端代码对于生成的线程数量非常激进。我给客户端增加了一个节流阀来减慢一些速度,服务器更喜欢这样。我相信我最初的服务器代码更改几乎没有影响。输出的差异可能是由于网络延迟等其他变量造成的。

下面是我如何更新客户端代码的:

// New private field in my client class
private SemaphoreSlim _semaphore = new SemaphoreSlim(Settings.Default.MaxConcurrentRequests, Settings.Default.MaxConcurrentRequests);
// Added continuation to Polly tasks
foreach (var file in files)
{
    var task = retryPolicy.ExecuteAsync(() => SendIllustrationRequest(file));
    task.ContinueWith((x) => _semaphore.Release());
    _transactionTasks.Add(task);
}
Task.WaitAll(_transactionTasks.ToArray());
// Added semaphore wait method to the start of the SendIllustrationRequest(file) method
_semaphore.Wait();

这个技术对我来说很有效,因为我在使用Polly, Polly立即开始执行任务。如果您可以选择创建任务而不立即启动它们,那么还有其他选项。

让我声明,这不是为什么你的代码失败的答案,但我有一个问题,更容易问一些空间来显示一些格式化的代码。如果这没有提供任何帮助/方向,我将/可以删除这个作为答案。

我假设你的方法是从传入的web api请求调用。你有什么理由不让它"异步的所有方式"?这是构造它的最简单的方法,并且由于代码不佳或有缺陷而导致死锁的可能性最小(如果您刚开始使用Tasks和async/await,则非常容易)。

// new signature (I changed the name and prefixed Async which is a common convention)
internal static async Task<string> ExtractFileAsync(HttpRequestMessage request)
{
    if (request.Content.IsMimeMultipartContent())
    {
        string uploadRoot = ServiceHelper.GetUploadDirectoryPath();
        var provider = new MultipartFormDataStreamProvider(uploadRoot);
        await request.Content.ReadAsMultipartAsync(provider);
        /* rest of code */
    }
}
// calling method example from some Web API Controller
public async Task<IHttpActionResult> Post(CancellationToken token)
{ 
    var result = await ExtractFileAsync(Request).ConfigureAwait(true); 
    /*some other code*/
}