Posting Audio (byte array) to MVC.NET Web Api

12,201

Solution 1

I used a ByteArrayEntity instead of a StringEntity.

// ByteArrayEntity 

HttpPost request = new HttpPost(getString(R.string.server_url) + "SendMessage");
ByteArrayEntity be = new ByteArrayEntity(msg);
be.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded"));
request.setEntity(be);
HttpResponse response = client.execute(request);

On the server side, I used this web API code to get the byte array:

[HttpPost]
public async Task<string> SendMessage()
{
    byte[] arrBytes = await Request.Content.ReadAsByteArrayAsync();
    return "";
}

Solution 2

I just posted a question on Stack Overflow at Uploading/Downloading Byte Arrays with AngularJS and ASP.NET Web API that is relevant (in part) to your question here. You might want to read that post to set the context for my response. It is about sending and receiving byte[]’s via Web API. I have one issue with the approach, but it has to do with the JavaScript client incorrectly handling the server response.

I would make the following changes to your Server-Side code as follows:

public class PostParms
{
    public string ExtraInfo { get; set; }
}

public class MediaController : ApiController
{
    [HttpPost]// byte[] is sent in body and parms sent in url
    public string Post([FromBody] byte[] audioSource, PostParms parms)
    {
        byte[] bytes = audioSource;
        return "success";
    }
}

Read the post at http://byterot.blogspot.com/2012/04/aspnet-web-api-series-part-5.html

Use/add Byte Rot’s asynchronous version of the Media Formatter for byte[]’s.

I had to tweak the formatter as shown below for a newer version of ASP.NET.

using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace YOUR_NAMESPACE
{
public class BinaryMediaTypeFormatter : MediaTypeFormatter
{
    /****************** Asynchronous Version ************************/

    private static Type _supportedType = typeof(byte[]);
    private bool _isAsync = true;
    public BinaryMediaTypeFormatter() : this(false){
    }
    public BinaryMediaTypeFormatter(bool isAsync) {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream"));
        IsAsync = isAsync;
    }
    public bool IsAsync {
        get { return _isAsync; }
        set { _isAsync = value; }
    }
    public override bool CanReadType(Type type){
        return type == _supportedType;
    }
    public override bool CanWriteType(Type type){
        return type == _supportedType;
    }
    public override Task<object> ReadFromStreamAsync(Type type, Stream stream,
        HttpContent contentHeaders, IFormatterLogger formatterLogger){// Changed to HttpContent
        Task<object> readTask = GetReadTask(stream);
        if (_isAsync){
            readTask.Start();
        }
        else{
            readTask.RunSynchronously();
        }
        return readTask;
    }
    private Task<object> GetReadTask(Stream stream){
        return new Task<object>(() =>{
            var ms = new MemoryStream();
            stream.CopyTo(ms);
            return ms.ToArray();
        });
    }
    private Task GetWriteTask(Stream stream, byte[] data){
        return new Task(() => {
            var ms = new MemoryStream(data);
            ms.CopyTo(stream);
        });
    }
    public override Task WriteToStreamAsync(Type type, object value, Stream stream,
        HttpContent contentHeaders, TransportContext transportContext){ // Changed to HttpContent
        if (value == null)
            value = new byte[0];
        Task writeTask = GetWriteTask(stream, (byte[])value);
        if (_isAsync){
            writeTask.Start();
        }
        else{
            writeTask.RunSynchronously();
        }
        return writeTask;
    }
}
}

I also had to add the following line to the config file.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
     // This line added to activate your binary formatter.
        config.Formatters.Add(new BinaryMediaTypeFormatter());

/*********************************** Client-Code *************************************/

You will need to use 'Content-Type': 'application/octet-stream' on the client.

You can send the byte[] as binary, but it has been too long since I have coded in C# on the client.

I think that the line: output.writeBytes(URLEncoder.encode(json.toString(),"UTF-8")); will have to be changed as a minimum.

I will have a look and see if I can find some C# client code snippets that might be relevant.

Edit You might have a look at the C# client code of the following post. It may help you to tweak your code to work with the approach that I suggested.

How to Get byte array properly from an Web Api Method in C#?

Share:
12,201

Related videos on Youtube

Chase Caillet
Author by

Chase Caillet

Updated on June 04, 2022

Comments

  • Chase Caillet
    Chase Caillet almost 2 years

    The Problem

    I am trying to send audio recorded by my android device to a MVC.NET Web Api. I confirmed the connection by passing simple string parameters. However, when I try to pass the byte array generated from the audio, I get a 500 from the server every time. I have tried multiple configurations, but here's what I currently have:

    MVC Web API

    public class PostParms
    {
        public string AudioSource { get; set; }
        public string ExtraInfo { get; set; }
    }
    
    public class MediaController : ApiController
    {
        [HttpPost]
        public string Post([FromBody]PostParms parms)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(parms.AudioSource);
            return "success";
        }
    }
    

    Android Code

    public class WebServiceTask extends AsyncTask<String, Void, Long>
    {   
        @Override
        protected Long doInBackground(String... parms)
        {
            long totalsize = 0;
            String filepath = parms[0];
            byte[] fileByte = convertAudioFileToByte(new File(filepath));        
    
            //Tried base64 below with Convert.FromBase64 on the C# side
            //String bytesstring = Base64.encodeToString(fileByte, Base64.DEFAULT);
    
            String bytesstring = "";
            try 
            {
                String t = new String(fileByte,"UTF-8");
        bytesstring = t;
            } catch (UnsupportedEncodingException e1)
            {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            }
    
            URL url;
            HttpURLConnection urlConnection = null;
            try {
                url = new URL("http://my.webservice.com:8185/api/media");
    
                //setup for connection
                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setUseCaches(false);
                urlConnection.setRequestMethod("POST");
                urlConnection.setDoOutput(true);
                urlConnection.setRequestProperty("Content-Type","application/json");
                urlConnection.setRequestProperty("Accept","application/json");
                urlConnection.connect();
    
                JSONObject json = new JSONObject();
                json.put("AudioSource", bytesstring);
                json.put("ExtraInfo", "none");
    
                DataOutputStream output = new DataOutputStream(urlConnection.getOutputStream());
                output.writeBytes(URLEncoder.encode(json.toString(),"UTF-8"));
                output.flush();
                output.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            finally {
                urlConnection.disconnect();
            }
            return totalsize;
        }
    
        protected void onPreExecute(){
    
        }
        protected void onPostExecute(){
    
        }
        private byte[] convertAudioFileToByte(File file) {
            byte[] bFile = new byte[(int) file.length()];
    
            try {
                // convert file into array of bytes
                FileInputStream fileInputStream = new FileInputStream(file);
                fileInputStream.read(bFile);
                fileInputStream.close();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return bFile;
        }
    }
    

    I can get a .NET application to work with the same API sending an audio stream, but not Android. Like I said, I've tried a number of configurations found on the internet with encoding and the output stream, but continue to get 500. I need help, as I am at a loss.

    Thanks in advance

  • alireza amini
    alireza amini over 8 years
    Worked For Me Thanks !!