asp.net-web-api - 网络API : how to access multipart form values when using MultipartMemoryStreamProvider?

标签 asp.net-web-api multipartform-data

我曾经使用MultipartFormDataStreamProvider来处理多部分请求。

由于我希望将上传的文件存储在内存中,而不是磁盘文件中,因此我更改了代码以使用 MultipartMemoryStreamProvider。文件加载似乎工作正常,但我无法再访问 其他表单值可通过 MultipartFormDataStreamProvider 下的 provider.FormData 获得。有人可以告诉我如何做到这一点吗?

Fiddler 捕获的原始请求:

POST http://myserver.com/QCCSvcHost/MIME/RealtimeTrans/ HTTP/1.1
Content-Type: multipart/form-data; boundary="XbCY"
Host: na-w-lxu3
Content-Length: 1470
Expect: 100-continue
Connection: Keep-Alive

--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=PayloadType

X12_270_Request_005010X279A1
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=ProcessingMode

RealTime
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=PayloadID

e51d4fae-7dec-11d0-a765-00a0c91e6fa6
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=TimeStamp

2007-08-30T10:20:34Z
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=SenderID

HospitalA
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=ReceiverID

PayerB
--XbCY
Content-Type: text/plain; charset=utf-8
Content-Disposition: form-data; name=CORERuleVersion

2.2.0
--XbCY
Content-Disposition: form-data; name=Payload; filename=276_5010.edi

ISA*00*~SE*16*0001~GE*1*1~IEA*1*191543498~
--XbCY--

我的 Controller 代码:

string payload = null;
NameValueCollection nvc = null;
string fname = null;
StringBuilder sb = new StringBuilder();
sb.AppendLine();
foreach (StreamContent item in provider.Contents)
{
    fname = item.Headers.ContentDisposition.FileName;
    if (!String.IsNullOrWhiteSpace(fname))
    {
        payload = item.ReadAsStringAsync().Result;
    }
    else
    {
        nvc = item.ReadAsFormDataAsync().Result;
    }
}

最佳答案

更新于 2015 年 4 月 28 日

您可以基于MultipartFormDataRemoteStreamProvider创建自定义提供程序。
示例:

public class CustomMultipartFormDataProvider : MultipartFormDataRemoteStreamProvider
{
    public override RemoteStreamInfo GetRemoteStream(HttpContent parent, HttpContentHeaders headers)
    {
        return new RemoteStreamInfo(
            remoteStream: new MemoryStream(),
            location: string.Empty,
            fileName: string.Empty);
    }
}
<小时/>

已更新

自定义内存中MultiaprtFormDataStreamProvider:

public class InMemoryMultipartFormDataStreamProvider : MultipartStreamProvider
{
    private NameValueCollection _formData = new NameValueCollection();
    private List<HttpContent> _fileContents = new List<HttpContent>();

    // Set of indexes of which HttpContents we designate as form data
    private Collection<bool> _isFormData = new Collection<bool>();

    /// <summary>
    /// Gets a <see cref="NameValueCollection"/> of form data passed as part of the multipart form data.
    /// </summary>
    public NameValueCollection FormData
    {
        get { return _formData; }
    }

    /// <summary>
    /// Gets list of <see cref="HttpContent"/>s which contain uploaded files as in-memory representation.
    /// </summary>
    public List<HttpContent> Files
    {
        get { return _fileContents; }
    }

    public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
    {
        // For form data, Content-Disposition header is a requirement
        ContentDispositionHeaderValue contentDisposition = headers.ContentDisposition;
        if (contentDisposition != null)
        {
            // We will post process this as form data
            _isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));

            return new MemoryStream();
        }

        // If no Content-Disposition header was present.
        throw new InvalidOperationException(string.Format("Did not find required '{0}' header field in MIME multipart body part..", "Content-Disposition"));
    }

    /// <summary>
    /// Read the non-file contents as form data.
    /// </summary>
    /// <returns></returns>
    public override async Task ExecutePostProcessingAsync()
    {
        // Find instances of non-file HttpContents and read them asynchronously
        // to get the string content and then add that as form data
        for (int index = 0; index < Contents.Count; index++)
        {
            if (_isFormData[index])
            {
                HttpContent formContent = Contents[index];
                // Extract name from Content-Disposition header. We know from earlier that the header is present.
                ContentDispositionHeaderValue contentDisposition = formContent.Headers.ContentDisposition;
                string formFieldName = UnquoteToken(contentDisposition.Name) ?? String.Empty;

                // Read the contents as string data and add to form data
                string formFieldValue = await formContent.ReadAsStringAsync();
                FormData.Add(formFieldName, formFieldValue);
            }
            else
            {
                _fileContents.Add(Contents[index]);
            }
        }
    }

    /// <summary>
    /// Remove bounding quotes on a token if present
    /// </summary>
    /// <param name="token">Token to unquote.</param>
    /// <returns>Unquoted token.</returns>
    private static string UnquoteToken(string token)
    {
        if (String.IsNullOrWhiteSpace(token))
        {
            return token;
        }

        if (token.StartsWith("\"", StringComparison.Ordinal) && token.EndsWith("\"", StringComparison.Ordinal) && token.Length > 1)
        {
            return token.Substring(1, token.Length - 2);
        }

        return token;
    }
}

用法:

public async Task Post()
{
    if (!Request.Content.IsMimeMultipartContent("form-data"))
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    var provider = await Request.Content.ReadAsMultipartAsync<InMemoryMultipartFormDataStreamProvider>(new InMemoryMultipartFormDataStreamProvider());

    //access form data
    NameValueCollection formData = provider.FormData;

    //access files
    IList<HttpContent> files = provider.Files;

    //Example: reading a file's stream like below
    HttpContent file1 = files[0];
    Stream file1Stream = await file1.ReadAsStreamAsync();
}

关于asp.net-web-api - 网络API : how to access multipart form values when using MultipartMemoryStreamProvider?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17072767/

相关文章:

qt - 将 Qt 中的 setWebhook 用于 Telegram 机器人

java - 从多部分请求中获取表单参数而不获取文件

带有 @RequestBody 的 Spring 多部分文件

c# - 如何使用不同的构造函数参数重用相同的 Controller 类

c# - LINQ 查询无法评估 StartsWith 中的 GET 参数

c# - asp.net webapi2 捕获所有路由

ruby-on-rails - form_for指定 ":html => { :multipart => true}"是否正确?

ios - Xamarin iOS 的 NSURLSession CreateUploadTask 失败

c# - 更新添加为 HttpClient 的 DefaultRequestHeaders 的自定义 header 值

python - 如何使用 multipart/form-data 通过 Telegram Bot 发送照片