Aracılığıyla paylaş


Özel İleti Kodlayıcı: Sıkıştırma Kodlayıcısı

Sıkıştırma örneği, Windows Communication Foundation (WCF) platformunu kullanarak özel kodlayıcı uygulamayı gösterir.

Örnek Ayrıntılar

Bu örnek bir istemci konsol programından (.exe), şirket içinde barındırılan bir hizmet konsolu programından (.exe) ve bir sıkıştırma iletisi kodlayıcı kitaplığından (.dll) oluşur. Hizmet, istek-yanıt iletişim desenini tanımlayan bir sözleşme uygular. Sözleşme, temel dize yankılama işlemlerini (Echo ve BigEcho) kullanıma sunan arabirimi tarafından ISampleServer tanımlanır. İstemci belirli bir işleme zaman uyumlu istekler yapar ve hizmet, iletiyi istemciye geri yineleyerek yanıtlar. İstemci ve hizmet etkinliği konsol pencerelerinde görünür. Bu örneğin amacı, özel kodlayıcı yazmayı göstermek ve iletinin kablo üzerindeki sıkıştırma etkisini göstermektir. İleti boyutunu, işlem süresini veya her ikisini hesaplamak için sıkıştırma iletisi kodlayıcıya izleme ekleyebilirsiniz.

Not

.NET Framework 4'te, sunucu sıkıştırılmış yanıt gönderiyorsa (GZip veya Deflate gibi bir algoritmayla oluşturulmuş) wcf istemcisinde otomatik sıkıştırma etkinleştirilmiştir. Hizmet Internet Information Server'da (IIS) Web'de barındırılıyorsa IIS, hizmetin sıkıştırılmış yanıt göndermesi için yapılandırılabilir. Bu örnek, gereksinim hem istemcide hem de hizmette sıkıştırma ve açma işlemi yapmaksa veya hizmet şirket içinde barındırılıyorsa kullanılabilir.

Örnek, özel ileti kodlayıcı oluşturma ve wcf uygulamasıyla tümleştirmeyi gösterir. Kitaplık GZipEncoder.dll hem istemci hem de hizmet ile dağıtılır. Bu örnek, iletileri sıkıştırmanın etkisini de gösterir. GZipEncoder.dll'daki kod aşağıdakileri gösterir:

  • Özel kodlayıcı ve kodlayıcı fabrikası oluşturma.

  • Özel kodlayıcı için bağlama öğesi geliştirme.

  • Özel bağlama öğelerini tümleştirmek için özel bağlama yapılandırmasını kullanma.

  • Özel bağlama öğesinin dosya yapılandırmasına izin vermek için özel yapılandırma işleyicisi geliştirme.

Daha önce belirtildiği gibi, özel kodlayıcıda uygulanan birkaç katman vardır. Bu katmanların her biri arasındaki ilişkiyi daha iyi göstermek için, hizmet başlatma için basitleştirilmiş bir olay sırası aşağıdaki listededir:

  1. Sunucu başlatılır.

  2. Yapılandırma bilgileri okunur.

    1. Hizmet yapılandırması özel yapılandırma işleyicisini kaydeder.

    2. Hizmet konağı oluşturulur ve açılır.

    3. Özel yapılandırma öğesi, özel bağlama öğesini oluşturur ve döndürür.

    4. Özel bağlama öğesi bir ileti kodlayıcı fabrikası oluşturur ve döndürür.

  3. Bir ileti alınır.

  4. İleti kodlayıcı fabrikası, iletide okumak ve yanıtı yazmak için bir ileti kodlayıcı döndürür.

  5. Kodlayıcı katmanı bir sınıf fabrikası olarak uygulanır. Özel kodlayıcı için yalnızca kodlayıcı sınıf fabrikasının genel kullanıma açık olması gerekir. veya ChannelFactory<TChannel> nesnesi oluşturulduğunda fabrika nesnesi bağlama öğesi ServiceHost tarafından döndürülür. İleti kodlayıcıları arabelleğe alınan veya akış modunda çalışabilir. Bu örnek hem arabelleğe alınan modu hem de akış modunu gösterir.

Her mod için soyut MessageEncoder sınıfta eşlik eden ReadMessage bir ve WriteMessage yöntemi vardır. Kodlama çalışmalarının çoğu bu yöntemlerde gerçekleşir. Örnek, var olan metin ve ikili ileti kodlayıcılarını sarmalar. Bu, örneğin iletilerin tel gösteriminin okunmasını ve yazılmasını iç kodlayıcıya devretmesine olanak tanır ve sıkıştırma kodlayıcının sonuçları sıkıştırmasına veya sıkıştırmasını açmasına olanak tanır. İleti kodlama için işlem hattı olmadığından, WCF'de birden çok kodlayıcı kullanmaya yönelik tek model budur. İletinin sıkıştırması kaldırıldıktan sonra, sonuçta elde edilen ileti işlenecek kanal yığını için yığına geçirilir. Sıkıştırma sırasında, sonuçta elde edilen sıkıştırılmış ileti doğrudan sağlanan akışa yazılır.

