MessagePack (.Net, c#)

MessagePack (.Net, c#)

Exploring through various ways to make communication between distributed system, I landed on serialising, deserialising and the content-type that travels over http to reach from source system to destination incase of using WebAPI for communication which is the most preferred way nowadays.

These things play an important role in communication and i think somehow relates to gRPC introduced by Google and looks like the future for inter system communication like how Microservices communicate with each other because conventional ways of doing so is lame.

Although data that travels over http is preferred to be on text format because it is easy to debug and consume as well, However if both parties(system) are supported to do some unconventional things apart from JSON/Text then there are options like MessagePack which are magically fast for serialisation, deserialisation and reduces content size to travel. I will be describing the ways to implement this over WEBAPI using standard MediaType Formatter.

First thing we need to do is install MessagePack:

Install-Package MessagePack

Now we need to create a Media Formatter so that WebAPI automatically takes input on x-msgpack format and gives response on x-msgpack format respectively.

   public class MessageFormatter:MediaTypeFormatter {
        public MessageFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/x-msgpack"));
        }

        public override bool CanReadType(Type type)
        {
            return true;
        }

        public override bool CanWriteType(Type type)
        {
            return true;
        }

        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            if (writeStream == null)
            {
                throw new ArgumentNullException(nameof(writeStream));
            }

            MessagePackSerializer.NonGeneric.Serialize(type, writeStream, value, ContractlessStandardResolver.Instance);
            return Task.FromResult(0);
        }
        public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            if (readStream == null)
            {
                throw new ArgumentNullException(nameof(readStream));
            }

            var value = MessagePackSerializer.NonGeneric.Deserialize(type, readStream, ContractlessStandardResolver.Instance);
            return Task.FromResult(value);
        }
    }

Now that we have created a Mediaformatter, lets register it inside Register method of WebApiConfig:

config.Formatters.Add(new MessageFormatter());

Now lets create an object that will be used to test above code:

   [MessagePackObject]
    public class Response_Base<T>
    {
        [Key(0)]
        public bool isSuccess { get; set; }
        [Key(1)]
        public string message { get; set; }
        [Key(2)]
        public T data { get; set; }
    }
    [MessagePackObject]
   public class test
    {
        [Key(0)]
        public object MyProperty { get; set; }
    }

If you see above there are some key attributes somehow similar to WCF which play important role in MessagePack world.Below is the Controller Action to call another Action in same controller:

 public void Get()
        {
            var response = new Response_Base<List<test>>();
            response.data = Enumerable.Range(1, 10).Select(x => new test() { MyProperty = x }).ToList();
            var requestdata= MessagePack.MessagePackSerializer.Serialize(response);
            var client = new RestClient("http://127.0.0.1:8080/api/home/");
            client.Timeout = -1;
            var request = new RestRequest(Method.PUT);
            request.AddHeader("Content-Type", "application/x-msgpack");
            request.AddHeader("Accept", "application/x-msgpack");
            request.AddParameter("application/x-msgpack", requestdata, ParameterType.RequestBody);
            IRestResponse resp = client.Execute(request);
            Console.WriteLine(resp.Content);
        }

And here is the one which is being called:

public Response_Base<List<test>> Put(Response_Base<List<test>> request) {
            return request;
        }

Now when request lands on Put, the data must be deserialised because of MediaType formatter. Similarly response must be auto serialised because of MediaType formatter and to use that response on receiving end, we must deserialise it into proper format.