使用ASP.Net的Web API的多部分表单POST表单、部分、Net、ASP

2023-09-03 02:08:11 作者:一盅浊酒醉方休

我有一个改编自A引导中的ASP.NET Web API RTM 的。

I have a POST ASP.Net Web Api method adapted from A guide to asynchronous file uploads in ASP.NET Web API RTM.

我遇到故障工作问题与所有发射的第一个请求被触发后,请求完成。

I am running into faulted Task problem with all the requests fired after the first request is fired and complete.

下面的情况:我有一个示例页面的员额和其他参数给Web API邮政法的文件。它工作正常,在第一时间和文件上传。但是,以后的所有请求最终在故障状态的任务。我得到MIME多流意外结束。 MIME多的信息是不完整的。任何想法,为什么?

Here’s the scenario: I have a sample page that posts a file along with other parameters to the Web API Post method. It works fine the first time and the file is uploaded. But, all subsequent requests end up the task in a faulted state. I get "Unexpected end of MIME multipart stream. MIME multipart message is not complete." Any ideas why?

粘贴下面是我的Post方法的来源$ C ​​$ C,样本HTML表单和总结例外。

Pasted below is the source code of my Post method, sample html form and the Aggregate Exception.

    public Task<HttpResponseMessage> Post([FromUri]string memberNumber)
    {
        // Check if the request contains multipart/form-data.
        if (!Request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }

        string root = HttpContext.Current.Server.MapPath("~/App_Data");
        var provider = new MultipartFormDataStreamProvider(root);

        // Read the form data and return an async task.
        var task = Request.Content.ReadAsMultipartAsync(provider).
            ContinueWith(t =>
            {
                if (t.IsFaulted || t.IsCanceled)
                {
                    throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception));
                }

                return Request.CreateResponse(HttpStatusCode.OK, new MyModel());
            });

        return task;
    }

我使用的一个样表像这样发射该Web API:

I am firing this web api using a sample form like this:

<form name="form1" method="post" enctype="multipart/form-data" action="api/claims/asd123" style="margin:auto;width:500px;">
    <div>
        <label for="HCPracticeNumber">HC Pratice Number:</label>
        <input type="text" name="HCPracticeNumber" id="HCPracticeNumber"/>
    </div>
    <div>
        <label for="ServiceDate">Service/Treatment date:</label>
        <input type="text" name="ServiceDate" id="ServiceDate"/>
    </div>
    <div>
        <label for="AmountClaimed">Amount Claimed:</label>
        <input type="text" name="AmountClaimed" id="AmountClaimed"/>
    </div>
    <div>
        <label for="Image">Image Attachment:</label>
        <input name="Image" type="file" />
    </div>
    <div>
        <input type="submit" value="Submit" />
    </div>
</form>

时,返回的AggregateException如下:

The AggregateException that is returned is as follows:

<Error>
<Message>An error has occurred.</Message>
    <ExceptionMessage>One or more errors occurred.</ExceptionMessage>
    <ExceptionType>System.AggregateException</ExceptionType>
    <StackTrace/>
    <InnerException>
        <Message>An error has occurred.</Message>
        <ExceptionMessage>
            Unexpected end of MIME multipart stream. MIME multipart message is not complete.
        </ExceptionMessage>
        <ExceptionType>System.IO.IOException</ExceptionType>
        <StackTrace>
            at System.Net.Http.Formatting.Parsers.MimeMultipartBodyPartParser.<ParseBuffer>d__0.MoveNext() at System.Net.Http.HttpContentMultipartExtensions.MoveNextPart(MultipartAsyncContext context)
        </StackTrace>
    </InnerException>
</Error>

更新:

在菲利普的在他的博客网站的建议,我修改后的方法来重置流的位置为0这样的:

After Filip's suggestion on his blog site, I modified the post method to reset the stream position to 0 like this:

        Stream reqStream = Request.Content.ReadAsStreamAsync().Result;
        if (reqStream.CanSeek)
        {
            reqStream.Position = 0;
        }
        var task = Request.Content.ReadAsMultipartAsync(provider).
            ContinueWith(t =>
            {
                if (t.IsFaulted || t.IsCanceled)
                {
                    throw new HttpResponseException(
                    Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
                    t.Exception));
                }

                return Request.CreateResponse(HttpStatusCode.OK, new MyModel());

            });

不过,这是非常不稳定code。它的工作原理有时没有其他时间。换句话说,它不能完全解决问题。

But, this is very temperamental code. It works sometimes it doesn't other times. In other words, it doesn't fix the problem fully.

推荐答案

事实证明,如菲利普的意见建议,这是我从改编的网络API使用处理程序Implementing消息处理程序来跟踪你的ASP .NET的Web API使用的正在读的内容主体,因此与该流的位置寻搞乱当请求正在我的POST方法处理。

It turns out, as Filip suggested in the comments, that the Web API Usage Handler that I adapted from Implementing Message Handlers To Track Your ASP .net Web API Usage was reading the content body and hence messing with the position seeker on the stream when the request was being processed in my POST method.

所以,我增加了一个条件语句的WebApiUsageHandler不读取请求体,如果请求的类型IsMimeMultipartContent的。这解决了问题。

So, I added a conditional statement to the WebApiUsageHandler to not read the request body if the request is of type IsMimeMultipartContent. This fixed the problem.

更新

我想更新与另一种选择的答复,通过电子邮件向我建议由菲利普,以便它记载:

I want to update the answer with another option, suggested to me by Filip via email, so that it is documented:

如果您使用code API使用处理程序中,就在阅读正文:

If you use this code inside the API usage handler, just before reading the body:

   //read content into a buffer
   request.Content.LoadIntoBufferAsync().Wait();

   request.Content.ReadAsStringAsync().ContinueWith(t =>
   {
       apiRequest.Content = t.Result;
       _repo.Add(apiRequest);
   });

的请求将被缓冲并且将有可能阅读两次,因此,上载将进一步有可能向下管道。 希望这有助于。

The request will be buffered and will be possible to read it twice, and therefore the upload will be possible further down the pipeline. Hope this helps.