Aracılığıyla paylaş


Veri Aktarımı Mimarisine Genel Bakış

Windows Communication Foundation (WCF) bir mesajlaşma altyapısı olarak düşünülebilir. daha fazla işlem için iletileri alabilir, işleyebilir ve kullanıcı koduna dağıtabilir veya kullanıcı kodu tarafından verilen verilerden iletiler oluşturup bir hedefe teslim edebilir. Gelişmiş geliştiricilere yönelik olan bu konu başlığında, iletileri ve kapsanan verileri işleme mimarisi açıklanmaktadır. Veri gönderme ve alma hakkında daha basit ve görev odaklı bir görünüm için bkz. Hizmet Sözleşmelerinde Veri AktarımıNı Belirtme.

Uyarı

Bu konuda, WCF nesne modeli incelenerek görünür olmayan WCF uygulama ayrıntıları açıklanmaktadır. Belgelenmiş uygulama ayrıntılarıyla ilgili olarak dikkat edilmesi gereken konular vardır. İlk olarak, açıklamalar basitleştirilmiştir; iyileştirmeler veya başka nedenlerle gerçek uygulama daha karmaşık olabilir. İkincisi, bunlar sürümden sürüme ve hatta bir hizmet sürümünde bildirimde bulunmadan değişebileceğinden, belgelenmiş olanlar bile olmak üzere belirli uygulama ayrıntılarına asla güvenmemelisiniz.

Temel Mimari

WCF ileti işleme özelliklerinin merkezinde, Message Kullanma bölümünde ayrıntılı olarak açıklanan sınıfı yer alır. WCF'nin çalışma zamanı bileşenleri iki ana bölüme ayrılabilir: kanal yığını ve hizmet çerçevesi, Message sınıfı bağlantı noktasıdır.

Kanal yığını, geçerli Message bir örnek ile ileti verilerinin gönderilmesine veya alınmasına karşılık gelen bazı eylemler arasında dönüştürmeden sorumludur. Gönderen tarafta, kanal yığını geçerli Message bir örnek alır ve bir işlemden sonra, iletinin gönderilmesine mantıksal olarak karşılık gelen bir eylem gerçekleştirir. Eylem TCP veya HTTP paketleri gönderiyor, iletiyi Message Queuing'de kuyruğa almak, iletiyi veritabanına yazmak, dosya paylaşımına kaydetmek veya uygulamaya bağlı olarak başka bir eylem olabilir. En yaygın eylem, iletiyi bir ağ protokolü üzerinden göndermektir. Alma tarafında tam tersi gerçekleşir; bir eylem algılanır (gelen TCP veya HTTP paketleri veya başka bir eylem olabilir) ve işlendikten sonra kanal yığını bu eylemi geçerli Message bir örneğe dönüştürür.

Message sınıfını ve kanal yığınını doğrudan kullanarak WCF'yi kullanabilirsiniz. Ancak bunu yapmak zor ve zaman alır. Buna ek olarak, Message nesne meta veri desteği sağlamaz, bu nedenle WCF'yi bu şekilde kullanıyorsanız kesin olarak yazılan WCF istemcileri oluşturamazsınız.

Bu nedenle WCF, nesneleri oluşturmak ve almak Message için kullanabileceğiniz kullanımı kolay bir programlama modeli sağlayan bir hizmet çerçevesi içerir. Hizmet çerçevesi, hizmet sözleşmeleri ile hizmetleri .NET Framework türleriyle eşler ve yalnızca özniteliğiyle işaretlenmiş .NET Framework yöntemleri olan kullanıcı işlemlerine OperationContractAttribute iletiler iletir (daha fazla ayrıntı için bkz. Hizmet Sözleşmeleri Tasarlama). Bu yöntemlerin parametreleri ve dönüş değerleri olabilir. Hizmet tarafında, hizmet çerçevesi gelen Message örnekleri parametrelere dönüştürür ve dönüş değerlerini giden Message örneklere dönüştürür. İstemci tarafında ise tam tersini yapar. Örneğin, aşağıdaki işlemi göz önünde bulundurun FindAirfare .

[ServiceContract]
public interface IAirfareFinderService
{
    [OperationContract]
    int FindAirfare(string FromCity, string ToCity, out bool IsDirectFlight);
}
<ServiceContract()> _
Public Interface IAirfareFinderService

    <OperationContract()> _
    Function FindAirfare(ByVal FromCity As String, _
    ByVal ToCity As String, ByRef IsDirectFlight As Boolean) As Integer

End Interface

FindAirfare'nin istemcide çağrıldığını varsayalım. İstemcideki servis çerçevesi FromCity ve ToCity parametrelerini bir giden Message örneğine dönüştürür ve gönderilmek üzere kanal yığınına geçirir.

Hizmet tarafında, bir Message örnek kanal yığınından geldiğinde, hizmet çerçevesi iletiden FromCity ve ToCity parametrelerini doldurmak için ilgili verileri ayıklar ve ardından hizmet tarafındaki FindAirfare yöntemini çağırır. Yöntemi döndürdüğünde, hizmet çerçevesi döndürülen tamsayı değerini ve IsDirectFlight çıkış parametresini alır ve bu bilgileri içeren bir Message nesne örneği oluşturur. Ardından örneği istemciye geri gönderilmek üzere kanal yığınına geçirir Message .

İstemci tarafında, yanıt iletisini içeren bir Message örnek kanal yığınından ortaya çıkar. Hizmet çerçevesi dönüş değerini ve IsDirectFlight değerini ayıklar ve bunları istemciyi çağırana döndürür.

İleti Sınıfı

sınıfı Message , bir iletinin soyut bir gösterimi olarak tasarlanmıştır, ancak tasarımı SOAP iletisine güçlü bir şekilde bağlıdır. üç Message ana bilgi parçası içerir: ileti gövdesi, ileti üst bilgileri ve ileti özellikleri.

