📜 ⬆️ ⬇️

Using Protocol Buffers on the .Net platform (Part 2)

In the first part, we met Protocol Buffers and tried to use them in the .Net application. Today we will continue to discuss and answer the remaining questions. As before, the reader should be fluent in the C # language and the SVN version control system for better mastering the material. It also does not hurt to have a general idea of ​​WCF, since there will be again (not) a lot of code, but already in the context of this technology!


Wait, but what we serialized on one platform can be deserialized on another?


Yes and no. Protobuf describes simple data types for which the answer is yes, but, unfortunately, there are data types for which the answer is negative. And our example proves it! Pay attention to type datetime . It is in itself a complex data type and, moreover, is platform dependent. Therefore, if we serialize it, then there is no guarantee that everything will be restored on another platform. Therefore, you need to come up with a way to eliminate this disadvantage. One of the solutions has already been implemented in protobuf-net and is as follows: the DateTime type is serialized as the time interval from 01-01-1970 (the starting point for unix systems). Conventions for the remaining types are here .

In order to protect yourself from such situations, it is recommended to use files with the .proto extension to describe your data structure (integration with Visual Studio is supported). This will help the source code generation program take into account the features of the final programming language and get a portable view of your structured data. In our case, we will have the following description (in the example, the type DateTime corresponds to its own data type based on this discussion ):
package Proto.Common;
message Task
{
optional int32 Id = 1;
optional DateTime CreatedAt = 2;
optional string CreatedBy = 3;
enum TaskPriority
{
Low = 0;
Medium = 1;
High = 2;
}
optional TaskPriority Priority = 4;
optional string Content = 5;
}

* This source code was highlighted with Source Code Highlighter .

Because the generated code is quite large and is not intended for manual editing, we omit it.
')

I noticed in the list of supported Javascript languages, is it worth refusing JSON in favor of protobuf?


Definitely not. JSON has built-in support in every browser and you do not need to upload the script to serialize it and deserialize it to the client. If you are experiencing problems with the amount of data, try, for example, enable compression. However, this implementation will definitely come in handy if you are developing using server-side Javascript, for example, in NodeJS .

Where else can i use protobuf besides the example described above?


As a .Net developer, you will find in protobuf-net support for platforms such as Silverlight, Compact Framework, Mono, and others. Let's see how to easily integrate protobuf into WCF. Let's start traditionally with the description of our entity (nothing has changed for the TaskPriority):
using System;
using System.Runtime.Serialization;

namespace Proto.Common
{
[DataContract]
public class Task
{
[DataMember(Order = 1)]
public int Id { get ; set ; }

[DataMember(Order = 2)]
public DateTime CreatedAt { get ; set ; }

[DataMember(Order = 3)]
public string CreatedBy { get ; set ; }

[DataMember(Order = 4)]
public TaskPriority Priority { get ; set ; }

[DataMember(Order = 5)]
public string Content { get ; set ; }
}
}


* This source code was highlighted with Source Code Highlighter .

As you can see, it differs little from the previously given description. But honestly, it does not look like an example of using protobuf! Service Contract:
using System.ServiceModel;

namespace Proto.Common
{
[ServiceContract]
public interface ITaskManager
{
[OperationContract]
Task[] GetTasks();
}
}


* This source code was highlighted with Source Code Highlighter .

Again, no hint of protobuf. The only place to mention is the service configuration file:
<? xml version ="1.0" ? >
< configuration >
< system.serviceModel >
< services >
< service name ="Proto.Server.TaskManager"
behaviorConfiguration ="Proto.Server.ServiceBehavior" >
<!-- Service Endpoints -->
< endpoint name ="Proto.Server.Endpoint"
address ="net.tcp:\\localhost:9000"
binding ="netTcpBinding"
contract ="Proto.Common.ITaskManager"
behaviorConfiguration ="Proto.Common.EndpointBehavior" />
</ service >
</ services >
< behaviors >
< serviceBehaviors >
< behavior name ="Proto.Server.ServiceBehavior" >
<!-- To receive exception details in faults for debugging purposes, set the value below to true.
Set to false before deployment to avoid disclosing exception information -->
< serviceDebug includeExceptionDetailInFaults ="true" />
</ behavior >
</ serviceBehaviors >
< endpointBehaviors >
< behavior name ="Proto.Common.EndpointBehavior" >
< protobuf />
</ behavior >
</ endpointBehaviors >
</ behaviors >
< extensions >
< behaviorExtensions >
< add name ="protobuf"
type ="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=1.0.0.280, Culture=neutral, PublicKeyToken=257b51d87d2e4d67" />
</ behaviorExtensions >
</ extensions >
</ system.serviceModel >
</ configuration >


* This source code was highlighted with Source Code Highlighter .

And customer:
<? xml version ="1.0" ? >
< configuration >
< system.serviceModel >
< client >
< endpoint name ="Proto.Client.Endpoint"
address ="net.tcp:\\localhost:9000"
binding ="netTcpBinding"
contract ="Proto.Common.ITaskManager"
behaviorConfiguration ="Proto.Common.EndpointBehavior" />
</ client >
< behaviors >
< endpointBehaviors >
< behavior name ="Proto.Common.EndpointBehavior" >
< protobuf />
</ behavior >
</ endpointBehaviors >
</ behaviors >
< extensions >
< behaviorExtensions >
< add name ="protobuf"
type ="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=1.0.0.280, Culture=neutral, PublicKeyToken=257b51d87d2e4d67" />
</ behaviorExtensions >
</ extensions >
</ system.serviceModel >
</ configuration >


* This source code was highlighted with Source Code Highlighter .

The implementation of the client and the service is trivial and not of interest.

If you enable message logging, you can see the following entry in the log:
< MessageLogTraceRecord Time ="2011-05-12T16:17:03.2780000+04:00" Source ="TransportSend" Type ="System.ServiceModel.Dispatcher.OperationFormatter+OperationFormatterMessage" xmlns ="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace" >
< s:Envelope xmlns:s ="http://www.w3.org/2003/05/soap-envelope" xmlns:a ="http://www.w3.org/2005/08/addressing" >
< s:Header >
< a:Action s:mustUnderstand ="1" >
tempuri.org/ITaskManager/GetTasksResponse
</ a:Action >
< a:RelatesTo >
urn:uuid:768e2f40-612c-4593-8cfb-eacb7b291a9c
</ a:RelatesTo >
< a:To s:mustUnderstand ="1" >
www.w3.org/2005/08/addressing/anonymous
</ a:To >
</ s:Header >
< s:Body >
< GetTasksResponse xmlns ="http://tempuri.org/" >
< proto >
Ci4IARIJCPTs+c/8SxAEGgpTdGV2ZSBKb2JzIAIqEUludmVudCBuZXcgaVBob25lCi8IAhIJCPTclY/4SxAEGg1TdGV2ZSBCYWxsbWVyKhFJbnN0YWxsIG93biBTa3lwZQ==
</ proto >
</ GetTasksResponse >
</ s:Body >
</ s:Envelope >
</ MessageLogTraceRecord >

* This source code was highlighted with Source Code Highlighter .


As far as I remember, the use of data contracts is not limited to attributes, what about the expansion of these contracts?


Exactly as in WCF. You know that you can accommodate contract changes with the IExtensibleDataObject . Protobuf-net has a similar interface and is called IExtensible. The difference is not so big, so you can study it yourself here .

Why many developers refuse to use protobuf-net in WCF?


This is nothing more than a myth. It's just that developers usually find protobuf when they are looking for solutions to speed up their network sharing. Some of them go further and remove the levels of abstraction imposed by WCF and use, for example, TcpClient for maximum speed. If this is your case, then you may find Thrift more useful.

You convinced me. Be sure to try protobuf-net in the next project. Thanks for the discussion!


You are welcome. The project is actively developing, so perhaps we will discuss it more than once.

Source: https://habr.com/ru/post/119510/


All Articles