My team uses Google grpc communication for micro service communication. I came across protobuf-net that is fast, reduces code complexity and no .proto file to be defined. I wanted to give a try using protobuf-net to see if we gain considerable performance improvement. However, I am getting error "specified method is not supported". I think I am not able to mark the entity correctly. I can use @marc-gravel help to understand the problem. Here are the details of my dotnet code
[ProtoContract]
public class ProtoBufInput
{
[ProtoMember(1)]
public string Id { get; set; }
[ProtoMember(2)]
public Building BuildingObj { get; set; }
[ProtoMember(3)]
public byte[] Payload { get; set; }
public ProtoBufInput(string id, Building buildingObj, byte[] payload)
{
BuildingObj = buildingObj;
Id = id;
Payload = payload;
}
}
[ProtoContract]
public class ProtoBufResult
{
[ProtoMember(1)]
public int RandomNumber { get; set; }
[ProtoMember(2)]
public bool RandomBool { get; set; }
[ProtoMember(3)]
public IList<string> ErrorMessages { get; set; }
[ProtoMember(5)]
public Building BuildingObj { get; set; }
[ProtoMember(6)]
public string RandomString { get; set; }
public ProtoBufResult()
{
RandomNumber = 0;
RandomBool = false;
}
}
[ProtoContract]
public class Building : Component<BuildingMetadata>
{
[ProtoMember(1)]
public string Id { get; set; }
[ProtoMember(2)]
public string tag { get; set; }
}
[ProtoContract]
public class BuildingMetadata : ComponentMetadata
{
[ProtoMember(1)]
public BuildingType Type { get; set; }
[ProtoMember(2)]
public bool IsAttached { get; set; }
public override object Clone()
{
var baseClone = base.Clone() as ComponentMetadata;
return new BuildingMetadata()
{
Model = baseClone.Model,
PropertyMetadata = baseClone.PropertyMetadata,
};
}
}
[ProtoContract]
public enum BuildingType
{
}
[ProtoContract]
public class ComponentMetadata : ICloneable
{
[ProtoMember(1)]
public string Model { get; set; }
[ProtoMember(2)]
public IDictionary<string, PropertyMetadata> PropertyMetadata { get; set; } = new Dictionary<string, PropertyMetadata>();
public virtual object Clone()
{
return new ComponentMetadata()
{
Model = Model,
PropertyMetadata = PropertyMetadata.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Clone() as PropertyMetadata),
};
}
}
[ProtoContract]
public class PropertyMetadata : ICloneable
{
[ProtoMember(1)]
[JsonProperty("Value")]
public JToken Value { get; set; }
[ProtoMember(2)]
[JsonProperty("Version")]
public int Version { get; set; }
[ProtoMember(3)]
[JsonProperty("backVersion")]
public int BackVersion { get; set; }
[ProtoMember(4)]
[JsonProperty("backCode")]
public int BackCode { get; set; }
[ProtoMember(5)]
[JsonProperty("Description")]
public string Description { get; set; }
[ProtoMember(6)]
[JsonProperty("createTime")]
public string CreateTime { get; set; }
public object Clone()
{
return new PropertyMetadata()
{
CreateTime = CreateTime ?? DateTime.UtcNow.ToString("o"),
};
}
}
[ProtoContract]
[ProtoInclude(1, typeof(Component<ComponentMetadata>))]
public class Component<TMetadataType> : ComponentBase, IComponent where TMetadataType : ComponentMetadata, new()
{
[ProtoMember(1)]
public TMetadataType Metadata { get; set; } = new TMetadataType();
public string Model => Metadata.Model;
public IEnumerable<(string, IComponent)> ListComponents() => Components.Select(x => (x.Key, x.Value as IComponent));
public IEnumerable<(string, JToken)> ListProperties() => Properties.Select(x => (x.Key, x.Value));
public ComponentMetadata GetMetadata() => Metadata;
public bool TryGetComponent(string name, out IComponent component)
{
component = null;
if (!Components.TryGetValue(name, out var innerComponent))
{
return false;
}
component = innerComponent as IComponent;
return true;
}
public bool TryGetProperty(string name, out JToken property) => Properties.TryGetValue(name, out property);
}
[ProtoContract]
public class ComponentBase
{
[ProtoMember(1)]
public IDictionary<string, JToken> Properties { get; set; } = new Dictionary<string, JToken>();
[ProtoMember(2)]
public IDictionary<string, InnerComponent> Components { get; set; } = new Dictionary<string, InnerComponent>();
}
[ProtoContract]
public class InnerComponent : Component<ComponentMetadata>
{
[ProtoMember(1)]
[JsonIgnore]
public string tag { get; set; }
}
Now coming to the service class and its implementation, I have something like this
[ServiceContract]
public interface IProtoBufService
{
[OperationContract]
public Task<ProtoBufResult> ProcessPb(ProtoBufInput input, CallContext context = default);
}
public class ProtoBufService : IProtoBufService
{
public Task<ProtoBufResult> ProcessPb(ProtoBufInput protoBufInput, CallContext context)
{
...
}
}
Rest of the configuration in start up file is correct like adding
serviceCollection.AddCodeFirstGrpc();
builder.MapGrpcService<Services.V2.ProtoBufService>();