如何在Asp.Net Web Api中接受复合请求

时间:2017-10-12 16:48:34

标签: c# asp.net rest asp.net-web-api

我有一个POST被发送到我设置的ASP.NET Web API端点。我已经记录了传入的请求,它们看起来像这样:

Host: somedomain.net
User-Agent: Jakarta; Commons-HttpClient/3.0.1
--7ZRj4zj5nzTkWtBlwkO5Y4Il-En_uTGP2enCIMn
Content-Disposition: form-data; name="companyId"
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 8bit

985
--7ZRj4zj5nzTkWtBlwkO5Y4Il-En_uTGP2enCIMn
Content-Disposition: form-data; name="inputFormData"
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 8bit

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><response>Response XML Data</response>
--7ZRj4zj5nzTkWtBlwkO5Y4Il-En_uTGP2enCIMn
Content-Disposition: form-data; name="completedAgreement"; filename="48ce7fa4079790440a964815a744d232.zip"
Content-Type: application/octet-stream; charset=ISO-8859-1
Content-Transfer-Encoding: binary

PK

我不确定如何让ASP.NET识别这一点。我已经尝试使用名称作为参数,它们是空的。

另一家公司控制着POST,所以我无法修改它的发送方式。

1 个答案:

答案 0 :(得分:0)

我必须创建一个MultipartStreamProvider来将我的数据拆分为表单数据和文件。

    /// <summary>
    /// Splits a multipart form post that has form data and files
    /// </summary>
    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;
        }
    }

然后,只需使用提供程序获取控制器上的文件即可。

    [HttpPost]
    public async Task<IHttpActionResult> Post()
    {
        // get the form data posted and split the content into form data and files
        var provider = await Request.Content.ReadAsMultipartAsync(new InMemoryMultipartFormDataStreamProvider());

        // access form data
        NameValueCollection formData = provider.FormData;
        List<HttpContent> files = provider.Files;

        // Do something with files and form data

        return Ok();
    }