简体   繁体   中英

How to use WebClient to POST to WebAPI using [FromBody]

The short of this is that I need to send a byte[] array as a body value. The problem is that [FromBody] is always null. All of the solutions I have seen so far involve the passed value going to a string in one way or another. This is fine if the original content being passed is plain text (ascii) but in cases where I'm sending (for example) a jpg, this doesn't work.

It is extremely important to realize and know that I CANNOT use HTTPClient as adding it in any form for some reason breaks the solution in all kinds of places. I am stuck using WebClient.

Here is the code I have below:

Calling page:

Private Function UploadFile(targetURL As String, fileAttachment As Byte()) As String
    Dim retVal As String = String.Empty
    Using client = New WebClient()
        Try                
            Dim request As HttpWebRequest = DirectCast(WebRequest.Create(targetURL), HttpWebRequest)
            request.Method = "POST"
            request.ContentType = "application/x-www-form-urlencoded"
            request.ContentLength = fileAttachment.Length

            Dim requestStream As Stream = request.GetRequestStream()
            requestStream.Write(fileAttachment, 0, fileAttachment.Length)

            Dim response As WebResponse = request.GetResponse()
            Dim respStream As Stream = response.GetResponseStream()
            Dim reader As New StreamReader(respStream)

            retVal = reader.ReadToEnd()
            respStream.Dispose()
            reader.Dispose()
        Catch ex As WebException
            If ex.Status = WebExceptionStatus.ProtocolError Then
                Dim wbrsp As HttpWebResponse = CType(ex.Response, HttpWebResponse)
                Throw New HttpException(CInt(wbrsp.StatusCode), wbrsp.StatusDescription)
            Else
                Throw New HttpException(500, ex.Message)
            End If
        End Try
    End Using
    Return retVal
End Function

WebAPI method:

    [Route("Upload/{appName}/{appKey}/{fileName}/{fileExt}")]
    public async Task<string> Post(string appName, string appKey, string fileName, string fileExt, [FromBody] byte[] values) { 
//snip as rest is not needed since values is always null

What would be a reasonable solution so that the byte array is not converted to a string (which has the effect of "corrupting" the values)?

The solution to this was counter-intuitive:

//targetURL As String, fileAttachment As Byte(), fileName As String, fileExtension As String
//you don't send the data to the webapi action. You WRITE to it like it's a file        
Using client = New WebClient()
    Try
        client.Headers.Add("Content-Type", "application/octet-stream")
        Using requestStream As Stream = client.OpenWrite(New Uri(targetURL), "POST")
            requestStream.Write(fileAttachment, 0, fileAttachment.Length)
        End Using    
    Catch ex As WebException
        If ex.Status = WebExceptionStatus.ProtocolError Then
            Dim wbrsp As HttpWebResponse = CType(ex.Response, HttpWebResponse)
            Throw New HttpException(CInt(wbrsp.StatusCode), wbrsp.StatusDescription)
        Else
            Throw New HttpException(500, ex.Message, New Exception("File upload failed."))
        End If
    End Try
End Using

And the magic code for the WebAPI:

byte[] values = await Request.Content.ReadAsByteArrayAsync(); 

You don't think of sending data to a URL the way you'd write to a file because you just don't do things that way but it works and the byte stream is not converted into a string anywhere in the process (which keeps the stream from being "corrupted" if the source isn't plain ascii.

Of course the big problem with this is that no matter how you set up the WebAPI action to return data, the OpenWrite method doesn't return anything. So all you can do is throw an exception if something borks. If you need data returned, you'll simply have to write another action to retrieve data created from your first call (in this case, a unique id for the file uploaded and saved).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM