C# Лучший способ передачи данных Serialized Protobuff через http

Я использую Protobub-Net от Marc Gravell для сериализации и десериализации объектов.

Я ищу наиболее эффективный способ передачи данных через http:// запрос.

Вот что я сделал до сих пор:

public string ProtobuffToString()
{
    Dictionary<int, decimal> List1 = new Dictionary<int, decimal>();
    List1.Add(2018, 1.2m);
    List1.Add(2017, 1.4m);
    List1.Add(2016, 1.9m);

    using (var stream = new MemoryStream())
    {
         ProtoBuf.Serializer.Serialize(stream, List1);
        return Convert.ToBase64String(stream.ToArray());
    }
}

public async System.Threading.Tasks.Task<string> ReadProtobuffAsync()
{
    using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
    using (System.Net.Http.HttpResponseMessage response = await client.GetAsync("http://localhost:53204/ProtobuffToString")) //<= Will call ProtobuffToString() above
    using (System.Net.Http.HttpContent content = response.Content)
    {
        string result = await content.ReadAsStringAsync();
        byte[] resultByte = Convert.FromBase64String(result);

        using (var stream = new MemoryStream(resultByte))
        {
            return JsonConvert.SerializeObject(ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(stream));
        }
    }
}

Могу ли я сделать это лучше?

И это лучше / быстрее, чем перенести его из json/Json.Net?

Возможно, да, потому что передача данных будет меньше, а сериализация / десериализация быстрее.

2 ответа

Решение

Могу ли я сделать это лучше?

Protobuf - это двоичный формат сериализации, который оптимизирован для (де) сериализации и передачи с минимальным размером. Преобразуя данные в Base64, вы добавляете еще один слой преобразования и увеличиваете объем передаваемых данных.

И это лучше / быстрее, чем перенести его из json/Json.Net?

Нет разумных аргументов в поддержку этого утверждения. Повторяя мое предыдущее утверждение, Protobuf высоко оптимизирован, в то время как JSON является своего рода компромиссом, который не очень эффективен для сериализации и не очень хорошо читается.

Сказав это, приведите небольшой пример, как отправить ваш Protobuf через HTTP

HttpClient client = new HttpClient();
using (var stream = new MemoryStream())
{
    // serialize to stream
    ProtoBuf.Serializer.Serialize(stream, List1);
    stream.Seek(0, SeekOrigin.Begin);

    // send data via HTTP
    StreamContent streamContent = new StreamContent(stream);
    streamContent.Headers.Add("Content-Type", "application/octet-stream");
    var response = client.PostAsync("http://what.ever/api/upload", streamContent);
}

Если вы хотите получить Protobuf, вы можете изменить свой фрагмент кода следующим образом

using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
using (System.Net.Http.HttpResponseMessage response = await client.GetAsync("http://localhost:53204/ProtobuffToString")) //<= Will call ProtobuffToString() above
using (System.Net.Http.HttpContent content = response.Content)
using (var memoryStream = new MemoryStream())
{
    await content.CopyToAsync(memoryStream);
    memoryStream.Seek(0, SeekOrigin.Begin); // reset stream

    return ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(memoryStream); // assuming that you return the Dictionary, not a string
}

На самом деле я не понимаю, почему вы хотели вернуть string вместо Dictionary<int, decimal> от ReadProtobuffAsync, Я бы рекомендовал бросить Dictionary в целом и используйте значимые определения protobuf и соответствующие классы, потому что это действительно сильная сторона Protobuf.

Вопрос и ответы субъективны и основаны исключительно на определении "лучший". Я вижу много "лишнего" кода, который не нужен. Я рекомендую вам работать непосредственно с Streams, нет необходимости сначала переходить к потоку памяти или конвертировать в base64 или конвертировать в json. Если вам нужно строковое представление, сделайте это в другом служебном методе, а не оборачивайте его в этот код.

Написать код

// depending on where you want to write to pass an appropriate Stream like a stream to write directly to an HttpPost or File on disk,
// there is no need to write to memory
public void SerializeToStream(Stream destinationStream)
{
    Dictionary<int, decimal> List1 = new Dictionary<int, decimal>();
    List1.Add(2018, 1.2m);
    List1.Add(2017, 1.4m);
    List1.Add(2016, 1.9m);

    ProtoBuf.Serializer.Serialize(destinationStream, List1);
}

Читать код

public async System.Threading.Tasks.Task<Dictionary<int, decimal>> ReadProtobuffAsync()
{
    using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
    using (System.IO.Stream responseStream = await client.GetStreamAsync("http://localhost:53204/ProtobuffToString"))
    {
        // deserialize directly from the response stream
        return ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(responseStream));
    }
}
Другие вопросы по тегам