Bu örnek, sınıfını kullanmak GZipStream üzere arabelleklerden akışlara dönüştürme gerçekleştirmek için yardımcı yöntemleri (CompressBuffer ve DecompressBuffer) kullanır.

Arabelleğe alınan ReadMessage ve WriteMessage sınıfları sınıfını BufferManager kullanır. Kodlayıcıya yalnızca kodlayıcı fabrikası üzerinden erişilebilir. soyut MessageEncoderFactory sınıfı, geçerli kodlayıcıya erişmek için adlı Encoder bir özellik ve oturumları destekleyen bir kodlayıcı oluşturmak için adlı CreateSessionEncoder bir yöntem sağlar. Böyle bir kodlayıcı, kanalın oturumları desteklediği, sıralandığı ve güvenilir olduğu senaryoda kullanılabilir. Bu senaryo, kabloya yazılan verilerin her oturumunda iyileştirmeye olanak tanır. Bu istenmiyorsa, temel yöntem aşırı yüklenmemelidir. özelliği, Encoder oturumsuz kodlayıcıya erişmek için bir mekanizma sağlar ve yöntemin CreateSessionEncoder varsayılan uygulaması özelliğin değerini döndürür. Örnek sıkıştırma sağlamak için mevcut bir kodlayıcıyı sarmaladığı MessageEncoderFactory için, uygulama iç kodlayıcı fabrikasını temsil eden bir MessageEncoderFactory kabul eder.

Kodlayıcı ve kodlayıcı fabrikası tanımlandığına göre, bir WCF istemcisi ve hizmetiyle birlikte kullanılabilirler. Ancak, bu kodlayıcıların kanal yığınına eklenmesi gerekir. ve ChannelFactory<TChannel> sınıflarından ServiceHost sınıflar türetebilir ve bu kodlayıcı fabrikasını OnInitialize el ile eklemek için yöntemleri geçersiz kılabilirsiniz. Kodlayıcı fabrikasını özel bağlama öğesi aracılığıyla da kullanıma sunun.

Yeni bir özel bağlama öğesi oluşturmak için sınıfından bir sınıf türetin BindingElement . Bununla birlikte, birkaç bağlama öğesi türü vardır. Özel bağlama öğesinin bir ileti kodlama bağlama öğesi olarak tanındığından emin olmak için, uygulamasını MessageEncodingBindingElementda uygulamanız gerekir. , MessageEncodingBindingElement eşleşen ileti kodlayıcı fabrikasının bir örneğini döndürmek için uygulanan yeni bir ileti kodlayıcı fabrikası (CreateMessageEncoderFactory ) oluşturmak için bir yöntem sunar. Ayrıca, MessageEncodingBindingElement adresleme sürümünü belirtmek için bir özelliği vardır. Bu örnek mevcut kodlayıcıları sarmaladığı için, örnek uygulama ayrıca var olan kodlayıcı bağlama öğelerini sarmalar ve oluşturucuya parametre olarak bir iç kodlayıcı bağlama öğesi alır ve bunu bir özellik aracılığıyla kullanıma sunar. Aşağıdaki örnek kod, sınıfının uygulamasını GZipMessageEncodingBindingElement gösterir.