İleti Gövdesi

İleti gövdesi, iletinin gerçek veri yükünü temsil etmeye yöneliktir. İleti gövdesi her zaman xml bilgi kümesi olarak temsil edilir. Bu, WCF'de oluşturulan veya alınan tüm iletilerin XML biçiminde olması gerektiği anlamına gelmez. İleti gövdesini yorumlamaya karar vermek kanal yığınına bağlı. Bunu XML olarak yayabilir, başka bir biçime dönüştürebilir, hatta tamamen göz ardı edebilir. Elbette, WCF'nin sağladığı bağlamaların çoğuyla, ileti gövdesi bir SOAP zarfının gövde bölümünde XML içeriği olarak temsil edilir.

Message sınıfının gövdesini temsil eden XML verilerinin bulunduğu bir arabellek içermeyebileceğini fark etmek önemlidir. Mantıksal olarak, Message bir XML Infoset içerir, ancak bu Infoset dinamik olarak oluşturulabilir ve bellekte hiçbir zaman fiziksel olarak bulunmayabilir.

İleti Gövdesine Veri Yerleştirme

İleti gövdesine veri koymak için tekdüzen bir mekanizma yoktur. Message sınıfının bir OnWriteBodyContents(XmlDictionaryWriter) adlı soyut yöntemi vardır ve bu yöntem bir XmlDictionaryWriter alır. Sınıfın Message her alt sınıfı bu yöntemi geçersiz kılmaktan ve kendi içeriğini yazmaktan sorumludur. İleti gövdesi mantıksal olarak OnWriteBodyContent tarafından üretilen XML Bilgi Kümesi'ni içerir. Örneğin, aşağıdaki Message alt sınıfı göz önünde bulundurun.

public class AirfareRequestMessage : Message
{
    public string fromCity = "Tokyo";
    public string toCity = "London";
    //code omitted…
    protected override void OnWriteBodyContents(XmlDictionaryWriter w)
    {
        w.WriteStartElement("airfareRequest");
        w.WriteElementString("from", fromCity);
        w.WriteElementString("to", toCity);
        w.WriteEndElement();
    }

    public override MessageVersion Version
    {
        get { throw new NotImplementedException("The method is not implemented.") ; }
    }

    public override MessageProperties Properties
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }
    public override MessageHeaders Headers
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }

    public override bool IsEmpty
    {
        get
        {
            return base.IsEmpty;
        }
    }

    public override bool IsFault
    {
        get
        {
            return base.IsFault;
        }
    }
}
Public Class AirfareRequestMessage
    Inherits Message

    Public fromCity As String = "Tokyo"
    Public toCity As String = "London"
    ' Code omitted…
    Protected Overrides Sub OnWriteBodyContents(ByVal w As XmlDictionaryWriter)
        w.WriteStartElement("airfareRequest")
        w.WriteElementString("from", fromCity)
        w.WriteElementString("to", toCity)
        w.WriteEndElement()
    End Sub

    Public Overrides ReadOnly Property Version() As MessageVersion
        Get
            Throw New NotImplementedException("The method is not implemented.")
        End Get
    End Property

    Public Overrides ReadOnly Property Properties() As MessageProperties
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
    End Property

    Public Overrides ReadOnly Property Headers() As MessageHeaders
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
    End Property


    Public Overrides ReadOnly Property IsEmpty() As Boolean
        Get
            Return MyBase.IsEmpty
        End Get
    End Property

    Public Overrides ReadOnly Property IsFault() As Boolean
        Get
            Return MyBase.IsFault
        End Get
    End Property
End Class

Fiziksel olarak, bir AirfareRequestMessage örnek yalnızca iki dize ("fromCity" ve "toCity") içerir. Ancak, mantıksal olarak ileti aşağıdaki XML bilgi kümesi içerir:

<airfareRequest>
    <from>Tokyo</from>
    <to>London</to>
</airfareRequest>

Elbette, işlem sözleşmesi parametrelerinden öncekine benzer bir ileti oluşturmak için hizmet çerçevesini kullanabileceğiniz için normalde bu şekilde ileti oluşturmazsınız. Ayrıca, sınıfın Message ortak içerik türlerine sahip iletiler oluşturmak için kullanabileceğiniz statik CreateMessage yöntemleri vardır: boş bir ileti, ile DataContractSerializerXML'ye seri hale getirilmiş bir nesne içeren bir ileti, SOAP hatası içeren bir ileti, ile temsil edilen XML içeren bir XmlReaderileti vb.

İleti Gövdesinden Veri Alma

İleti gövdesinde depolanan verileri iki ana yolla ayıklayabilirsiniz:

  • WriteBodyContents(XmlDictionaryWriter) yöntemini çağırıp bir XML yazıcısını geçirerek iletinin tüm gövdesini bir kerede alabilirsiniz. İleti gövdesinin tamamı bu yazara yazılır. İleti gövdesinin tamamını bir kerede almak, ileti yazma olarak da adlandırılır. Yazma öncelikli olarak ileti gönderirken kanal yığını tarafından yapılır; kanal yığınının bir bölümü genellikle ileti gövdesinin tamamına erişim elde eder, kodlar ve gönderir.

  • İleti gövdesinden bilgi edinmenin bir diğer yolu, GetReaderAtBodyContents()'i çağırmak ve bir XML okuyucu elde etmektir. Daha sonra yöntemler okuyucuda çağrılarak ileti gövdesine gerektiğinde sırayla erişim sağlanabilir. İleti gövdesini parça parça almak, ileti okuma olarak da adlandırılır. İletiyi okumak öncelikli olarak hizmet çerçevesi tarafından iletileri alırken kullanılır. Örneğin, DataContractSerializer kullanımdaysa, hizmet çerçevesi gövde üzerinde bir XML okuyucu alır ve bunu serileştirme motoruna geçirir. Daha sonra, iletiyi öğe öğe okuyarak ilgili nesne grafını oluşturmaya başlar.

