Search code examples
c#arraysjsonbyte

Return a byte[] array from controller class in ASP.NET


I have a Controller class (in C#) which has to return a byte array from its login method. Please find the below source code of my Controller class for my Login functionality.

[RoutePrefix("Account")]
    public class AccountsController : ApiController     
    {
        [Route("Login")]
        [HttpPost]   
        public byte[] Login()
        {
            byte[] mSessionID = new Session().getmSessionID();
            return mSessionID;
        }
    }

While Testing, the web service returns a base64Encoded string value as "LVpgqWBYkyXX1FlDg95vlA==". I want my Web service to return a byte array response (which is in JSON response).


Solution

  • If you want to get the response in this format:

    {
      "Numbers": [
        2,
        3,
        4,
        5,
        6,
        7,
        8,
        9,
        10,
        1,
        11,
        12,
        13,
        14,
        15,
        2,
        45
      ]
    }
    

    Solution 1: JSON Formatters

    You need to modify the way that JSON is serialized. WebAPI uses JSON.Net unser the hood to format WebAPI responses as JSON. We can override the byte[] formatter as follows:

    Create a custom formatter

    public class ByteArrayFormatter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(byte[]);
        }
        public override bool CanRead
        {
            get
            {
                return false;
            }
        }
        public override bool CanWrite
        {
            get
            {
                return true;
            }
        }
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var byteArray = (byte[])value;
            writer.WriteStartArray();
            if (byteArray != null && byteArray.Length > 0)
            {
                foreach (var b in byteArray)
                {
                    writer.WriteValue(b);
                }
            }
            writer.WriteEndArray();
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    Register the formatter globally in the Application_Start method in Global.asax.cs (note that ALL byte[] types will be serialised this way):

    var formatters = GlobalConfiguration.Configuration.Formatters;
    var jsonFormatter = formatters.JsonFormatter;
    jsonFormatter.SerializerSettings.Converters.Add(new ByteArrayFormatter());
    

    Create a model so that your JSON response has a Numbers property:

    public class NumbersModelByte
    {
        public byte[] Numbers { get; set; }
    }
    

    Modify your controller to use this model:

    [Route("login")]
    [System.Web.Http.AcceptVerbs("GET")]
    [System.Web.Http.HttpGet]
    public NumbersModelByte Login()
    {
        byte[] mSessionID = new Session().getmSessionID();
        return new NumbersModelByte
        {
            Numbers = mSessionID
        };
    }
    

    Solution 2: The quick and dirty

    You will need to return an object (a model).

    NumbersModelInt.cs (notice the int[] type)

    public class NumbersModelInt
    {
        public int[] Numbers { get; set; }
    }
    

    Then you need to cast all of your bytes in your byte array to ints in the response:

    [Route("Login")]
    [HttpPost]   
    public byte[] Login()
    {
        byte[] mSessionID = new Session().getmSessionID();
        return new NumbersModelInt
        {
            Numbers = mSessionID.Select(b => (int) b).ToArray()
        };
    }