Använda meddelandeklassen
Klassen Message är grundläggande för Windows Communication Foundation (WCF). All kommunikation mellan klienter och tjänster resulterar i slutänden att Message instanser skickas och tas emot.
Vanligtvis interagerar du inte direkt med Message klassen. I stället används WCF-tjänstmodellkonstruktioner, till exempel datakontrakt, meddelandekontrakt och åtgärdskontrakt, för att beskriva inkommande och utgående meddelanden. I vissa avancerade scenarier kan du dock programmera med Message klassen direkt. Du kanske till exempel vill använda Message klassen:
När du behöver ett alternativt sätt att skapa utgående meddelandeinnehåll (till exempel att skapa ett meddelande direkt från en fil på disk) i stället för att serialisera .NET Framework-objekt.
När du behöver ett alternativt sätt att använda inkommande meddelandeinnehåll (till exempel när du vill tillämpa en XSLT-transformering på xml-innehållet i råformat) i stället för att deserialisera till .NET Framework-objekt.
När du behöver hantera meddelanden på ett allmänt sätt oavsett meddelandeinnehåll (till exempel när du dirigerar eller vidarebefordrar meddelanden när du skapar en router, en lastbalanserare eller ett publiceringsprenumereringssystem).
Innan du använder Message klassen bör du bekanta dig med arkitekturen för WCF-dataöverföring i Översikt över arkitektur för dataöverföring.
A Message är en allmän container för data, men dess design följer noga utformningen av ett meddelande i SOAP-protokollet. Precis som i SOAP har ett meddelande både en meddelandetext och rubriker. Meddelandetexten innehåller faktiska nyttolastdata, medan rubrikerna innehåller ytterligare namngivna datacontainrar. Reglerna för att läsa och skriva brödtexten och rubrikerna skiljer sig åt, till exempel är rubrikerna alltid buffrade i minnet och kan nås i valfri ordning valfritt antal gånger, medan brödtexten kan vara skrivskyddad en gång och kan strömmas. När du använder SOAP mappas meddelandetexten normalt till SOAP-brödtexten och meddelanderubrikerna mappas till SOAP-huvudena.
Använda meddelandeklassen i åtgärder
Du kan använda Message klassen som indataparameter för en åtgärd, returvärdet för en åtgärd eller både och. Om Message används någonstans i en åtgärd gäller följande begränsningar:
Åtgärden får inte ha några
out
ellerref
parametrar.Det får inte finnas fler än en
input
parameter. Om parametern finns måste den vara antingen Meddelande eller en meddelandekontraktstyp.Returtypen måste vara antingen
void
,Message
eller en meddelandekontraktstyp.
Följande kodexempel innehåller ett giltigt åtgärdskontrakt.
[ServiceContract]
public interface IMyService
{
[OperationContract]
Message GetData();
[OperationContract]
void PutData(Message m);
}
<ServiceContract()> _
Public Interface IMyService
<OperationContract()> _
Function GetData() As Message
<OperationContract()> _
Sub PutData(ByVal m As Message)
End Interface
Skapa grundläggande meddelanden
Klassen Message innehåller statiska CreateMessage
fabriksmetoder som du kan använda för att skapa grundläggande meddelanden.
Alla CreateMessage
överlagringar tar en versionsparameter av typen MessageVersion som anger vilka SOAP- och WS-Adresseringsversioner som ska användas för meddelandet. Om du vill använda samma protokollversioner som det inkommande meddelandet kan du använda IncomingMessageVersion egenskapen på den OperationContext instans som hämtas från Current egenskapen. De flesta CreateMessage
överlagringar har också en strängparameter som anger soap-åtgärden som ska användas för meddelandet. Versionen kan ställas in på för att None
inaktivera SOAP-kuvertgenerering. Meddelandet består bara av brödtexten.
Skapa meddelanden från objekt
Den mest grundläggande CreateMessage
överbelastningen som bara tar en version och en åtgärd skapar ett meddelande med en tom brödtext. En annan överlagring tar ytterligare Object en parameter. Detta skapar ett meddelande vars brödtext är den serialiserade representationen av det angivna objektet. DataContractSerializer Använd med standardinställningarna för serialisering. Om du vill använda en annan serialiserare, eller om du vill ha den DataContractSerializer
konfigurerade på ett annat sätt, använder du den CreateMessage
överlagring som också tar en XmlObjectSerializer
parameter.
Om du till exempel vill returnera ett objekt i ett meddelande kan du använda följande kod.
public class MyService1 : IMyService
{
public Message GetData()
{
Person p = new Person();
p.name = "John Doe";
p.age = 42;
MessageVersion ver = OperationContext.Current.IncomingMessageVersion;
return Message.CreateMessage(ver, "GetDataResponse", p);
}
public void PutData(Message m)
{
// Not implemented.
}
}
[DataContract]
public class Person
{
[DataMember] public string name;
[DataMember] public int age;
}
Public Class MyService1
Implements IMyService
Public Function GetData() As Message _
Implements IMyService.GetData
Dim p As New Person()
p.name = "John Doe"
p.age = 42
Dim ver As MessageVersion = _
OperationContext.Current.IncomingMessageVersion
Return Message.CreateMessage(ver, "GetDataResponse", p)
End Function
Public Sub PutData(ByVal m As Message) _
Implements IMyService.PutData
' Not implemented.
End Sub
End Class
<DataContract()> _
Public Class Person
<DataMember()> _
Public name As String
<DataMember()> _
Public age As Integer
End Class
Skapa meddelanden från XML-läsare
Det finns CreateMessage
överlagringar som tar en XmlReader eller en XmlDictionaryReader för brödtexten i stället för ett objekt. I det här fallet innehåller meddelandets brödtext den XML som är resultatet av läsning från den skickade XML-läsaren. Följande kod returnerar till exempel ett meddelande med brödtextinnehåll som lästs från en XML-fil.
public class MyService2 : IMyService
{
public Message GetData()
{
FileStream stream = new FileStream("myfile.xml",FileMode.Open);
XmlDictionaryReader xdr =
XmlDictionaryReader.CreateTextReader(stream,
new XmlDictionaryReaderQuotas());
MessageVersion ver =
OperationContext.Current.IncomingMessageVersion;
return Message.CreateMessage(ver,"GetDataResponse",xdr);
}
public void PutData(Message m)
{
// Not implemented.
}
}
Public Class MyService2
Implements IMyService
Public Function GetData() As Message Implements IMyService.GetData
Dim stream As New FileStream("myfile.xml", FileMode.Open)
Dim xdr As XmlDictionaryReader = _
XmlDictionaryReader.CreateTextReader(stream, New XmlDictionaryReaderQuotas())
Dim ver As MessageVersion = OperationContext.Current.IncomingMessageVersion
Return Message.CreateMessage(ver, "GetDataResponse", xdr)
End Function
Public Sub PutData(ByVal m As Message) Implements IMyService.PutData
End Sub
End Class
Dessutom finns CreateMessage
det överlagringar som tar en XmlReader eller en XmlDictionaryReader som representerar hela meddelandet och inte bara brödtexten. Dessa överlagringar tar också en heltalsparameter maxSizeOfHeaders
. Rubriker buffras alltid i minnet så snart meddelandet har skapats, och den här parametern begränsar mängden buffring som sker. Det är viktigt att ange den här parametern till ett säkert värde om XML-koden kommer från en ej betrodd källa för att minska risken för överbelastningsattacker. SOAP- och WS-Adresseringsversionerna av meddelandet som XML-läsaren representerar måste matcha de versioner som anges med hjälp av versionsparametern.
Skapa meddelanden med BodyWriter
En CreateMessage
överlagring tar en BodyWriter
instans för att beskriva meddelandets brödtext. A BodyWriter
är en abstrakt klass som kan härledas för att anpassa hur meddelandetexter skapas. Du kan skapa en egen BodyWriter
härledd klass för att beskriva meddelandekroppar på ett anpassat sätt. Du måste åsidosätta den BodyWriter.OnWriteBodyContents
metod som tar en XmlDictionaryWriter. Den här metoden ansvarar för att skriva ut brödtexten.
Brödtextskrivare kan buffrade eller icke-buffrade (strömmade). Buffrade brödtextskrivare kan skriva ut sitt innehåll valfritt antal gånger, medan strömmade kan skriva ut sitt innehåll bara en gång. Egenskapen IsBuffered
anger om en brödtextskrivare är buffrad eller inte. Du kan ange detta för brödtextskrivaren genom att anropa den skyddade BodyWriter
konstruktorn som tar en isBuffered
boolesk parameter. Brödtextskrivare stöder skapandet av en buffrad brödtextskrivare från en icke-buffrad brödtextskrivare. Du kan åsidosätta OnCreateBufferedCopy
metoden för att anpassa den här processen. Som standard används en minnesintern buffert som innehåller DEN XML som returneras av OnWriteBodyContents
. OnCreateBufferedCopy
tar en maxBufferSize
heltalsparameter. Om du åsidosätter den här metoden får du inte skapa buffertar som är större än den här maximala storleken.
Klassen BodyWriter
innehåller WriteBodyContents
metoderna ochCreateBufferedCopy
, som i huvudsak är tunna omslutningar och OnCreateBufferedCopy
OnWriteBodyContents
metoder. Dessa metoder utför tillståndskontroll för att säkerställa att en icke-buffrad brödtextskrivare inte används mer än en gång. Dessa metoder anropas endast direkt när anpassade Message
härledda klasser skapas baserat på BodyWriters
.
Skapa felmeddelanden
Du kan använda vissa CreateMessage
överlagringar för att skapa SOAP-felmeddelanden. Det mest grundläggande av dessa är ett MessageFault objekt som beskriver felet. Andra överlagringar tillhandahålls för enkelhetens skull. Den första överlagringen tar en FaultCode
och en orsakssträng och skapar en MessageFault
användning med MessageFault.CreateFault
hjälp av den här informationen. Den andra överlagringen tar ett detaljobjekt och skickar det även till CreateFault
tillsammans med felkoden och orsaken. Följande åtgärd returnerar till exempel ett fel.
public class MyService3 : IMyService
{
public Message GetData()
{
FaultCode fc = new FaultCode("Receiver");
MessageVersion ver = OperationContext.Current.IncomingMessageVersion;
return Message.CreateMessage(ver,fc,"Bad data","GetDataResponse");
}
public void PutData(Message m)
{
// Not implemented.
}
}
Public Class MyService3
Implements IMyService
Public Function GetData() As Message Implements IMyService.GetData
Dim fc As New FaultCode("Receiver")
Dim ver As MessageVersion = OperationContext.Current.IncomingMessageVersion
Return Message.CreateMessage(ver, fc, "Bad data", "GetDataResponse")
End Function
Public Sub PutData(ByVal m As Message) Implements IMyService.PutData
End Sub
End Class
Extrahera meddelandetextdata
Klassen Message
stöder flera sätt att extrahera information från dess brödtext. Dessa kan klassificeras i följande kategorier:
Hela meddelandetexten skrivs ut på en gång till en XML-skrivare. Detta kallas för att skriva ett meddelande.
Hämta en XML-läsare över meddelandetexten. På så sätt kan du senare komma åt meddelandetexten bit för bit efter behov. Detta kallas för att läsa ett meddelande.
Hela meddelandet, inklusive dess brödtext, kan kopieras till en minnesintern buffert av typen MessageBuffer . Detta kallas för att kopiera ett meddelande.
Du kan bara komma åt brödtexten för en Message
enda gång, oavsett hur den nås. Ett meddelandeobjekt har en State
egenskap som ursprungligen är inställd på Skapad. De tre åtkomstmetoderna som beskrivs i föregående lista anger tillståndet till Skrivet, Läst respektive Kopierat. Dessutom kan en Close
metod ställa in tillståndet till Stängd när innehållet i meddelandetexten inte längre krävs. Meddelandetexten kan endast nås i tillståndet Skapad och det går inte att gå tillbaka till tillståndet Skapad när tillståndet har ändrats.
Skriva meddelanden
Metoden WriteBodyContents(XmlDictionaryWriter) skriver ut brödtextinnehållet i en viss Message
instans till en viss XML-skrivare. Metoden WriteBody gör samma sak, förutom att den omsluter brödtextinnehållet i lämpligt omslutningselement (till exempel <soap:body>
). WriteMessage Slutligen skriver du ut hela meddelandet, inklusive det omslutande SOAP-kuvertet och rubrikerna. Om SOAP är inaktiverat (Version är MessageVersion.None), gör alla tre metoderna samma sak: de skriver ut innehållet i meddelandetexten.
Följande kod skriver till exempel ut brödtexten i ett inkommande meddelande till en fil.
public class MyService4 : IMyService
{
public void PutData(Message m)
{
FileStream stream = new FileStream("myfile.xml",FileMode.Create);
XmlDictionaryWriter xdw =
XmlDictionaryWriter.CreateTextWriter(stream);
m.WriteBodyContents(xdw);
xdw.Flush();
}
public Message GetData()
{
throw new NotImplementedException();
}
}
Public Class MyService4
Implements IMyService
Public Sub PutData(ByVal m As Message) Implements IMyService.PutData
Dim stream As New FileStream("myfile.xml", FileMode.Create)
Dim xdw As XmlDictionaryWriter = XmlDictionaryWriter.CreateTextWriter(stream)
m.WriteBodyContents(xdw)
xdw.Flush()
End Sub
Public Function GetData() As Message Implements IMyService.GetData
Throw New NotImplementedException()
End Function
End Class
Ytterligare två hjälpmetoder skriver ut vissa SOAP-startelementtaggar. Dessa metoder har inte åtkomst till meddelandetexten och ändrar därför inte meddelandetillståndet. Dessa kan vara:
WriteStartBody skriver elementet starttext, till exempel
<soap:Body>
.WriteStartEnvelope skriver elementet startkuvert, till exempel
<soap:Envelope>
.
Om du vill skriva motsvarande slutelementtaggar anropar du WriteEndElement
motsvarande XML-skrivare. Dessa metoder kallas sällan direkt.
Läsa meddelanden
Det primära sättet att läsa en meddelandetext är att anropa GetReaderAtBodyContents. Du får tillbaka en XmlDictionaryReader som du kan använda för att läsa meddelandetexten. Observera att Message övergår till lästillståndet så snart som GetReaderAtBodyContents anropas och inte när du använder den returnerade XML-läsaren.
Med GetBody metoden kan du också komma åt meddelandetexten som ett skrivet objekt. Internt använder GetReaderAtBodyContents
den här metoden , och därför övergår även meddelandetillståndet Read till tillståndet (se egenskapen State ).
Det är bra att kontrollera egenskapen IsEmpty , i vilket fall meddelandetexten är tom och GetReaderAtBodyContents genererar en InvalidOperationException. Om det är ett mottaget meddelande (till exempel svaret) kanske du också vill kontrollera IsFault, vilket anger om meddelandet innehåller ett fel.
Den mest grundläggande överbelastningen av GetBody deserialiserar meddelandetexten till en instans av en typ (som anges av den generiska parametern) med hjälp av en DataContractSerializer konfigurerad med standardinställningarna och med MaxItemsInObjectGraph kvoten inaktiverad. Om du vill använda en annan serialiseringsmotor eller konfigurera på DataContractSerializer
ett sätt som inte är standard använder du överbelastningen GetBody som tar en XmlObjectSerializer.
Följande kod extraherar till exempel data från en meddelandetext som innehåller ett serialiserat Person
objekt och skriver ut personens namn.
public class MyService5 : IMyService
{
public void PutData(Message m)
{
Person p = m.GetBody<Person>();
Console.WriteLine(p.name);
}
public Message GetData()
{
throw new NotImplementedException();
}
}
}
namespace Samples2
{
[ServiceContract]
public interface IMyService
{
[OperationContract]
Message GetData();
[OperationContract]
void PutData(Message m);
}
[DataContract]
public class Person
{
[DataMember] public string name;
[DataMember] public int age;
}
Public Class MyService5
Implements IMyService
Public Sub PutData(ByVal m As Message) Implements IMyService.PutData
Dim p As Person = m.GetBody(Of Person)()
Console.WriteLine(p.name)
End Sub
Public Function GetData() As Message Implements IMyService.GetData
Throw New NotImplementedException()
End Function
End Class
End Namespace
Namespace Samples2
<ServiceContract()> _
Public Interface IMyService
<OperationContract()> _
Function GetData() As Message
<OperationContract()> _
Sub PutData(ByVal m As Message)
End Interface
<DataContract()> _
Public Class Person
<DataMember()> _
Public name As String
<DataMember()> _
Public age As Integer
End Class
Kopiera ett meddelande till en buffert
Ibland är det nödvändigt att komma åt meddelandetexten mer än en gång, till exempel för att vidarebefordra samma meddelande till flera mål som en del av ett publisher-subscriber-system. I det här fallet är det nödvändigt att buffrar hela meddelandet (inklusive brödtexten) i minnet. Du kan göra detta genom att anropa CreateBufferedCopy(Int32). Den här metoden tar en heltalsparameter som representerar den maximala buffertstorleken och skapar en buffert som inte är större än den här storleken. Det är viktigt att ange detta till ett säkert värde om meddelandet kommer från en ej betrodd källa.
Bufferten returneras som en MessageBuffer instans. Du kan komma åt data i bufferten på flera sätt. Det primära sättet är att anropa CreateMessage för att skapa Message
instanser från bufferten.
Ett annat sätt att komma åt data i bufferten är att implementera IXPathNavigable det gränssnitt som MessageBuffer klassen implementerar för direkt åtkomst till den underliggande XML:en. Vissa CreateNavigator överlagringar gör att du kan skapa System.Xml.XPath navigatörer som skyddas av en nodkvot, vilket begränsar antalet XML-noder som kan besökas. Detta hjälper till att förhindra överbelastningsattacker baserat på lång bearbetningstid. Det här citatt är inaktiverat som standard. Med vissa CreateNavigator
överlagringar kan du ange hur tomt utrymme ska hanteras i XML-koden med uppräkningen XmlSpace , där standardvärdet är XmlSpace.None
.
Ett sista sätt att komma åt innehållet i en meddelandebuffert är att skriva ut innehållet till en dataström med hjälp av WriteMessage.
I följande exempel visas processen att arbeta med ett MessageBuffer
: ett inkommande meddelande vidarebefordras till flera mottagare och loggas sedan till en fil. Utan buffring är detta inte möjligt eftersom meddelandetexten sedan bara kan nås en gång.
[ServiceContract]
public class ForwardingService
{
private List<IOutputChannel> forwardingAddresses;
[OperationContract]
public void ForwardMessage (Message m)
{
//Copy the message to a buffer.
MessageBuffer mb = m.CreateBufferedCopy(65536);
//Forward to multiple recipients.
foreach (IOutputChannel channel in forwardingAddresses)
{
Message copy = mb.CreateMessage();
channel.Send(copy);
}
//Log to a file.
FileStream stream = new FileStream("log.xml",FileMode.Append);
mb.WriteMessage(stream);
stream.Flush();
}
}
<ServiceContract()> _
Public Class ForwardingService
Private forwardingAddresses As List(Of IOutputChannel)
<OperationContract()> _
Public Sub ForwardMessage(ByVal m As Message)
'Copy the message to a buffer.
Dim mb As MessageBuffer = m.CreateBufferedCopy(65536)
'Forward to multiple recipients.
Dim channel As IOutputChannel
For Each channel In forwardingAddresses
Dim copy As Message = mb.CreateMessage()
channel.Send(copy)
Next channel
'Log to a file.
Dim stream As New FileStream("log.xml", FileMode.Append)
mb.WriteMessage(stream)
stream.Flush()
End Sub
End Class
Klassen MessageBuffer
har andra medlemmar som är värda att notera. Metoden Close kan anropas för att frigöra resurser när buffertinnehållet inte längre krävs. Egenskapen BufferSize returnerar storleken på den allokerade bufferten. Egenskapen MessageContentType returnerar MIME-innehållstypen för meddelandet.
Komma åt meddelandetexten för felsökning
I felsökningssyfte kan du anropa ToString metoden för att få en representation av meddelandet som en sträng. Den här representationen matchar vanligtvis hur ett meddelande skulle se ut på tråden om det kodades med textkodaren, förutom att XML-koden skulle vara bättre formaterad för mänsklig läsbarhet. Det enda undantaget är meddelandetexten. Brödtexten kan bara läsas en gång och ToString
ändrar inte meddelandetillståndet. ToString
Därför kanske metoden inte kan komma åt brödtexten och kan ersätta en platshållare (till exempel "..." eller tre punkter) i stället för meddelandetexten. Använd därför inte ToString
för att logga meddelanden om brödtextinnehållet i meddelandena är viktigt.
Komma åt andra meddelandedelar
Olika egenskaper tillhandahålls för att komma åt information om det andra meddelandet än dess brödtextinnehåll. Dessa kan dock inte anropas när meddelandet har stängts:
Egenskapen Headers representerar meddelanderubrikerna. Se avsnittet "Arbeta med rubriker" senare i det här avsnittet.
Egenskapen Properties representerar meddelandeegenskaperna, som är delar av namngivna data som är kopplade till meddelandet som vanligtvis inte genereras när meddelandet skickas. Se avsnittet "Arbeta med egenskaper" senare i det här avsnittet.
Egenskapen Version anger den SOAP- och WS-Adresseringsversion som är associerad med meddelandet, eller
None
om SOAP är inaktiverat.Egenskapen IsFault returnerar
true
om meddelandet är ett SOAP-felmeddelande.Egenskapen IsEmpty returnerar
true
om meddelandet är tomt.
Du kan använda GetBodyAttribute(String, String) metoden för att komma åt ett visst attribut i brödtextomslutningselementet (till exempel <soap:Body>
) som identifieras med ett visst namn och namnområde. Om ett sådant attribut inte hittas null
returneras. Den här metoden kan bara anropas när Message
är i tillståndet Skapad (när meddelandetexten ännu inte har använts).
Arbeta med rubriker
A Message
kan innehålla valfritt antal namngivna XML-fragment, som kallas rubriker. Varje fragment mappar normalt till en SOAP-rubrik. Rubriker nås via Headers
egenskapen av typen MessageHeaders. MessageHeaders är en samling MessageHeaderInfo objekt och enskilda rubriker kan nås via dess IEnumerable gränssnitt eller via dess indexerare. Följande kod visar till exempel namnen på alla rubriker i en Message
.
public class MyService6 : IMyService
{
public void PutData(Message m)
{
foreach (MessageHeaderInfo mhi in m.Headers)
{
Console.WriteLine(mhi.Name);
}
}
public Message GetData()
{
throw new NotImplementedException();
}
}
Public Class MyService6
Implements IMyService
Public Sub PutData(ByVal m As Message) Implements IMyService.PutData
Dim mhi As MessageHeaderInfo
For Each mhi In m.Headers
Console.WriteLine(mhi.Name)
Next mhi
End Sub
Public Function GetData() As Message Implements IMyService.GetData
Throw New NotImplementedException()
End Function
End Class
Lägga till, ta bort, hitta rubriker
Du kan lägga till en ny rubrik i slutet av alla befintliga rubriker med hjälp av Add metoden . Du kan använda Insert metoden för att infoga ett huvud i ett visst index. Befintliga rubriker flyttas för det infogade objektet. Rubrikerna sorteras enligt deras index och det första tillgängliga indexet är 0. Du kan använda de olika CopyHeadersFrom metodöverlagringarna för att lägga till rubriker från en annan Message
instans eller MessageHeaders
instans. Vissa överlagringar kopierar en enskild rubrik, medan andra kopierar dem alla. Metoden Clear tar bort alla rubriker. Metoden RemoveAt tar bort ett huvud vid ett visst index (flyttar alla rubriker efter det). Metoden RemoveAll tar bort alla rubriker med ett visst namn och namnområde.
Hämta en viss rubrik med hjälp av FindHeader metoden . Den här metoden tar namnet och namnområdet för huvudet för att hitta och returnerar dess index. Om rubriken inträffar mer än en gång genereras ett undantag. Om rubriken inte hittas returneras -1.
I SOAP-huvudmodellen kan rubriker ha ett Actor
värde som anger den avsedda mottagaren av huvudet. De mest grundläggande FindHeader
överlagringssökningarna söker bara rubriker som är avsedda för den ultimata mottagaren av meddelandet. Men med en annan överlagring kan du ange vilka värden som Actor
ingår i sökningen. Mer information finns i SOAP-specifikationen.
En CopyTo(MessageHeaderInfo[], Int32) metod tillhandahålls för att kopiera rubriker från en MessageHeaders samling till en matris med MessageHeaderInfo objekt.
Om du vill komma åt XML-data i en rubrik kan du anropa GetReaderAtHeader och returnera en XML-läsare för det specifika huvudindexet. Om du vill deserialisera rubrikinnehållet till ett objekt använder GetHeader<T>(Int32) du eller någon av de andra överlagringarna. De mest grundläggande överlagringarna deserialiserar rubriker med hjälp av det DataContractSerializer konfigurerade på standardsättet. Om du vill använda en annan serialiserare eller en annan konfiguration av DataContractSerializer
använder du en av de överlagringar som tar en XmlObjectSerializer
. Det finns också överlagringar som tar rubriknamnet, namnområdet och eventuellt en lista med Actor
värden i stället för ett index. Detta är en kombination av FindHeader
och GetHeader
.
Arbeta med egenskaper
En Message
instans kan innehålla ett godtyckligt antal namngivna objekt av godtyckliga typer. Den här samlingen nås via Properties
egenskapen av typen MessageProperties
. Samlingen implementerar IDictionary<TKey,TValue> gränssnittet och fungerar som en mappning från String till Object. Normalt mappas inte egenskapsvärden direkt till någon del av meddelandet på tråden, utan ger snarare olika tips för meddelandebearbetning till de olika kanalerna i WCF-kanalstacken eller till CopyTo(MessageHeaderInfo[], Int32) tjänstramverket. Ett exempel finns i Översikt över arkitektur för dataöverföring.
Ärver från meddelandeklassen
Om de inbyggda meddelandetyperna som skapas med CreateMessage
inte uppfyller dina krav skapar du en klass som härleds från Message
klassen.
Definiera innehållet i meddelandetexten
Det finns tre huvudsakliga metoder för att komma åt data i en meddelandetext: skriva, läsa och kopiera dem till en buffert. De här åtgärderna resulterar slutligen i OnWriteBodyContentsatt metoderna , OnGetReaderAtBodyContentsoch OnCreateBufferedCopy anropas på din härledda klass av Message
. Basklassen Message
garanterar att endast en av dessa metoder anropas för varje Message
instans och att den inte anropas mer än en gång. Basklassen säkerställer också att metoderna inte anropas för ett stängt meddelande. Du behöver inte spåra meddelandetillståndet i implementeringen.
OnWriteBodyContents är en abstrakt metod och måste implementeras. Det mest grundläggande sättet att definiera brödtextinnehållet i meddelandet är att skriva med den här metoden. Följande meddelande innehåller till exempel 100 000 slumpmässiga tal från 1 till 20.
public class RandomMessage : Message
{
override protected void OnWriteBodyContents(XmlDictionaryWriter writer)
{
Random r = new Random();
for (int i = 0; i <100000; i++)
{
writer.WriteStartElement("number");
writer.WriteValue(r.Next(1,20));
writer.WriteEndElement();
}
}
//code omitted…
Public Class RandomMessage
Inherits Message
Protected Overrides Sub OnWriteBodyContents( _
ByVal writer As XmlDictionaryWriter)
Dim r As New Random()
Dim i As Integer
For i = 0 To 99999
writer.WriteStartElement("number")
writer.WriteValue(r.Next(1, 20))
writer.WriteEndElement()
Next i
End Sub
' Code omitted.
Metoderna OnGetReaderAtBodyContents() och OnCreateBufferedCopy har standardimplementeringar som fungerar i de flesta fall. Standardimplementeringarna anropar OnWriteBodyContents, buffrar resultaten och arbetar med den resulterande bufferten. I vissa fall kanske detta dock inte räcker. I föregående exempel resulterar läsning av meddelandet i att 100 000 XML-element buffrats, vilket kanske inte är önskvärt. Du kanske vill åsidosätta OnGetReaderAtBodyContents() för att returnera en anpassad härledd XmlDictionaryReader klass som hanterar slumpmässiga tal. Du kan sedan åsidosätta OnWriteBodyContents för att använda läsaren OnGetReaderAtBodyContents() som metoden returnerar, som du ser i följande exempel.
public override MessageHeaders Headers
{
get { throw new Exception("The method or operation is not implemented."); }
}
public override MessageProperties Properties
{
get { throw new Exception("The method or operation is not implemented."); }
}
public override MessageVersion Version
{
get { throw new Exception("The method or operation is not implemented."); }
}
}
public class RandomMessage2 : Message
{
override protected XmlDictionaryReader OnGetReaderAtBodyContents()
{
return new RandomNumbersXmlReader();
}
override protected void OnWriteBodyContents(XmlDictionaryWriter writer)
{
XmlDictionaryReader xdr = OnGetReaderAtBodyContents();
writer.WriteNode(xdr, true);
}
public override MessageHeaders Headers
{
get { throw new Exception("The method or operation is not implemented."); }
}
public override MessageProperties Properties
{
get { throw new Exception("The method or operation is not implemented."); }
}
public override MessageVersion Version
{
get { throw new Exception("The method or operation is not implemented."); }
}
}
public class RandomNumbersXmlReader : XmlDictionaryReader
{
//code to serve up 100000 random numbers in XML form omitted…
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 Properties() As MessageProperties
Get
Throw New Exception("The method or operation is not implemented.")
End Get
End Property
Public Overrides ReadOnly Property Version() As MessageVersion
Get
Throw New Exception("The method or operation is not implemented.")
End Get
End Property
End Class
Public Class RandomMessage2
Inherits Message
Protected Overrides Function OnGetReaderAtBodyContents() As XmlDictionaryReader
Return New RandomNumbersXmlReader()
End Function
Protected Overrides Sub OnWriteBodyContents(ByVal writer As XmlDictionaryWriter)
Dim xdr As XmlDictionaryReader = OnGetReaderAtBodyContents()
writer.WriteNode(xdr, True)
End Sub
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 Properties() As MessageProperties
Get
Throw New Exception("The method or operation is not implemented.")
End Get
End Property
Public Overrides ReadOnly Property Version() As MessageVersion
Get
Throw New Exception("The method or operation is not implemented.")
End Get
End Property
End Class
Public Class RandomNumbersXmlReader
Inherits XmlDictionaryReader
'code to serve up 100000 random numbers in XML form omitted
På samma sätt kanske du vill åsidosätta OnCreateBufferedCopy
för att returnera din egen MessageBuffer
härledda klass.
Förutom att tillhandahålla innehåll i meddelandetexten måste den härledda klassen även åsidosätta Version
egenskaperna , Headers
och Properties
.
Observera att om du skapar en kopia av ett meddelande använder kopian meddelanderubrikerna från originalet.
Andra medlemmar som kan åsidosättas
Du kan åsidosätta OnWriteStartEnvelopemetoderna , OnWriteStartHeadersoch OnWriteStartBody för att ange hur starttaggar för SOAP-kuvert, SOAP-huvuden och SOAP-brödtextelement skrivs ut. Dessa motsvarar <soap:Envelope>
normalt , <soap:Header>
och <soap:Body>
. Dessa metoder bör normalt inte skriva ut något om egenskapen Version returnerar None.
Kommentar
Standardimplementeringen av OnGetReaderAtBodyContents
anrop OnWriteStartEnvelope
och OnWriteStartBody
innan du anropar OnWriteBodyContents
och buffrar resultatet. Rubriker skrivs inte ut.
Åsidosätt OnWriteMessage metoden för att ändra hur hela meddelandet konstrueras från dess olika delar. Metoden OnWriteMessage
anropas från WriteMessage och från standardimplementeringen OnCreateBufferedCopy . Observera att åsidosättande WriteMessage inte är bästa praxis. Det är bättre att åsidosätta lämpliga On
metoder (till exempel OnWriteStartEnvelope, OnWriteStartHeadersoch OnWriteBodyContents.
Åsidosätt OnBodyToString för att åsidosätta hur meddelandetexten representeras under felsökningen. Standardvärdet är att representera det som tre punkter ("..."). Observera att den här metoden kan anropas flera gånger när meddelandetillståndet är något annat än Stängd. En implementering av den här metoden bör aldrig orsaka någon åtgärd som bara måste utföras en gång (till exempel att läsa från en dataström som endast är framåt).
Åsidosätt OnGetBodyAttribute metoden för att tillåta åtkomst till attribut i SOAP-brödtextelementet. Den här metoden kan kallas valfritt antal gånger, men Message
bastypen garanterar att den bara anropas när meddelandet är i tillståndet Skapad. Det krävs inte för att kontrollera tillståndet i en implementering. Standardimplementeringen returnerar null
alltid , vilket indikerar att det inte finns några attribut i brödtextelementet.
Om objektet Message
måste göra någon särskild rensning när meddelandetexten inte längre krävs kan du åsidosätta OnClose. Standardimplementeringen gör ingenting.
Egenskaperna IsEmpty
och IsFault
kan åsidosättas. Som standard returnerar false
båda .