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; }
    }
}
View Code
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()
            };
        }
    }
}
View Code
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");
        }
    }
}
View Code
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);
        }
    }
}
View Code

源码

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);
            }
        }
    }
View Code
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);
        }
    }
View Code

结果对比:

如下图ResponseSize优化前是优化后的5倍

 

 

 

 

注意:

  1. ProtoContract、ProtoMember 替换DataContract、DataMember
  2. 客户端和服务端需通过添加ProtoEndpointBehavior将wcf默认序列化DataContractSerializer替换为XmlProtoSerializer (具体实现查看源码)

    客户端:client.Endpoint.EndpointBehaviors.Add(new ProtoEndpointBehavior());

    服务端:host.Description.Endpoints[0].EndpointBehaviors.Add(new ProtoEndpointBehavior());

  3. Client需添加Lib.dll引用,若不添加,而使用生成代码的Chart,Chart的代码如下,此时客户端仍使用DataMemberAttribute,服务端使用ProtoMember 会导致反序列化失败,结果集为空。

 

posted @ 2020-02-12 16:04  vvf  阅读(188)  评论(0)    收藏  举报