public sealed class GZipMessageEncodingBindingElement
                        : MessageEncodingBindingElement //BindingElement
                        , IPolicyExportExtension
{

    //We use an inner binding element to store information
    //required for the inner encoder.
    MessageEncodingBindingElement innerBindingElement;

        //By default, use the default text encoder as the inner encoder.
        public GZipMessageEncodingBindingElement()
            : this(new TextMessageEncodingBindingElement()) { }

    public GZipMessageEncodingBindingElement(MessageEncodingBindingElement messageEncoderBindingElement)
    {
        this.innerBindingElement = messageEncoderBindingElement;
    }

    public MessageEncodingBindingElement InnerMessageEncodingBindingElement
    {
        get { return innerBindingElement; }
        set { innerBindingElement = value; }
    }

    //Main entry point into the encoder binding element.
    // Called by WCF to get the factory that creates the
    //message encoder.
    public override MessageEncoderFactory CreateMessageEncoderFactory()
    {
        return new
GZipMessageEncoderFactory(innerBindingElement.CreateMessageEncoderFactory());
    }

    public override MessageVersion MessageVersion
    {
        get { return innerBindingElement.MessageVersion; }
        set { innerBindingElement.MessageVersion = value; }
    }

    public override BindingElement Clone()
    {
        return new
        GZipMessageEncodingBindingElement(this.innerBindingElement);
    }

    public override T GetProperty<T>(BindingContext context)
    {
        if (typeof(T) == typeof(XmlDictionaryReaderQuotas))
        {
            return innerBindingElement.GetProperty<T>(context);
        }
        else
        {
            return base.GetProperty<T>(context);
        }
    }

    public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        context.BindingParameters.Add(this);
        return context.BuildInnerChannelFactory<TChannel>();
    }

    public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        context.BindingParameters.Add(this);
        return context.BuildInnerChannelListener<TChannel>();
    }

    public override bool CanBuildChannelListener<TChannel>(BindingContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        context.BindingParameters.Add(this);
        return context.CanBuildInnerChannelListener<TChannel>();
    }

    void IPolicyExportExtension.ExportPolicy(MetadataExporter exporter, PolicyConversionContext policyContext)
    {
        if (policyContext == null)
        {
            throw new ArgumentNullException("policyContext");
        }
       XmlDocument document = new XmlDocument();
       policyContext.GetBindingAssertions().Add(document.CreateElement(
            GZipMessageEncodingPolicyConstants.GZipEncodingPrefix,
            GZipMessageEncodingPolicyConstants.GZipEncodingName,
            GZipMessageEncodingPolicyConstants.GZipEncodingNamespace));
    }
}

GZipMessageEncodingBindingElement Aşağıdaki örnekte gösterildiği gibi bu bağlama öğesinin IPolicyExportExtension meta verilerde ilke olarak dışarı aktarılabilmesi için sınıfın arabirimini uyguladığını unutmayın.

<wsp:Policy wsu:Id="BufferedHttpSampleServer_ISampleServer_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <gzip:text xmlns:gzip=
        "http://schemas.microsoft.com/ws/06/2004/mspolicy/netgzip1" />
       <wsaw:UsingAddressing />
     </wsp:All>
   </wsp:ExactlyOne>
</wsp:Policy>

GZipMessageEncodingBindingElementImporter sınıfı arabirimini IPolicyImportExtension uygular, bu sınıf için GZipMessageEncodingBindingElementilkeyi içeri aktarır. Svcutil.exe aracı, ilkeleri yapılandırma dosyasına aktarmak ve işlemek GZipMessageEncodingBindingElementiçin kullanılabilir. aşağıdakiler Svcutil.exe.config dosyasına eklenmelidir.

<configuration>
  <system.serviceModel>
    <extensions>
      <bindingElementExtensions>
        <add name="gzipMessageEncoding"
          type=
            "Microsoft.ServiceModel.Samples.GZipMessageEncodingElement, GZipEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </bindingElementExtensions>
    </extensions>
    <client>
      <metadata>
        <policyImporters>
          <remove type=
"System.ServiceModel.Channels.MessageEncodingBindingElementImporter, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
          <extension type=
"Microsoft.ServiceModel.Samples.GZipMessageEncodingBindingElementImporter, GZipEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </policyImporters>
      </metadata>
    </client>
  </system.serviceModel>
</configuration>

Sıkıştırma kodlayıcısı için eşleşen bir bağlama öğesi olduğuna göre, aşağıdaki örnek kodda gösterildiği gibi yeni bir özel bağlama nesnesi oluşturup özel bağlama öğesi eklenerek hizmete veya istemciye program aracılığıyla bağlanabilir.

ICollection<BindingElement> bindingElements = new List<BindingElement>();
HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
GZipMessageEncodingBindingElement compBindingElement = new GZipMessageEncodingBindingElement ();
bindingElements.Add(compBindingElement);
bindingElements.Add(httpBindingElement);
CustomBinding binding = new CustomBinding(bindingElements);
binding.Name = "SampleBinding";
binding.Namespace = "http://tempuri.org/bindings";

Bu, kullanıcı senaryolarının çoğu için yeterli olsa da, bir hizmetin Web'de barındırılması durumunda dosya yapılandırmasını desteklemek kritik önem taşır. Web'de barındırılan senaryoyu desteklemek için, özel bağlama öğesinin bir dosyada yapılandırılabilir olmasına izin verecek özel bir yapılandırma işleyicisi geliştirmeniz gerekir.

