wcf 优化
一、序列化问题
当时ws标准的流行(xml标签对,效率低),当时针对内网解决信息孤岛问题,没有考虑带宽
使用protobuf 序列化编码器进行优化
全称Protocol Buffers 谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。
单独的一套编码规则(不是xml,不是json)
namespace Lib { //[DataContract] //public class Chart //{ // [DataMember] // public string ChartName { get; set; } // [DataMember] // public List<Point> Points { get; set; } //} //[DataContract] //public class Point //{ // [DataMember] // public DateTime PointTime { get; set; } // [DataMember] // public int TotalNum { get; set; } //} [ProtoContract] public class Chart { [ProtoMember(1)] public string ChartName { get; set; } [ProtoMember(2)] public List<Point> Points { get; set; } } [ProtoContract] public class Point { [ProtoMember(1)] public DateTime PointTime { get; set; } [ProtoMember(2)] public int TotalNum { get; set; } } }
namespace Lib { [ServiceContract] public interface IOptimizeService { [OperationContract] Chart Do(int i); } } namespace Lib { public class OptimizeService : IOptimizeService { public Chart Do(int i) { return new Chart() { ChartName = "", Points = Enumerable.Repeat(1, 100).Select(x => new Point { PointTime = DateTime.Now.AddDays(-x), TotalNum = x }).ToList() }; } } }
namespace Host05 { class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(Lib.OptimizeService))) { host.Description.Endpoints[0].EndpointBehaviors.Add(new ProtoEndpointBehavior()); host.Opened += Host_Opened; host.Open(); Console.ReadKey(); } } private static void Host_Opened(object sender, EventArgs e) { Console.WriteLine("opened"); } } }
namespace Client05 { class Program { static void Main(string[] args) { ServiceReference1.OptimizeServiceClient client = new ServiceReference1.OptimizeServiceClient(); client.Endpoint.EndpointBehaviors.Add(new ProtoEndpointBehavior()); Lib.Chart cahr = client.Do(1); } } }
源码
public class ProtoEndpointBehavior : IEndpointBehavior { void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { ReplaceDataContractSerializerOperationBehavior(endpoint); } void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { ReplaceDataContractSerializerOperationBehavior(endpoint); } void IEndpointBehavior.Validate(ServiceEndpoint endpoint) { } private static void ReplaceDataContractSerializerOperationBehavior(ServiceEndpoint serviceEndpoint) { foreach (OperationDescription operation in serviceEndpoint.Contract.Operations) { ReplaceDataContractSerializerOperationBehavior(operation); } } private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description) { DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>(); if (dataContractSerializerOperationBehavior != null) { description.Behaviors.Remove(dataContractSerializerOperationBehavior); ProtoOperationBehavior protoOperationBehavior = new ProtoOperationBehavior(description); protoOperationBehavior.MaxItemsInObjectGraph = dataContractSerializerOperationBehavior.MaxItemsInObjectGraph; description.Behaviors.Add(protoOperationBehavior); } } }
public sealed class ProtoOperationBehavior : DataContractSerializerOperationBehavior { private TypeModel model; /// <summary> /// The type-model that should be used with this behaviour /// </summary> public TypeModel Model { get { return model; } set { if (value == null) { throw new ArgumentNullException("value"); } model = value; } } /// <summary> /// Create a new ProtoOperationBehavior instance /// </summary> public ProtoOperationBehavior(OperationDescription operation) : base(operation) { model = RuntimeTypeModel.Default; } /// <summary> /// Creates a protobuf serializer if possible (falling back to the default WCF serializer) /// </summary> public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes) { if (model == null) { throw new InvalidOperationException("No Model instance has been assigned to the ProtoOperationBehavior"); } return XmlProtoSerializer.TryCreate(model, type) ?? base.CreateSerializer(type, name, ns, knownTypes); } }
结果对比:
如下图ResponseSize优化前是优化后的5倍


注意:
- ProtoContract、ProtoMember 替换DataContract、DataMember
- 客户端和服务端需通过添加ProtoEndpointBehavior将wcf默认序列化DataContractSerializer替换为XmlProtoSerializer (具体实现查看源码)
客户端:client.Endpoint.EndpointBehaviors.Add(new ProtoEndpointBehavior());
服务端:host.Description.Endpoints[0].EndpointBehaviors.Add(new ProtoEndpointBehavior());
- Client需添加Lib.dll引用,若不添加,而使用生成代码的Chart,Chart的代码如下,此时客户端仍使用DataMemberAttribute,服务端使用ProtoMember 会导致反序列化失败,结果集为空。
![]()
![]()



浙公网安备 33010602011771号