İleti gövdesi yalnızca bir kez alınabilir. Bu, yalnızca ileriye doğru akışlarla çalışmayı mümkün kılar. Örneğin, OnWriteBodyContents(XmlDictionaryWriter) dosyasından FileStream okuyan ve sonuçları XML Infoset olarak döndüren bir geçersiz kılma fonksiyonu yazabilirsiniz. Hiçbir zaman dosyanın başına "geri almanız" gerekmez.

WriteBodyContents ve GetReaderAtBodyContents yöntemleri, ileti gövdesinin daha önce hiç alınıp alınmadığını denetler ve ardından sırasıyla OnWriteBodyContents veya OnGetReaderAtBodyContents çağrısında bulunur.

WCF'de İleti Kullanımı

İletilerin çoğu giden (kanal yığını tarafından gönderilecek hizmet çerçevesi tarafından oluşturulanlar) veya gelen (kanal yığınından gelen ve hizmet çerçevesi tarafından yorumlananlar) olarak sınıflandırılabilir. Ayrıca, kanal yığını, arabellekli veya akış modunda çalışabilir. Hizmet çerçevesi akışlı veya akışsız programlama modelini de kullanıma sunabilir. Bu, aşağıdaki tabloda listelenen durumların yanı sıra uygulanmalarının basitleştirilmiş ayrıntılarına yol açar.

İleti türü İletideki gövde verileri Yazma (OnWriteBodyContents) uygulaması Read (OnGetReaderAtBodyContents) Uygulaması
Giden, akış dışı programlama modelinden oluşturuldu İletiyi yazmak için gereken veriler (örneğin, bir nesne ve DataContractSerializer onu serileştirmek için gereken örnek)* Depolanan verilere göre iletiyi yazdırmak için özel mantık (örneğin, kullanılan seri hale getirici WriteObject ise DataContractSerializer çağrısı yapın) OnWriteBodyContents Çağır, sonuçları arabelleğe al, arabellekten XML okuyucu döndür
Giden, akışlı programlama modelinden oluşturuldu Stream yazılması gereken veriler* Depolanan akıştan veri çıkarma işlemine IStreamProvider mekanizmasını kullanarak başla OnWriteBodyContents Çağır, sonuçları arabelleğe al, arabellekten XML okuyucu döndür
Akış kanalı yığınından gelen Stream üzerinden gelen verileri temsil eden bir XmlReader nesne Depolanan XmlReader içeriğini WriteNode kullanarak yazın. Depolanan değeri verir XmlReader
Akışsız kanal yığınından gelen XmlReader üzerinde olan gövde verilerini içeren bir arabellek Depolanan XmlReader içeriğini WriteNode kullanarak yazar. Depolanan lang'i verir

* Bu öğeler doğrudan alt sınıflarda Message değil, sınıfın BodyWriter alt sınıflarında uygulanır. Daha fazla bilgi için, BodyWriter hakkında bkz. Mesaj Sınıfını Kullanma.

İleti Üst Bilgileri

Bir ileti başlıklar içerebilir. Üst bilgi mantıksal olarak bir ad, ad alanı ve diğer birkaç özellik ile ilişkilendirilmiş bir XML Bilgi Kümesinden oluşur. İleti üst bilgilerine, Headers üzerindeki Message özelliği kullanılarak erişilir. Her başlık bir MessageHeader sınıfıyla temsil edilir. Normalde, SOAP iletileriyle çalışmak üzere yapılandırılmış bir kanal yığını kullanılırken ileti üst bilgileri SOAP ileti üst bilgilerine eşlenir.

Bilgileri bir ileti üst bilgisine yerleştirmek ve bu üst bilgiden bilgi ayıklamak, ileti gövdesini kullanmaya benzer. Akış desteklenmediğinden işlem biraz basitleştirilmiştir. Aynı başlığın içeriğine birden çok kez erişmek mümkündür ve başlıklar rastgele sırayla erişilebilir olduğundan başlıklar her zaman arabelleğe alınmaya zorlanır. Üst bilgi üzerinden XML okuyucu almak için genel amaçlı bir mekanizma yoktur, ancak WCF'nin içinde bu tür bir MessageHeader özelliğe sahip okunabilir bir üst bilgiyi temsil eden bir alt sınıf vardır. Bu tür, MessageHeader özelleştirilmiş uygulama başlıklarına sahip bir ileti geldiğinde kanal dizisi tarafından oluşturulur. Bu, hizmet çerçevesinin bu üst bilgileri yorumlamak için DataContractSerializer gibi bir çözülüm motoru kullanmasını sağlar.

Daha fazla bilgi için bkz. İleti Sınıfını Kullanma.

İleti Özellikleri

İleti özellikleri içerebilir. Özellik, bir dize adıyla ilişkilendirilmiş herhangi bir .NET Framework nesnesidir. Özelliklere Properties üzerindeki Message özelliği aracılığıyla erişilir.

İleti gövdesinden ve ileti üst bilgilerinden farklı olarak (normalde sırasıyla SOAP gövdesine ve SOAP üst bilgilerine eşlenir), ileti özellikleri normalde iletilerle birlikte gönderilmez veya alınmaz. İleti özellikleri öncelikli olarak, ileti hakkındaki verileri kanal yığınındaki çeşitli kanallar arasında ve kanal yığını ile hizmet modeli arasında geçirmek için bir iletişim mekanizması olarak bulunur.

