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ı (.exe), şirket içinde barındırılan bir hizmet konsol programı (.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, ISampleServer arabirimi aracılığıyla temel dize yankılama işlemlerini (Echo ve BigEcho) sunulan şekilde 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. Mesaj boyutunu, işlem süresini veya her ikisini hesaplamak için sıkıştırma mesajı kodlayıcısına izleme araçları ekleyebilirsiniz.

Uyarı

.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, hem istemcide hem de hizmette sıkıştırma ve açma işlemi yapma gereksinimi varsa veya hizmet kendi kendine barındırılıyorsa kullanılabilir.

Örnek, özel bir ileti kodlayıcının nasıl oluşturulup bir WCF uygulamasıyla entegre edileceğini 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 kodu 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 sunucusu 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 uygulanmaktadır. Özel kodlayıcı için yalnızca kodlayıcı sınıf fabrikasının genel kullanıma açık olması gerekir. ServiceHost veya ChannelFactory<TChannel> nesnesi oluşturulduğunda fabrika nesnesi, bağlama öğesi tarafından döndürülür. İleti kodlayıcıları arabelleğe alınan veya akışkan modda çalışabilir. Bu örnek hem arabelleğe alınan modu hem de akış modunu gösterir.

Her mod için soyut ReadMessage sınıfta eşlik eden WriteMessage bir ve MessageEncoder 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, örneklemin iletilerin tel temsilinin 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ırmayı açmasına izin verir. İleti kodlama için işlem hattı olmadığından, WCF'de birden çok kodlayıcı kullanmaya yönelik tek model budur. İleti sıkıştırması kaldırıldıktan sonra, elde edilen mesajın kanal yığını tarafından işlenmesi için kanal yığınına aktarılır. 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, CompressBuffer sınıfını kullanmak üzere arabelleklerden akışlara dönüştürmek için yardımcı yöntemleri (DecompressBuffer ve GZipStream) kullanır.

Arabelleğe alınan ReadMessage ve WriteMessage sınıfları BufferManager sınıfını 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. Sıkıştırma sağlamak üzere örnek, mevcut bir kodlayıcıyı sarmaladığından, MessageEncoderFactory uygulaması 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 ServiceHost sınıflarından ChannelFactory<TChannel> 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 bir bağlama öğesi aracılığıyla da görünür hale getirebilirsiniz.

Yeni bir özel bağlama öğesi oluşturmak için, BindingElement sınıfından bir alt sınıf türetin. 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, MessageEncodingBindingElement öğesini de uygulamanız gerekir. MessageEncodingBindingElement eşleşen ileti kodlayıcı fabrikasının bir örneğini döndürmek üzere 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, GZipMessageEncodingBindingElement sınıfının uygulanmasını 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ı, IPolicyImportExtension arabirimini uygular, bu sınıf GZipMessageEncodingBindingElement için politikayı içeri aktarır. Svcutil.exe aracı, ilkeleri yapılandırma dosyasına aktarmak için kullanılabilir. GZipMessageEncodingBindingElement'yi işlemek için, aşağıdakiler Svcutil.exe.config'e 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'un tüm yönleri, türetilmiş sınıfta özellikler olarak BindingElementExtensionElement şeklinde 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, GZipMessageEncodingElement implementasyonunu gö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 aşağıdaki gösterime 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> öğesi içinde 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çinOne-Time Kurulum Yordamını yaptığınızdan 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 bir makine veya makineler arası bir yapılandırmada çalıştırmak için, Windows Communication Foundation örneklerini çalıştırmayönergelerini izleyin.