Yapılandırma sisteminin üzerinde bağlama öğesi için bir yapılandırma işleyicisi oluşturabilirsiniz. Bağlama öğesinin yapılandırma işleyicisi sınıfından BindingElementExtensionElement türetilmelidir. , BindingElementExtensionElement.BindingElementType yapılandırma sistemine bu bölüm için oluşturulacak bağlama öğesinin türünü bildirir. ayarlanabilen BindingElement tüm yönleri türetilmiş sınıfta özellik BindingElementExtensionElement olarak gösterilmelidir. Yapılandırma ConfigurationPropertyAttribute öğesi özniteliklerini özelliklere eşleme ve öznitelikler eksikse varsayılan değerleri ayarlama konusunda yardımcı olur. Yapılandırmadaki değerler yüklendikten ve özelliklere uygulandıktan sonra, BindingElementExtensionElement.CreateBindingElement özellikleri bağlama öğesinin somut bir örneğine dönüştüren yöntemi çağrılır. BindingElementExtensionElement.ApplyConfiguration yöntemi, türetilmiş sınıftaki BindingElementExtensionElement özellikleri yeni oluşturulan bağlama öğesinde ayarlanacak değerlere dönüştürmek için kullanılır.

Aşağıdaki örnek kod, uygulamasını GZipMessageEncodingElementgösterir.

public class GZipMessageEncodingElement : BindingElementExtensionElement
{
    public GZipMessageEncodingElement()
    {
    }

//Called by the WCF to discover the type of binding element this
//config section enables
    public override Type BindingElementType
    {
        get { return typeof(GZipMessageEncodingBindingElement); }
    }

    //The only property we need to configure for our binding element is
    //the type of inner encoder to use. Here, we support text and
    //binary.
    [ConfigurationProperty("innerMessageEncoding",
                         DefaultValue = "textMessageEncoding")]
    public string InnerMessageEncoding
    {
        get { return (string)base["innerMessageEncoding"]; }
        set { base["innerMessageEncoding"] = value; }
    }

    //Called by the WCF to apply the configuration settings (the
    //property above) to the binding element
    public override void ApplyConfiguration(BindingElement bindingElement)
    {
        GZipMessageEncodingBindingElement binding =
                (GZipMessageEncodingBindingElement)bindingElement;
        PropertyInformationCollection propertyInfo =
                    this.ElementInformation.Properties;
        if (propertyInfo["innerMessageEncoding"].ValueOrigin !=
                                     PropertyValueOrigin.Default)
        {
            switch (this.InnerMessageEncoding)
            {
                case "textMessageEncoding":
                    binding.InnerMessageEncodingBindingElement =
                      new TextMessageEncodingBindingElement();
                    break;
                case "binaryMessageEncoding":
                    binding.InnerMessageEncodingBindingElement =
                         new BinaryMessageEncodingBindingElement();
                    break;
            }
        }
    }

    //Called by the WCF to create the binding element
    protected override BindingElement CreateBindingElement()
    {
        GZipMessageEncodingBindingElement bindingElement =
                new GZipMessageEncodingBindingElement();
        this.ApplyConfiguration(bindingElement);
        return bindingElement;
    }
}

Bu yapılandırma işleyicisi, hizmet veya istemci için App.config veya Web.config dosyasında aşağıdaki gösterimle eşler.

<gzipMessageEncoding innerMessageEncoding="textMessageEncoding" />

Bu yapılandırma işleyicisini kullanmak için, aşağıdaki örnek yapılandırmada gösterildiği gibi system.serviceModel> öğesinde kayıtlı <olmalıdır.

<extensions>
    <bindingElementExtensions>
       <add
           name="gzipMessageEncoding"
           type=
           "Microsoft.ServiceModel.Samples.GZipMessageEncodingElement,
           GZipEncoder, Version=1.0.0.0, Culture=neutral,
           PublicKeyToken=null" />
      </bindingElementExtensions>
</extensions>

Sunucuyu çalıştırdığınızda, işlem istekleri ve yanıtları konsol penceresinde görüntülenir. Sunucuyu kapatmak için pencerede ENTER tuşuna basın.

Press Enter key to Exit.

        Server Echo(string input) called:
        Client message: Simple hello

        Server BigEcho(string[] input) called:
        64 client messages

İstemciyi çalıştırdığınızda, işlem istekleri ve yanıtları konsol penceresinde görüntülenir. İstemciyi kapatmak için istemci penceresinde ENTER tuşuna basın.

Calling Echo(string):
Server responds: Simple hello Simple hello

Calling BigEcho(string[]):
Server responds: Hello 0

Press <ENTER> to terminate client.

Örneği ayarlamak, derlemek ve çalıştırmak için

  1. Aşağıdaki komutu kullanarak ASP.NET 4.0'ı yükleyin:

    %windir%\Microsoft.NET\Framework\v4.0.XXXXX\aspnet_regiis.exe /i /enable
    
  2. Windows Communication Foundation Örnekleri için Tek Seferlik Kurulum Yordamı'nı gerçekleştirdiğinizden emin olun.

  3. Çözümü oluşturmak için Windows Communication Foundation Örnekleri Oluşturma başlığındaki yönergeleri izleyin.

  4. Örneği tek veya makineler arası bir yapılandırmada çalıştırmak için Windows Communication Foundation Örneklerini Çalıştırma başlığındaki yönergeleri izleyin.