Örneğin, WCF'nin bir parçası olarak eklenen HTTP aktarım kanalı, istemcilere yanıt gönderirken "404 (Bulunamadı)" ve "500 (İç Sunucu Hatası)" gibi çeşitli HTTP durum kodları oluşturabilir. Yanıt iletisi göndermeden önce, Properties öğesinin Message içinde HttpResponseMessageProperty türünde bir nesne içeren "httpResponse" adlı bir özellik olup olmadığını denetler. Böyle bir özellik bulunursa özelliğine StatusCode bakar ve bu durum kodunu kullanır. Bulunamazsa, varsayılan "200 (Tamam)" kodu kullanılır.

Daha fazla bilgi için bkz. İleti Sınıfını Kullanma.

Bir Bütün Olarak İleti

Şimdiye kadar iletinin çeşitli bölümlerine yalıtılmış olarak erişme yöntemlerini ele aldık. Ancak, Message sınıfı, iletiyi bir bütün olarak ele almak için yöntemler de sağlar. Örneğin, WriteMessage yöntemi iletinin tamamını bir XML yazıcısına yazar.

Bunun mümkün olması için, tüm Message örnek ile XML Infoset arasında bir eşleme tanımlanmalıdır. Aslında böyle bir eşleme vardır: WCF, bu eşlemeyi tanımlamak için SOAP standardını kullanır. Bir Message örnek XML Infoset olarak yazıldığında, sonuçta elde edilen Infoset, iletiyi içeren geçerli SOAP zarfıdır. Bu nedenle, WriteMessage normalde aşağıdaki adımları gerçekleştirir:

  1. SOAP zarf öğesi açma etiketini yazın.

  2. SOAP üst bilgi öğesi açma etiketini yazın, tüm üst bilgileri yazın ve üst bilgi öğesini kapatın.

  3. SOAP gövdesinin öğesinin açılış etiketini yazın.

  4. İçeriği yazmak için WriteBodyContents veya eşdeğer bir yöntemi çağrı yaparak.

  5. Gövde ve zarf öğelerini kapatın.

Önceki adımlar SOAP standardına yakından bağlıdır. Bu, SOAP'nin birden çok sürümünün mevcut olması nedeniyle karmaşıktır, örneğin, SOAP zarf öğesinin kullanımdaki SOAP sürümünü bilmeden doğru bir şekilde yazılmasının mümkün olmamasıdır. Ayrıca, bazı durumlarda, bu karmaşık SOAP'ye özgü eşlemenin tamamen kapatılması istenebilir.

Bu amaçlar için Version üzerinde bir Message özellik sağlanır. İletiyi yazarken kullanılacak SOAP sürümüne ayarlanabilir veya SOAP'ye özgü eşlemeleri önlemek için None olarak ayarlanabilir. Version özelliği olarak Noneayarlanırsa, iletinin tamamıyla çalışan yöntemler, ileti yalnızca gövdesinden oluşuyormuş gibi davranır, örneğin, WriteMessage yukarıda listelenen birden çok adımı gerçekleştirmek yerine yalnızca çağrı WriteBodyContents yapar. Gelen iletilerde Version otomatik olarak algılanması ve doğru ayarlanması beklenir.

Kanal Katmanı

Kanallar

Daha önce belirtildiği gibi, kanal yığını giden Message örnekleri bir eyleme (ağ üzerinden paket gönderme gibi) dönüştürmek veya bazı eylemleri (ağ paketlerini alma gibi) gelen Message örneklere dönüştürmekle sorumludur.

Kanal yığını, sırayla sıralanmış bir veya daha fazla kanaldan oluşur. Giden Message örnek yığındaki ilk kanala geçirilir ( en üstteki kanal olarak da adlandırılır), bu da bunu yığında bir sonraki kanala geçirir ve bu şekilde devam eder. İleti, aktarım kanalı olarak adlandırılan son kanalda sonlanır. Gelen iletiler, aktarım kanalından gelir ve yığın boyunca kanal aracılığıyla katmandan katmana iletilir. En üstteki kanaldan, ileti genellikle hizmet çerçevesine geçirilir. Bu, uygulama iletileri için her zamanki desen olsa da, bazı kanallar biraz farklı çalışabilir, örneğin, yukarıdaki bir kanaldan ileti gönderilmeden kendi altyapı iletilerini gönderebilirler.

Kanallar, veri yığından geçerken ileti üzerinde çeşitli şekillerde çalışabilir. En yaygın işlem, giden iletiye üst bilgi eklemek ve gelen iletide üst bilgileri okumaktır. Örneğin, bir kanal iletinin dijital imzasını hesaplayıp üst bilgi olarak ekleyebilir. Kanal, gelen iletilerde bu dijital imza üst bilgisini de inceleyip geçerli bir imzası olmayan iletilerin kanal yığınına çıkış yapmasını engelleyebilir. Kanallar genellikle ileti özelliklerini de ayarlar veya inceler. İleti gövdesi genellikle değiştirilmez, ancak buna izin verilir, örneğin WCF güvenlik kanalı ileti gövdesini şifreleyebilir.

Aktarım Kanalları ve İleti Kodlayıcıları

Yığındaki en alttaki kanal, diğer kanallar tarafından değiştirildiği gibi giden bir Messageöğesini gerçekten bir eyleme dönüştürmekle sorumludur. Alma tarafında, bu kanal bazı eylemleri diğer kanalların işleyebileceği bir Message'ya dönüştürür.

Önceden belirtildiği gibi, eylemler çeşitlilik gösterebilir: çeşitli protokoller üzerinden ağ paketleri gönderme veya alma, iletiyi veritabanında okuma veya yazma, ya da Message Queuing kuyruğunda kuyruğa alma veya kuyruktan çıkarma gibi bazı örnekler olarak. Tüm bu eylemlerin tek bir ortak yanı vardır: WCFMessage örneği ile gönderilebilen, alınabilen, okunabilen, yazılabilir, kuyruğa alınabilen veya kuyruktan çıkarılabilen gerçek bir bayt grubu arasında dönüştürme gerektirir. bir Message bayt grubuna dönüştürme işlemi kodlama olarak adlandırılır ve bir bayt grubundan oluşturma Message işleminin ters işlemi kod çözme olarak adlandırılır.

