9

Mar

Compressione in WCF

Ciao a tutti

posto un po di codice d'esempio per realizzare un extension per comprimere la comunicazione in WCF

cosa molto molto utile :)

 [code language="csharp"]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.IO;
using System.IO.Compression;
using System.ServiceModel.Channels;
using System.Xml;
using System.Diagnostics;
using System.ServiceModel;

namespace GzipEndpointBehavior
{
    #region PROGRAM

    class Program
    {
        static void Main(string[] args)
        {
            var h = new ServiceHost(typeof(Service1));
            h.Open();

            var c = new ChannelFactory("client").CreateChannel();


            Console.WriteLine(c.getBigString());

            Console.ReadLine();
        }
    }

    #endregion

    #region SERVICE

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string getBigString();
    }


    public class Service1 : IService1
    {
        public string getBigString()
        {
            return @"
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
                // NOTE: You can use the ""Rename"" command on the ""Refactor"" menu to change the class name ""Service1"" in both code and config file together.
            ".Trim();
        }
    }


    #endregion

    #region EXTENSIONS

    public class GzipEndpointBehavior : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(CompressorMessageInspector); }
        }

        protected override object CreateBehavior()
        {
            return new CompressorMessageInspector(CompressorMessageInspector.CompressionType.GZIP);
        }
    }

    public class DeflateEndpointBehavior : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(CompressorMessageInspector); }
        }

        protected override object CreateBehavior()
        {
            return new CompressorMessageInspector(CompressorMessageInspector.CompressionType.DEFLATE);
        }
    }

    #endregion

    internal class CompressorMessageInspector : IEndpointBehavior, IClientMessageInspector, IDispatchMessageInspector
    {
        public enum CompressionType
        {
            GZIP,
            DEFLATE
        }

        private CompressionType Mode;
        public CompressorMessageInspector(CompressionType mode) { Mode = mode; }

        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new CompressorMessageInspector(Mode));
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CompressorMessageInspector(Mode));
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            //client: response by server
            var body = reply.GetBody();
            reply = ReadMessage(Decompress(body), reply.Version);
        }

        public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
        {
            //client: requesting to server
            var body = Compress(WriteMessage(request));
            request = Message.CreateMessage(request.Version, request.Headers.Action, body);
            return null;
        }

        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            //server received request
            var body = request.GetBody();
            request = ReadMessage(Decompress(body), request.Version);
            return null;
        }

        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            //server response
            var body = Compress(WriteMessage(reply));
            reply = Message.CreateMessage(reply.Version, reply.Headers.Action, body);
        }

        private Stream NewCompressionStream(Stream m, CompressionMode mode)
        {
            switch (Mode)
            {
                case CompressionType.GZIP:
                    return new GZipStream(m, mode);
                case CompressionType.DEFLATE:
                    return new DeflateStream(m, mode);
                default:
                    throw new ArgumentException("Mode unknow");
            }
        }

        protected virtual byte[] Compress(byte[] arg)
        {
            using (var m = new MemoryStream())
            {
                using (var g = NewCompressionStream(m, CompressionMode.Compress))
                {
                    g.Write(arg, 0, arg.Length);
                }
                Debug.WriteLine("{0} compression: -{1:P1}", Mode.ToString(), 1- (Convert.ToDecimal(m.ToArray().Length) / Convert.ToDecimal(arg.Length)));
                Debug.WriteLine("From {0:N2}KB to {1:N2}KB", Convert.ToDecimal(arg.Length) / 1024, Convert.ToDecimal(m.ToArray().Length) / 1024);
                return m.ToArray();
            }
        }

        protected virtual byte[] Decompress(byte[] arg)
        {
            using (var m = new MemoryStream(arg))
            {
                using (var g = NewCompressionStream(m, CompressionMode.Decompress))
                {
                    using (var w = new MemoryStream())
                    {
                        byte[] b = new byte[1024];
                        var i = g.Read(b, 0, 1024);
                        while(i>0)
                        {
                            w.Write(b,0,i);
                            i = g.Read(b, 0, 1024);
                        }
                        return w.ToArray();
                    }
                }
            }
        }

        protected byte[] WriteMessage(Message arg)
        {
            using (var m = new MemoryStream())
            {
                using (var x = XmlWriter.Create(m))
                {
                    arg.WriteMessage(x);
                }
                return m.ToArray();
            }
        }

        protected Message ReadMessage(byte[] arg, MessageVersion version)
        {
            var m = new MemoryStream(arg);
            var x = XmlReader.Create(m);
            return Message.CreateMessage(x, int.MaxValue, version);
        }
    }
}

[/code]

.config:

 [code language="csharp"]



 
   
     
       
         
       

     

     
       
         
         
       

     

   

   
     
        http://localhost/Service1" behaviorConfiguration="compression"
                  binding="wsHttpBinding" contract="GzipEndpointBehavior.IService1" />
     

   

   
     
       
         
         
       

     

   

   
                      address="http://localhost/Service1" binding="wsHttpBinding" contract="GzipEndpointBehavior.IService1" />
   


   
     
       
       
     

   

 

[/code]

 

buon lavoro :)

by Antonio Esposito on 3/9/2011