Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

asp.net - Parsing/Consuming a MultipartFormDataContent (set by MVC) on the WebApi side

I got the ByteArrayContent to work

/* MVC Method , ByteArrayContent */

        private async Task<HttpResponseMessage> ExecuteProxy(string url)
        {
            using (var client = new HttpClient(HttpClientHandlerFactory.GetWindowsAuthenticationHttpClientHandler()))
            {

                byte[] byte1 = new byte[] { 1, 2, 3 };

                ByteArrayContent byteContent = new ByteArrayContent(byte1);

                this.Request.Method = HttpMethod.Post;
                this.Request.Content = byteContent;

                return await client.SendAsync(this.Request);                    

            }
        }

/* WebApi Delegating Handler , ByteArrayContent */

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var byteArray = request.Content.ReadAsByteArrayAsync().Result;

            if (null != byteArray)
            {
                /* I see the byte of "1,2,3" */
            }
        }

The below method isn't part of the problem, but I include it for completeness.

public static class HttpClientHandlerFactory
{
    public static HttpClientHandler GetWindowsAuthenticationHttpClientHandler()
    {
        HttpClientHandler returnHandler = new HttpClientHandler()
        {
            UseDefaultCredentials = true,
            PreAuthenticate = true
        };

        return returnHandler;
    }
}   

I'm having trouble "getting" the MultipartFormDataContent on the WebApi side of things.

/* MVC Method , MultipartFormDataContent */

        private async Task<HttpResponseMessage> ExecuteProxy(string url)
        {
            using (var client = new HttpClient(HttpClientHandlerFactory.GetWindowsAuthenticationHttpClientHandler()))
            {

                byte[] byte1 = new byte[] { 1, 2, 3 };
                ByteArrayContent byteContent1 = new ByteArrayContent(byte1);

                StringContent stringContent1 = new StringContent("StringContent1Value");

                byte[] byte2 = new byte[] { 4, 5, 6 };
                ByteArrayContent byteContent2 = new ByteArrayContent(byte2);                

                StringContent stringContent2 = new StringContent("StringContent2Value");

                MultipartFormDataContent multipartContent = new MultipartFormDataContent();
                multipartContent.Add(byteContent1, "MyByteArrayContent1");
                multipartContent.Add(stringContent1);   
                multipartContent.Add(byteContent2, "MyByteArrayContent2");
                multipartContent.Add(stringContent2);   



                this.Request.Method = HttpMethod.Post;
                this.Request.Content = multipartContent;

                return await client.SendAsync(this.Request);                    

            }
        }



        /* WebApi Delegating Handler , MultipartFormDataContent*/

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            /* I have no idea how to change this back into a MultipartFormDataContent .. or however else you parse it */
        }

I've googled and read about 40 SOF posts about it. The solution still alludes me.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

So the magic method seems to be ReadAsMultipartAsync

There were two issues with this. One minor, one significant.

  1. ReadAsMultipartAsync is an extension method. (This is the minor issue)

    /* System.Net.Http.Formatting.dll */

and

using System.Net.Http.Headers;

This is why I did not see this method originally in the intellisense. (I had not added the reference .. or the using statement to my .cs)

  1. There was an issue with the method itself (outlined in the link below)

Request.Content.ReadAsMultipartAsync never returns

So below is what I came up with that allows "by name" finding.

 /* WebApi Delegating Handler , MultipartFormDataContent*/

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {

        /* see https://stackoverflow.com/questions/15201255/request-content-readasmultipartasync-never-returns */
        IEnumerable<HttpContent> contents = null;
        Task.Factory.StartNew(
                () =>
                contents = request.Content.ReadAsMultipartAsync().Result.Contents,
                CancellationToken.None,
                TaskCreationOptions.LongRunning, // guarantees separate thread
                TaskScheduler.Default)
            .Wait();

        if (null != contents)
        {
            //// This could be accomplished with LINQ queries, but I've left the for-loops in ... so its easier to see what's going on
            foreach (HttpContent currentHttpContent in contents)
            {
                if (null != currentHttpContent)
                {
                    if (null != currentHttpContent.Headers)
                    {
                        HttpContentHeaders cheaders = currentHttpContent.Headers;

                        if (null != cheaders)
                        {
                            if (null != cheaders.ContentDisposition)
                            {
                                System.Net.Http.Headers.ContentDispositionHeaderValue cdhv = cheaders.ContentDisposition;
                                if (null != cdhv)
                                {
                                    if (!string.IsNullOrEmpty(cdhv.Name))
                                    {
                                        if (cdhv.Name.Equals("MyByteArrayContent1", StringComparison.OrdinalIgnoreCase))
                                        {
                                            byte[] byteArray = null;
                                            ////currentHttpContent.LoadIntoBufferAsync().Wait();
                                            ////currentHttpContent.ReadAsByteArrayAsync().ContinueWith(t =>
                                            ////{
                                            ////    byteArray = t.Result;
                                            ////});
                                            byteArray = currentHttpContent.ReadAsByteArrayAsync().Result;
                                        }

                                        /* you can also check for MyByteArrayContent2, StringContent1Value, StringContent2Value as well, left out for brevity */
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

Other links:

Request.Content.ReadAsMultipartAsync never returns

Multipart form POST using ASP.Net Web API

How to get MultipartFormDataContent in Web.API Post method?

How do I get the file contents of a MultipartMemoryStreamProvider as a byte array?

Post byte array to Web API server using HttpClient

Why is the body of a Web API request read once?

(No answer for the below one)

How to parse MultipartFormDataContent

APPEND:

Here is the linq query I figured out:

        if (null != contents)
        {
            /* sometimes the ContentDisposition.Name is null so the extra where filters are helpful to avoid object-null-reference exception */
            HttpContent foundContent = (from cnt in contents
                                       where null!= cnt && null != cnt.Headers && null != cnt.Headers.ContentDisposition && !string.IsNullOrEmpty(cnt.Headers.ContentDisposition.Name) && cnt.Headers.ContentDisposition.Name.Equals("MyByteArrayContent1", StringComparison.OrdinalIgnoreCase)
                                       select cnt).FirstOrDefault();

            if (null != foundContent )
            {
                byte[] byteArray = foundContent .ReadAsByteArrayAsync().Result;
            }
        }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
...