Çoğu aktarım kanalı, kodlama ve kod çözme işini gerçekleştirmek için ileti kodlayıcıları olarak adlandırılan bileşenleri kullanır. İleti kodlayıcı sınıfın MessageEncoder alt sınıfıdır. MessageEncoder farklı ReadMessage ve WriteMessage yöntem aşırı yüklemeleri içerir, Message ile bayt grupları arasında dönüştürme yapmak için.

Gönderim tarafında, bir arabelleğe alma aktarım kanalı, üstündeki bir kanaldan aldığı Message nesneyi WriteMessage nesneye geçirir. Daha sonra eylemini gerçekleştirmek için kullandığı bir bayt dizisi alır (örneğin, bu baytları geçerli TCP paketleri olarak paketleme ve doğru hedefe gönderme). Akış aktarım kanalı önce bir Stream (örneğin, giden TCP bağlantısı üzerinden) oluşturur ve ardından hem Stream hem de Message 'yi uygun WriteMessage aşırı yüklemeye geçirerek iletiyi yazmak için gönderir.

Alma tarafında, bir arabelleğe alma aktarım kanalı gelen baytları (örneğin, gelen TCP paketlerinden) bir diziye ayıklar ve daha yukarıdaki kanal yığınına iletebileceği bir ReadMessage nesnesi almak için Message çağrısını yapar. Akış aktarım kanalı, gelen TCP bağlantısı üzerinden bir ağ akışı gibi bir Stream nesnesi oluşturur ve bu nesneyi bir ReadMessage nesnesi almak için Message'e iletir.

Aktarım kanalları ile ileti kodlayıcı arasındaki ayrım zorunlu değildir; ileti kodlayıcı kullanmayan bir aktarım kanalı yazmak mümkündür. Ancak, bu ayrılmanın avantajı kompozisyon kolaylığıdır. Aktarım kanalı yalnızca tabanını MessageEncoderkullandığı sürece, herhangi bir WCF veya üçüncü taraf ileti kodlayıcı ile çalışabilir. Benzer şekilde, aynı kodlayıcı normalde herhangi bir aktarım kanalında kullanılabilir.

İleti Kodlayıcı İşlemi

Bir kodlayıcının tipik çalışmasını açıklamak için aşağıdaki dört örneği göz önünde bulundurmak yararlıdır.

Operasyon Yorum
Kodlama, Arabelleğe Alınan Arabelleğe alınan modda kodlayıcı normalde değişken boyutlu bir arabellek oluşturur ve ardından bunun üzerinde bir XML yazıcı oluşturur. Ardından, kodlanan ileti üzerinde WriteMessage(XmlWriter) çağrılır; bu işlem, bu konudaki WriteBodyContents(XmlDictionaryWriter) bölümde açıklandığı gibi önce üst bilgileri yazar ve sonra Message kullanarak gövdeyi yazar. Daha sonra aktarım kanalının kullanması için arabellek içeriği (bayt dizisi olarak temsil edilir) döndürülür.
Kodlama, Akışlı Akış modunda, işlem yukarıdakine benzer, ancak daha basittir. Arabelleğe gerek yoktur. Akış üzerinde normalde bir XML yazıcı oluşturulur ve WriteMessage(XmlWriter) üzerindeki Message bu yazıcıya yazılması için çağrılır.
Kod Çözme, Arabellekli Arabelleğe alınmış modda kod çözme işlemi yapılırken, normalde arabelleğe alınan verileri içeren özel Message bir alt sınıf oluşturulur. İletinin üst bilgileri okunur ve ileti gövdesinde konumlandırılmış bir XML okuyucu oluşturulur. Bu, GetReaderAtBodyContents() ile döndürülecek olan okuyucudur.
Kod Çözme, Akışa Alma Akış modunda kod çözme işlemi yapılırken normalde özel bir İleti alt sınıfı oluşturulur. Akış, tüm üst bilgileri okumak ve ileti gövdesinde konumlandırmak için yeterli düzeyde ilerlemiştir. Daha sonra akış üzerinden bir XML okuyucu oluşturulur. Bu, GetReaderAtBodyContents() ile döndürülecek olan okuyucudur.

Kodlayıcılar diğer işlevleri de gerçekleştirebilir. Örneğin, kodlayıcılar XML okuyucularını ve yazıcılarını havuza alabilir. Her gerektiğinde yeni bir XML okuyucu veya yazıcı oluşturmak pahalıdır. Bu nedenle kodlayıcılar normalde bir okuyucu havuzu ve yapılandırılabilir boyutta yazar havuzu tutar. Daha önce açıklanan kodlayıcı işleminin açıklamalarında, "XML okuyucu/yazıcı oluşturma" tümceciği her kullanıldığında, normalde "havuzdan bir tane alın veya yoksa oluşturun" anlamına gelir. Kodlayıcı (ve Message kod çözme sırasında oluşturduğu alt sınıflar), artık gerekli olmadığında (örneğin, kapatıldığında Message ) okuyucuları ve yazıcıları havuzlara döndürmek için mantık içerir.

WCF üç ileti kodlayıcı sağlar, ancak ek özel türler oluşturmak mümkündür. Sağlanan türler Metin, İkili ve İleti İletim İyileştirme Mekanizması 'dır (MTOM). Bunlar , İleti Kodlayıcı Seçme bölümünde ayrıntılı olarak açıklanmıştır.

IStreamProvider Arabirimi

Akışlı gövde içeren bir giden iletiyi XML yazıcısına yazarken, Message uygulamasında aşağıdakine OnWriteBodyContents(XmlDictionaryWriter) benzer bir çağrı dizisi kullanılır:

  • Akışın önüne gerekli bilgileri yazın (örneğin, açılış XML etiketi).

  • Akışı yazın.

  • Akışı takip eden tüm bilgileri yazın (örneğin, kapanış XML etiketi).

