网页API:如何使用MultipartMemoryStreamProvider时访问多部分表单值? [英] Web API: how to access multipart form values when using MultipartMemoryStreamProvider?

查看:886
本文介绍了网页API:如何使用MultipartMemoryStreamProvider时访问多部分表单值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以前用MultipartFormDataStreamProvider来处理多部分请求。因为我要上传的文件被存储,而不是磁盘文件在内存中,我已经改变了我的code使用MultipartMemoryStreamProvider。该文件加载似乎工作正常,但我不再能够访问
其他形式的价值是能获得通过 provider.FormData MultipartFormDataStreamProvider下。可能有人告诉我怎么做呢?

原始请求由小提琴手捕获:

  POST http://myserver.com/QCCSvcHost/MIME/RealtimeTrans/ HTTP / 1.1
内容类型:多重/ form-data的;边界=XbCY
主持人:NA-W-lxu3
内容长度:1470
期望:100-继续
连接:保持活动--XbCY
内容类型:text / plain的;字符集= UTF-8
内容处置:表格数据;名称= PayloadTypeX12_270_Request_005010X279A1
--XbCY
内容类型:text / plain的;字符集= UTF-8
内容处置:表格数据;名称= ProcessingMode即时的
--XbCY
内容类型:text / plain的;字符集= UTF-8
内容处置:表格数据;名称= PayloadIDe51d4fae-7dec-11D0-a765-00a0c91e6fa6
--XbCY
内容类型:text / plain的;字符集= UTF-8
内容处置:表格数据;名称=时间戳2007-08-30T10:20:34Z
--XbCY
内容类型:text / plain的;字符集= UTF-8
内容处置:表格数据;名称= SenderIDHospitalA
--XbCY
内容类型:text / plain的;字符集= UTF-8
内容处置:表格数据;名称= ReceiverIDPayerB
--XbCY
内容类型:text / plain的;字符集= UTF-8
内容处置:表格数据;名称= CORERuleVersion2.2.0
--XbCY
内容处置:表格数据;名称=净荷;文件名= 276_5010.ediISA * 00 *〜SE * 16 * 0001〜GE * 1 * 1〜国际能源署* 1 * 191543498〜
--XbCY--

我的控制器code:

 字符串有效载荷= NULL;
雷士的NameValueCollection = NULL;
字符串FNAME = NULL;
StringBuilder的SB =新的StringBuilder();
sb.AppendLine();
的foreach(在provider.Contents StreamContent项)
{
    FNAME = item.Headers.ContentDisposition.FileName;
    如果(!String.IsNullOrWhiteSpace(FNAME))
    {
        有效载荷= item.ReadAsStringAsync()结果。
    }
    其他
    {
        雷士= item.ReadAsFormDataAsync()结果。
    }
}


解决方案

更新2015年4月28日

您可以创建基于 MultipartFormDataRemoteStreamProvider 自定义提供。结果
例如:

 公共类CustomMultipartFormDataProvider:MultipartFormDataRemoteStreamProvider
{
    公众覆盖RemoteStreamInfo GetRemoteStream(HttpContent父母,HttpContentHeaders头)
    {
        返回新RemoteStreamInfo(
            remoteStream:新的MemoryStream()
            位置:的String.Empty,
            文件名:的String.Empty);
    }
}


更新