Bu, metin xml kodlamasına benzer kodlamalarla iyi çalışır. Ancak, bazı kodlamalar XML Infoset bilgilerini (örneğin, XML öğelerini başlatma ve sonlandırma etiketleri) öğelerin içinde bulunan verilerle birlikte yerleştirmez. Örneğin, MTOM kodlamasında ileti birden çok bölüme ayrılır. Bir bölüm, gerçek öğe içeriği için diğer bölümlere başvurular içerebilen XML Infoset'i içerir. XML Bilgi Kümesi genellikle akış halinde olan içeriğe göre daha küçüktür, bu yüzden Bilgi Kümesi'ni tamponlamak, yazmak ve ardından içeriği akış yöntemiyle yazmak mantıklıdır. Bu, kapanış öğesi etiketinin yazıldığı sırada akışın yazılmamış olması gerektiği anlamına gelir.

Bu amaçla arabirim IStreamProvider kullanılır. Arabirim, yazılacak olan akışı döndüren bir GetStream() yönteme sahiptir. Yayınlanan ileti gövdesini OnWriteBodyContents(XmlDictionaryWriter) doğru bir şekilde yazmak için şunlara dikkat edilmelidir:

  1. Akışın önüne gerekli bilgileri yazın (örneğin, açılış XML etiketi).

  2. WriteValue alanını alan XmlDictionaryWriter üzerindeki IStreamProvider aşırı yüklemesini çağırın, akışın yazılması için dönen bir IStreamProvider uygulaması ile.

  3. Akışı takip eden tüm bilgileri yazın (örneğin, kapanış XML etiketi).

Bu yaklaşımla, XML yazıcısı GetStream() çağırma ve akış verilerini yazma zamanını seçebilir. Örneğin, metinsel ve ikili XML yazıcıları bunu hemen çağırır ve akış içeriklerini başlangıç ve bitiş etiketleri arasında yazar. MTOM yazıcı, iletinin uygun bölümünü yazmaya hazır olduğunda GetStream() çağrısını yapmaya karar verebilir.

Service Framework'te Verileri Temsil Etme

Bu konunun "Temel Mimari" bölümünde belirtildiği gibi, hizmet çerçevesi WCF'nin diğer şeylerin yanı sıra ileti verileri ve gerçek Message örnekler için kullanıcı dostu bir programlama modeli arasında dönüştürmeden sorumlu olan bölümüdür. Normalde, bir ileti değişimi hizmet çerçevesinde özniteliğiyle OperationContractAttribute işaretlenmiş bir .NET Framework yöntemi olarak temsil edilir. Yöntem, bazı parametreleri alabilir ve bir dönüş değeri veya çıkış parametrelerini (veya her ikisini birden) döndürebilir. Hizmet tarafında giriş parametreleri gelen iletiyi, dönüş değeri ve çıkış parametreleri giden iletiyi temsil eder. İstemci tarafında tersi doğrudur. Parametreleri ve dönüş değerini kullanarak iletileri açıklamaya yönelik programlama modeli , Hizmet Sözleşmelerinde Veri Aktarımını Belirtme bölümünde ayrıntılı olarak açıklanmıştır. Ancak, bu bölüm kısa bir genel bakış sağlayacaktır.

Programlama Modelleri

WCF hizmet çerçevesi, iletileri tanımlamak için beş farklı programlama modelini destekler:

1. Boş İleti

Bu en basit dava. Boş bir gelen iletiyi açıklamak için herhangi bir giriş parametresi kullanmayın.

[OperationContract]
int GetCurrentTemperature();
<OperationContract()> Function GetCurrentTemperature() As Integer

Boş bir çıkış mesajını tanımlamak için void dönüş değeri kullanın ve out parametresi kullanmayın.

[OperationContract]
void SetDesiredTemperature(int t);
<OperationContract()> Sub SetDesiredTemperature(ByVal t As Integer)

Bunun tek yönlü işlem sözleşmesinden farklı olduğunu unutmayın:

[OperationContract(IsOneWay = true)]
void SetLightbulb(bool isOn);
<OperationContract(IsOneWay:=True)> Sub SetLightbulb(ByVal isOn As Boolean)

SetDesiredTemperature Örnekte, iki yönlü ileti değişimi deseni açıklanmıştır. İşlemden bir ileti döndürülür, ancak boş olur. İşlemden hata döndürülmesi mümkündür. "Ampul Ayarla" örneğinde, ileti değişimi deseni tek yönlüdür, bu nedenle açıklanacağı bir giden ileti yoktur. Bu durumda hizmet istemciye herhangi bir durum bildiremez.

2. İleti Sınıfını Doğrudan Kullanma

Sınıfını Message (veya alt sınıflarından birini) doğrudan bir işlem sözleşmesinde kullanmak mümkündür. Bu durumda, hizmet çerçevesi Message işlemden kanal yığınına (veya tam tersi) iletir ve daha fazla işlem yapılmaz.

Message'ü doğrudan kullanmanın iki ana kullanım örneği vardır. Diğer programlama modellerinden hiçbiri iletinizi açıklamak için yeterli esneklik sunmadığında, bunu gelişmiş senaryolar için kullanabilirsiniz. Örneğin, bir iletiyi açıklamak için disk üzerindeki dosyaları kullanmak isteyebilirsiniz; dosyanın özellikleri ileti üst bilgilerine, dosyanın içeriği de ileti gövdesine dönüşebilir. Daha sonra aşağıdakine benzer bir şey oluşturabilirsiniz.

public class FileMessage : Message
// Code not shown.
Public Class FileMessage
    Inherits Message
    ' Code not shown.

Bir işlem sözleşmesinde Message'ün ikinci yaygın kullanımı, bir hizmetin belirli ileti içeriğini umursamadığı ve mesaj üzerinde kara kutu gibi davrandığında gerçekleşir. Örneğin, iletileri birden çok alıcıya ileden bir hizmetiniz olabilir. Sözleşme aşağıdaki gibi yazılabilir.

[OperationContract]
public FileMessage GetFile()
{
    //code omitted…
    FileMessage fm = new FileMessage("myFile.xml");
    return fm;
}
<OperationContract()> Public Function GetFile() As FileMessage
    'code omitted…
    Dim fm As New FileMessage("myFile.xml")
    Return fm
End Function

Action="*" satırı, mesaj yönlendirmeyi etkili bir şekilde kapatır ve sözleşmeye gönderilen tüm iletilerin IForwardingService işlemine ulaşmasını ForwardMessage garanti eder. (Normalde dağıtıcı, hangi işleme yönelik olduğunu belirlemek için iletinin "Eylem" üst bilgisini inceler. Action="*", "Eylem üst bilgisinin tüm olası değerleri" anlamına gelir.) Tüm olası iletileri alabildiği için Action="*" ve Message'ın parametre olarak kullanılması "evrensel sözleşme" olarak bilinir. Tüm olası iletileri gönderebilmek için dönüş değeri olarak İleti'yi kullanın ve "*" olarak ayarlayın ReplyAction . Bu, hizmet çerçevesinin kendi Eylem üst bilgisini eklemesini engelleyerek, döndürülen nesneyi kullanarak Message bu üst bilgiyi denetlemenizi sağlar.

3. İleti Sözleşmeleri

WCF, iletileri açıklamak için ileti sözleşmeleri olarak adlandırılan bildirim temelli bir programlama modeli sağlar. Bu model , İleti Sözleşmelerini Kullanma bölümünde ayrıntılı olarak açıklanmıştır. Temelde, iletinin tamamı, ileti sözleşmesi sınıfının hangi bölümlerinin iletinin hangi bölümüyle eşlenmesi gerektiğini açıklamak için MessageBodyMemberAttribute ve MessageHeaderAttribute gibi öznitelikler kullanan tek bir .NET Framework türüyle temsil edilir.

İleti sözleşmeleri, elde edilen Message örnekleri üzerinde çok fazla denetim sağlar (ancak sınıfı doğrudan kullanmak Message, açıkçası, bu kadar fazla denetim sağlamaz). Örneğin, ileti gövdeleri genellikle her biri kendi XML öğesiyle temsil edilen birden çok bilgi parçasından oluşur. Bu öğeler teknik belgede (çıplak modda) doğrudan yer alabilir veya bir XML elemanı içinde sarılarak sunulabilir. Mesaj sözleşmesi programlama modelini kullanmak, çıplak mı sarmalanmış mı mesaj kararını vermenizi ve sarmalayıcı öğenin adı ile ad alanını kontrol etmenizi sağlar.

İleti sözleşmesinin aşağıdaki kod örneği bu özellikleri gösterir.

[MessageContract(IsWrapped = true, WrapperName = "Order")]
public class SubmitOrderMessage
{
    [MessageHeader]
    public string customerID;
    [MessageBodyMember]
    public string item;
    [MessageBodyMember]
    public int quantity;
}
<MessageContract(IsWrapped:=True, WrapperName:="Order")> _
Public Class SubmitOrderMessage
    <MessageHeader()> Public customerID As String
    <MessageBodyMember()> Public item As String
    <MessageBodyMember()> Public quantity As Integer
End Class

Seri hale getirilecek şekilde işaretlenmiş öğeler ( MessageBodyMemberAttribute, MessageHeaderAttributeveya diğer ilgili özniteliklerle) ileti sözleşmesine katılmak için seri hale getirilebilir olmalıdır. Daha fazla bilgi için bu konunun devamında yer alan "Serileştirme" bölümüne bakın.

4. Parametreler

Çoğu zaman, birden çok veri parçası üzerinde işlem yapan bir işlemi açıklamak isteyen bir geliştiricinin, ileti sözleşmelerinin sağladığı denetim derecesine ihtiyacı yoktur. Örneğin, yeni hizmetler oluştururken genellikle temel mi yoksa kapsayıcı mı olacağını belirlemek ve kapsayıcı öğenin adını seçmek istemezsiniz. Bu kararların alınması genellikle Web hizmetleri ve SOAP hakkında derin bilgi gerektirir.

WCF hizmet çerçevesi, bu seçenekleri kullanıcıya zorlamadan, ilgili birden çok bilgi parçası göndermek veya almak için en iyi ve en çok birlikte çalışabilen SOAP gösterimini otomatik olarak seçebilir. Bu, yalnızca bu bilgi parçalarını bir işlem sözleşmesinin parametreleri veya dönüş değerleri olarak tanımlayarak gerçekleştirilir. Örneğin, aşağıdaki işlem sözleşmesini göz önünde bulundurun.

[OperationContract]
void SubmitOrder(string customerID, string item, int quantity);
<OperationContract()> _
Sub SubmitOrder( _
    ByVal customerID As String, _
    ByVal item As String, _
    ByVal quantity As Integer)

Hizmet çerçevesi otomatik olarak üç bilgi parçasını da (customerID, itemve quantity) ileti gövdesine yerleştirmeye ve bunları adlı SubmitOrderRequestsarmalayıcı öğesine sarmalamaya karar verir.

Daha karmaşık ileti sözleşmesine veya tabanlı programlama modellerine geçmek için özel nedenler olmadığı sürece, gönderilecek veya Messagealınacak bilgilerin basit bir işlem sözleşmesi parametreleri listesi olarak açıklanması önerilen yaklaşımdır.

5. Akış