自定义在内存MultiaprtFormDataStreamProvider:

 公共类InMemoryMultipartFormDataStreamProvider:MultipartStreamProvider
{
    私人的NameValueCollection _formData =新的NameValueCollection();
    私人列表< HttpContent> _fileContents =新的List< HttpContent>();    其中HttpContents的//设置指标,我们指​​定为表单数据
    私人收藏<布尔> _isFormData =新的收集和LT;布尔>();    ///<总结>
    ///获取<见CREF =NameValueCollection中/>形式的数据通过作为多部分形式的数据的一部分。
    ///< /总结>
    公众的NameValueCollection FORMDATA
    {
        {返回_formData; }
    }    ///<总结>
    ///获取的&LT名单;见CREF =HttpContent/> S包含上传的文件在内存中重新presentation。
    ///< /总结>
    公开名单< HttpContent>档
    {
        {返回_fileContents; }
    }    公共覆盖流GetStream(HttpContent父母,HttpContentHeaders头)
    {
        //对于表单数据,内容处理标头是必需的
        ContentDispositionHeaderValue contentDisposition = headers.ContentDisposition;
        如果(contentDisposition!= NULL)
        {
            //我们将发布这个过程作为表单数据
            _isFormData.Add(String.IsNullOrEmpty(contentDisposition.FileName));            返回新的MemoryStream();
        }        //如果没有Content-Disposition头是present。
        抛出新的InvalidOperationException异常(的String.Format(找不到所需的{0}在MIME多主体部分头字段..,内容处置));
    }    ///<总结>
    ///读非文件的内容的表单数据。
    ///< /总结>
    ///<&回报GT;< /回报>
    公共覆盖异步任务ExecutePostProcessingAsync()
    {
        //寻找非文件HttpContents的实例,异步阅读
        //得到字符串内容,然后添加的表单数据
        对于(INT指数= 0;指数 - LT; Contents.Count;指数++)
        {
            如果(_isFormData [指数])
            {
                HttpContent formContent =目录[指数]
                //提取从内容处置头名。我们知道,从早期的标头是present。
                ContentDispositionHeaderValue contentDisposition = formContent.Headers.ContentDisposition;
                字符串formFieldName = UnquoteToken(contentDisposition.Name)?的String.Empty;                //读取内容作为字符串数据,并添加表单数据
                字符串formFieldValue =等待formContent.ReadAsStringAsync();
                FormData.Add(formFieldName,formFieldValue);
            }
            其他
            {
                _fileContents.Add(目录[指数]);
            }
        }
    }    ///<总结>
    ///令牌上删除边界的报价,如果present
    ///< /总结>
    ///< PARAM NAME =令牌>令牌来解除引用< /参数>
    ///<退货和GT;非上市令牌LT; /回报>
    私人静态字符串UnquoteToken(字符串标记)
    {
        如果(String.IsNullOrWhiteSpace(标记))
        {
            返回记号。
        }        如果(token.StartsWith(\\,StringComparison.Ordinal)及&放大器; token.EndsWith(\\,StringComparison.Ordinal)及&放大器; token.Length→1)
        {
            返回token.Substring(1,token.Length - 2);
        }        返回记号。
    }
}

用法

 公共异步任务后()
{
    如果(!Request.Content.IsMimeMultipartContent(表单数据))
    {
        抛出新的Htt presponseException(的HTTPStatus code.BadRequest);
    }    VAR提供商=等待Request.Content.ReadAsMultipartAsync< InMemoryMultipartFormDataStreamProvider>(新InMemoryMultipartFormDataStreamProvider());    //获取表单数据
    NameValueCollection中FORMDATA = provider.FormData;    //访问文件
    IList的< HttpContent>文件= provider.Files;    //例:读文件的流如下图所示
    HttpContent文件1 =文件[0];
    流file1Stream =等待file1.ReadAsStreamAsync();
}

I used to use MultipartFormDataStreamProvider to process multipart requests. Since I want the uploaded file to be stored in memory, instead of a disk file, I've changed my code to use MultipartMemoryStreamProvider. The file loading seems to be working fine but I am no longer able to access other form values which were available through provider.FormData under MultipartFormDataStreamProvider. Could someone show me how to do this?

The raw request captured by 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--

My controller code:

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;
    }
}

解决方案

Updated 4/28/2015

You could create a custom provider based on MultipartFormDataRemoteStreamProvider.
Example:

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


Updated

Custom In-memory 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;
    }
}

Usage:

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();
}

这篇关于网页API:如何使用MultipartMemoryStreamProvider时访问多部分表单值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