Bir işlem sözleşmesinde veya bir ileti sözleşmesinde alt sınıflarından birini veya tek ileti gövdesi parçası olarak kullanmak Stream , yukarıda açıklananlardan ayrı bir programlama modeli olarak kabul edilebilir. Stream kullanmanın bu yolu, kendi akış uyumlu Message alt sınıfınızı yazmak dışında, sözleşmenizin akışlı bir şekilde kullanılabileceğinden emin olmanın tek yoludur. Daha fazla bilgi için bkz. Büyük Veri ve Akış.

Alt Stream sınıflarından biri veya alt sınıflarından biri bu şekilde kullanıldığında seri hale getirici çağrılmıyor. Giden iletiler için özel bir streaming Message alt sınıfı oluşturulur ve akış, IStreamProvider arabirimi hakkındaki bölümde açıklandığı gibi yazılır. Gelen iletiler için hizmet çerçevesi, gelen ileti üzerinde bir Stream alt sınıf oluşturur ve bunu işleme sunar.

Programlama Modeli Kısıtlamaları

Yukarıda açıklanan programlama modelleri rastgele birleştirilemez. Örneğin, bir işlem bir ileti sözleşmesi türünü kabul ederse, ileti sözleşmesinin tek giriş parametresi olması gerekir. Ayrıca işlemin boş bir ileti (dönüş türü void) veya başka bir ileti sözleşmesi döndürmesi gerekir. Bu programlama modeli kısıtlamaları, belirli programlama modellerinin konu başlıklarında açıklanmıştır: İleti Sözleşmelerini Kullanma, İleti Sınıfını Kullanma ve Büyük Veri ve Akış.

İleti Biçimlendiricileri

Yukarıda açıklanan programlama modelleri , hizmet çerçevesine ileti biçimlendiricileri olarak adlandırılan bileşenleri takarak desteklenir. İleti biçimlendiricileri, istemcilerde kullanılmak üzere IClientMessageFormatter ya da IDispatchMessageFormatter arabirimini veya her ikisini birden uygulayan türlerdir. Bunlar hizmet ve WCF istemcileri ile kullanılmak üzere tasarlanmıştır.

İleti biçimlendiricileri normalde davranışlara göre takılıdır. Örneğin, DataContractSerializerOperationBehavior veri sözleşmesi ileti biçimlendiricisini ekler. Bu işlem, hizmet tarafında, Formatter yönteminde ApplyDispatchBehavior(OperationDescription, DispatchOperation) doğru biçimlendiriciye ayarlanarak veya istemci tarafında, Formatter yönteminde ApplyClientBehavior(OperationDescription, ClientOperation) doğru biçimlendiriciye ayarlanarak gerçekleştirilir.

Aşağıdaki tablolarda, bir ileti biçimlendiricinin uygulayabileceği yöntemler listelenir.

Arayüz Yöntem Eylem
IDispatchMessageFormatter DeserializeRequest(Message, Object[]) Gelen Message, işlem parametrelerine dönüştürülür.
IDispatchMessageFormatter SerializeReply(MessageVersion, Object[], Object) İşlemden giden Message dönüş değeri/çıkış parametreleri oluşturur
IClientMessageFormatter SerializeRequest(MessageVersion, Object[]) Operasyon parametrelerinden bir giden Message oluşturur
IClientMessageFormatter DeserializeReply(Message, Object[]) Gelen Message bir değeri dönüş değerine/çıkış parametrelerine dönüştürür

Seri -leştirme

İleti içeriğini açıklamak için ileti sözleşmelerini veya parametrelerini her kullandığınızda, .NET Framework türleri ile XML Infoset gösterimi arasında dönüştürme yapmak için serileştirme kullanmanız gerekir. Serileştirme işlemi, WCF'deki diğer yerlerde kullanılır; örneğin, Message'ün bir nesneye seri durumdan çıkarılmış olan iletinin tüm gövdesini okumak için kullanabileceğiniz Genel GetBody yöntemi vardır.

WCF, parametreleri ve ileti parçalarını seri hale getirmek ve seri durumdan çıkarmak için "kullanıma hazır" iki serileştirme teknolojisini destekler: DataContractSerializer ve XmlSerializer. Ayrıca, özel serileştiriciler yazabilirsiniz. Ancak, WCF'nin diğer bölümleri (Genel GetBody yöntem veya SOAP hata serileştirmesi gibi) yalnızca XmlObjectSerializer alt sınıfları (DataContractSerializer ve NetDataContractSerializer, XmlSerializerdeğil) kullanacak şekilde kısıtlanabilir, hatta yalnızca DataContractSerializerkullanmak için sabit kodlanmış olabilir.

XmlSerializer, ASP.NET Web hizmetlerinde kullanılan serileştirme altyapısıdır. DataContractSerializer, yeni veri sözleşmesi programlama modelini anlayan yeni serileştirme altyapısıdır. DataContractSerializer varsayılan seçenektir ve XmlSerializer öğesini kullanma seçeneği, DataContractFormatAttribute özniteliği kullanılarak işlem bazında yapılabilir.

DataContractSerializerOperationBehavior ve XmlSerializerOperationBehavior sırasıyla DataContractSerializer ve XmlSerializer için ileti biçimlendiricilerini takmaktan sorumlu işlem davranışlarıdır. DataContractSerializerOperationBehavior davranışı, 'den XmlObjectSerializer türetilen herhangi bir seri hale getiriciyle çalışabilir, ayrıca NetDataContractSerializer de (Detaylar için Stand-Alone Serileştirmeyi Kullanma bölümüne bakın) çalışabilir. Bu işlev, serileştiriciyi almak için sanal yöntem aşırı yüklemelerinden birini çağırır. Farklı bir seri hale getiriciyi takmak için yeni bir DataContractSerializerOperationBehavior alt sınıfı oluşturun ve her iki CreateSerializer aşırı yüklemesini de geçersiz kılın.

Ayrıca bakınız