De berichtklasse gebruiken
De Message klasse is fundamenteel voor Windows Communication Foundation (WCF). Alle communicatie tussen clients en services resulteert uiteindelijk in Message het verzenden en ontvangen van exemplaren.
Normaal gesproken zou u niet rechtstreeks met de Message klas communiceren. In plaats daarvan worden wcF-servicemodelconstructies, zoals gegevenscontracten, berichtcontracten en bewerkingscontracten, gebruikt om binnenkomende en uitgaande berichten te beschrijven. In sommige geavanceerde scenario's kunt u echter de Message klasse rechtstreeks programmeren. U kunt bijvoorbeeld de Message klasse gebruiken:
Wanneer u een alternatieve manier nodig hebt om uitgaande berichtinhoud te maken (bijvoorbeeld het rechtstreeks vanuit een bestand op schijf maken) in plaats van .NET Framework-objecten te serialiseren.
Wanneer u een alternatieve manier nodig hebt om de inhoud van binnenkomende berichten te gebruiken (bijvoorbeeld wanneer u een XSLT-transformatie wilt toepassen op de onbewerkte XML-inhoud) in plaats van deserialiseren in .NET Framework-objecten.
Wanneer u berichten op een algemene manier moet verwerken, ongeacht de inhoud van berichten (bijvoorbeeld wanneer u berichten routert of doorstuurt bij het bouwen van een router, load balancer of een systeem voor publiceren/abonneren).
Voordat u de Message klasse gebruikt, moet u vertrouwd raken met de WCF-architectuur voor gegevensoverdracht in het architectuuroverzicht van gegevensoverdracht.
A Message is een container voor algemeen gebruik voor gegevens, maar het ontwerp volgt het ontwerp van een bericht in het SOAP-protocol nauw. Net als in SOAP heeft een bericht zowel een berichttekst als kopteksten. De hoofdtekst van het bericht bevat de werkelijke nettoladinggegevens, terwijl de headers extra benoemde gegevenscontainers bevatten. De regels voor het lezen en schrijven van de hoofdtekst en de kopteksten zijn bijvoorbeeld verschillend, de headers worden altijd gebufferd in het geheugen en kunnen in willekeurige volgorde worden geopend, terwijl de hoofdtekst slechts één keer kan worden gelezen en kan worden gestreamd. Normaal gesproken wordt de hoofdtekst van het bericht toegewezen aan de SOAP-hoofdtekst en worden de berichtkoppen toegewezen aan de SOAP-headers.
De berichtklasse gebruiken in bewerkingen
U kunt de Message klasse gebruiken als invoerparameter van een bewerking, de retourwaarde van een bewerking of beide. Als Message er ergens in een bewerking wordt gebruikt, zijn de volgende beperkingen van toepassing:
De bewerking kan geen of
out
ref
parameters bevatten.Er mogen niet meer dan één
input
parameter zijn. Als de parameter aanwezig is, moet dit bericht of een berichtcontracttype zijn.Het retourtype moet ofwel ,
Message
of een berichtcontracttype zijnvoid
.
Het volgende codevoorbeeld bevat een geldig bewerkingscontract.
[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
Basisberichten maken
De Message klasse biedt statische CreateMessage
factory-methoden die u kunt gebruiken om basisberichten te maken.
Alle CreateMessage
overbelastingen hebben een versieparameter van het type MessageVersion die aangeeft welke SOAP- en WS-Adresseringsversies voor het bericht moeten worden gebruikt. Als u dezelfde protocolversies wilt gebruiken als het binnenkomende bericht, kunt u de IncomingMessageVersion eigenschap gebruiken op het OperationContext exemplaar dat u hebt verkregen uit de Current eigenschap. De meeste CreateMessage
overbelastingen hebben ook een tekenreeksparameter die aangeeft dat de SOAP-actie moet worden gebruikt voor het bericht. De versie kan worden ingesteld om soap-envelopgeneratie uit te None
schakelen. Het bericht bestaat alleen uit de hoofdtekst.
Berichten van objecten maken
De meest eenvoudige CreateMessage
overbelasting die slechts een versie gebruikt en een actie maakt een bericht met een lege hoofdtekst. Een andere overbelasting heeft een extra Object parameter. Hiermee wordt een bericht gemaakt waarvan de hoofdtekst de geserialiseerde weergave van het opgegeven object is. Gebruik de DataContractSerializer standaardinstellingen voor serialisatie. Als u een andere serialisatiefunctie wilt gebruiken of als u de DataContractSerializer
geconfigureerde anders wilt configureren, gebruikt u de CreateMessage
overbelasting die ook een XmlObjectSerializer
parameter gebruikt.
Als u bijvoorbeeld een object in een bericht wilt retourneren, kunt u de volgende code gebruiken.
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
Berichten maken van XML-lezers
Er zijn CreateMessage
overbelastingen die een XmlReader of een XmlDictionaryReader voor de hoofdtekst innemen in plaats van een object. In dit geval bevat de hoofdtekst van het bericht de XML die het resultaat is van het lezen van de doorgegeven XML-lezer. De volgende code retourneert bijvoorbeeld een bericht met de hoofdtekst die is gelezen uit een XML-bestand.
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
Daarnaast zijn CreateMessage
er overbelastingen die een XmlReader of een XmlDictionaryReader die het hele bericht vertegenwoordigen en niet alleen de hoofdtekst. Deze overbelastingen hebben ook een geheel getalparameter maxSizeOfHeaders
. Headers worden altijd in het geheugen gebufferd zodra het bericht is gemaakt en deze parameter beperkt de hoeveelheid buffering die plaatsvindt. Het is belangrijk om deze parameter in te stellen op een veilige waarde als de XML afkomstig is van een niet-vertrouwde bron om de mogelijkheid van een Denial of Service-aanval te beperken. De SOAP- en WS-Adresseringsversies van het bericht die de XML-lezer vertegenwoordigt, moeten overeenkomen met de versies die worden aangegeven met behulp van de versieparameter.
Berichten maken met BodyWriter
Eén CreateMessage
overbelasting neemt een BodyWriter
exemplaar om de hoofdtekst van het bericht te beschrijven. A BodyWriter
is een abstracte klasse die kan worden afgeleid om aan te passen hoe berichtteksten worden gemaakt. U kunt uw eigen BodyWriter
afgeleide klasse maken om berichtteksten op een aangepaste manier te beschrijven. U moet de BodyWriter.OnWriteBodyContents
methode die een XmlDictionaryWritergebruikt, overschrijven. Deze methode is verantwoordelijk voor het schrijven van de hoofdtekst.
Hoofdtekstschrijvers kunnen worden gebufferd of niet-gebufferd (gestreamd). Schrijvers van gebufferde lichamen kunnen hun inhoud op elk gewenst moment uitschrijven, terwijl gestreamde personen hun inhoud slechts één keer kunnen uitschrijven. De IsBuffered
eigenschap geeft aan of een body writer is gebufferd of niet. U kunt dit instellen voor uw hoofdtekstschrijver door de beveiligde BodyWriter
constructor aan te roepen die een isBuffered
booleaanse parameter gebruikt. Hoofdschrijvers ondersteunen het maken van een gebufferde lichaamschrijver van een niet-gebufferde lichaamschrijver. U kunt de OnCreateBufferedCopy
methode overschrijven om dit proces aan te passen. Standaard wordt een in-memory buffer gebruikt die de XML bevat die wordt geretourneerd door OnWriteBodyContents
. OnCreateBufferedCopy
neemt een maxBufferSize
geheel getalparameter. Als u deze methode overschrijft, moet u geen buffers maken die groter zijn dan deze maximale grootte.
De BodyWriter
klasse biedt de WriteBodyContents
en CreateBufferedCopy
methoden, die in wezen dunne wrappers OnWriteBodyContents
zijn en OnCreateBufferedCopy
methoden, respectievelijk. Met deze methoden wordt statuscontrole uitgevoerd om ervoor te zorgen dat een niet-gebufferde body writer niet meer dan één keer wordt geopend. Deze methoden worden alleen rechtstreeks aangeroepen bij het maken van aangepaste Message
afgeleide klassen op BodyWriters
basis van .
Foutberichten maken
U kunt bepaalde CreateMessage
overbelastingen gebruiken om SOAP-foutberichten te maken. De meest elementaire hiervan is een MessageFault object dat de fout beschrijft. Andere overbelastingen worden voor het gemak geboden. De eerste dergelijke overbelasting neemt een FaultCode
en een redentekenreeks en maakt een MessageFault
gebruik van MessageFault.CreateFault
deze informatie. De andere overbelasting neemt een detailobject en geeft het ook door aan CreateFault
samen met de foutcode en de reden. Met de volgende bewerking wordt bijvoorbeeld een fout geretourneerd.
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
Berichttekstgegevens extraheren
De Message
klasse ondersteunt meerdere manieren om informatie uit de hoofdtekst te extraheren. Deze kunnen worden geclassificeerd in de volgende categorieën:
De volledige berichttekst in één keer naar een XML-schrijver laten schrijven. Dit wordt een bericht geschreven.
Een XML-lezer over de hoofdtekst van het bericht halen. Hierdoor hebt u later toegang tot de hoofdtekst van het bericht, indien nodig. Dit wordt een bericht gelezen.
Het hele bericht, inclusief de hoofdtekst, kan worden gekopieerd naar een buffer in het geheugen van het MessageBuffer type. Dit wordt het kopiëren van een bericht genoemd.
U hebt slechts eenmaal toegang tot de hoofdtekst Message
, ongeacht hoe deze wordt geopend. Een berichtobject heeft een State
eigenschap die in eerste instantie is ingesteld op Gemaakt. Met de drie toegangsmethoden die in de voorgaande lijst worden beschreven, wordt de status respectievelijk ingesteld op Geschreven, Gelezen en Gekopieerd. Daarnaast kan een Close
methode de status instellen op Gesloten wanneer de hoofdtekst van het bericht niet meer nodig is. De hoofdtekst van het bericht kan alleen worden geopend in de status Gemaakt en er is geen manier om terug te gaan naar de status Gemaakt nadat de status is gewijzigd.
Berichten schrijven
Met WriteBodyContents(XmlDictionaryWriter) de methode wordt de hoofdinhoud van een bepaald Message
exemplaar weggeschreven naar een bepaalde XML-schrijver. De WriteBody methode doet hetzelfde, behalve dat deze de hoofdtekstinhoud in het juiste wrapper-element plaatst (bijvoorbeeld <soap:body>
). Ten slotte WriteMessage schrijft u het hele bericht uit, inclusief de soap-envelop en de kopteksten. Als SOAP is uitgeschakeld (Version is MessageVersion.None), doen alle drie de methoden hetzelfde: ze schrijven de hoofdtekst van het bericht op.
Met de volgende code wordt bijvoorbeeld de hoofdtekst van een binnenkomend bericht naar een bestand geschreven.
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
Twee extra helpermethoden schrijven bepaalde SOAP start-elementtags uit. Deze methoden hebben geen toegang tot de berichttekst en dus wijzigen ze de berichtstatus niet. Deze omvatten:
WriteStartBody schrijft het hoofdtekstelement van het begin, bijvoorbeeld
<soap:Body>
.WriteStartEnvelope schrijft bijvoorbeeld het begin-envelopelement
<soap:Envelope>
.
Als u de bijbehorende tags voor eindelementen wilt schrijven, roept WriteEndElement
u de bijbehorende XML-schrijver aan. Deze methoden worden zelden rechtstreeks aangeroepen.
Berichten lezen
De primaire manier om een berichttekst te lezen, is door te bellen GetReaderAtBodyContents. U krijgt een XmlDictionaryReader bericht dat u kunt gebruiken om de hoofdtekst van het bericht te lezen. Houd er rekening mee dat de Message overgangen naar de leesstatus zodra GetReaderAtBodyContents deze worden aangeroepen en niet wanneer u de geretourneerde XML-lezer gebruikt.
Met de GetBody methode kunt u ook toegang krijgen tot de hoofdtekst van het bericht als een getypt object. Intern gebruikt GetReaderAtBodyContents
deze methode en wordt de berichtstatus dus ook overgemaakt naar de Read status (zie de State eigenschap).
Het is een goede gewoonte om de IsEmpty eigenschap te controleren, in welk geval de hoofdtekst van het bericht leeg is en GetReaderAtBodyContents een InvalidOperationException. Als het een ontvangen bericht is (bijvoorbeeld het antwoord), kunt u ook controleren IsFaultof het bericht een fout bevat.
De meest eenvoudige overbelasting van deserialisatie van de hoofdtekst van GetBody het bericht in een exemplaar van een type (aangegeven door de algemene parameter) met behulp van een DataContractSerializer geconfigureerd met de standaardinstellingen en met het MaxItemsInObjectGraph quotum uitgeschakeld. Als u een andere serialisatie-engine wilt gebruiken of de DataContractSerializer
engine op een niet-standaard manier wilt configureren, gebruikt u de GetBody overbelasting die een XmlObjectSerializer.
Met de volgende code worden bijvoorbeeld gegevens geëxtraheerd uit een berichttekst die een geserialiseerd Person
object bevat en worden de naam van de persoon afgedrukt.
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
Een bericht naar een buffer kopiëren
Soms is het nodig om meerdere keren toegang te krijgen tot de berichttekst, bijvoorbeeld om hetzelfde bericht door te sturen naar meerdere bestemmingen als onderdeel van een uitgeversabonneesysteem. In dit geval is het noodzakelijk om het hele bericht (inclusief de hoofdtekst) in het geheugen te bufferen. U kunt dit doen door te bellen CreateBufferedCopy(Int32). Deze methode gebruikt een geheel getalparameter die de maximale buffergrootte vertegenwoordigt en maakt een buffer die niet groter is dan deze grootte. Het is belangrijk om dit in te stellen op een veilige waarde als het bericht afkomstig is van een niet-vertrouwde bron.
De buffer wordt geretourneerd als een MessageBuffer exemplaar. U kunt op verschillende manieren toegang krijgen tot gegevens in de buffer. De primaire manier is om CreateMessage exemplaren te maken Message
vanuit de buffer.
Een andere manier om toegang te krijgen tot de gegevens in de buffer is door de IXPathNavigable interface te implementeren die door de MessageBuffer klasse wordt geïmplementeerd om rechtstreeks toegang te krijgen tot de onderliggende XML. Met sommige CreateNavigator overbelastingen kunt u navigators maken System.Xml.XPath die worden beveiligd door een knooppuntquotum, waardoor het aantal XML-knooppunten dat kan worden bezocht, wordt beperkt. Dit helpt denial of service-aanvallen te voorkomen op basis van een lange verwerkingstijd. Deze aanhalingsteken is standaard uitgeschakeld. Met sommige CreateNavigator
overbelastingen kunt u opgeven hoe witruimte in de XML moet worden verwerkt met behulp van de XmlSpace opsomming, waarbij de standaardwaarde is XmlSpace.None
.
Een laatste manier om toegang te krijgen tot de inhoud van een berichtbuffer is door de inhoud ervan naar een stream te schrijven met behulp van WriteMessage.
In het volgende voorbeeld ziet u hoe u met een MessageBuffer
: een binnenkomend bericht wordt doorgestuurd naar meerdere geadresseerden en vervolgens bent aangemeld bij een bestand. Zonder buffering is dit niet mogelijk, omdat de hoofdtekst van het bericht vervolgens slechts één keer kan worden geopend.
[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
De MessageBuffer
klas heeft andere leden die het vermelden waard zijn. De Close methode kan worden aangeroepen voor gratis resources wanneer de bufferinhoud niet meer nodig is. De BufferSize eigenschap retourneert de grootte van de toegewezen buffer. De MessageContentType eigenschap retourneert het MIME-inhoudstype van het bericht.
Toegang tot de berichttekst voor foutopsporing
Voor foutopsporing kunt u de ToString methode aanroepen om een weergave van het bericht als een tekenreeks op te halen. Deze weergave komt over het algemeen overeen met de manier waarop een bericht op de draad zou lijken als het is gecodeerd met de tekstcoderingsprogramma, behalve dat de XML beter zou zijn opgemaakt voor menselijke leesbaarheid. De enige uitzondering hierop is de hoofdtekst van het bericht. De hoofdtekst kan slechts eenmaal worden gelezen en ToString
wijzigt de berichtstatus niet. Daarom heeft de ToString
methode mogelijk geen toegang tot de hoofdtekst en kan deze een tijdelijke aanduiding vervangen (bijvoorbeeld '...'. of drie puntjes) in plaats van de hoofdtekst van het bericht. Gebruik daarom geen ToString
logboekberichten als de hoofdtekst van de berichten belangrijk is.
Toegang tot andere berichtonderdelen
Er zijn verschillende eigenschappen beschikbaar voor toegang tot informatie over het andere bericht dan de hoofdinhoud. Deze kunnen echter niet worden aangeroepen zodra het bericht is gesloten:
De Headers eigenschap vertegenwoordigt de berichtkoppen. Zie de sectie 'Werken met kopteksten' verderop in dit onderwerp.
De Properties eigenschap vertegenwoordigt de berichteigenschappen, die stukjes benoemde gegevens zijn die zijn gekoppeld aan het bericht dat doorgaans niet wordt verzonden wanneer het bericht wordt verzonden. Zie de sectie 'Werken met eigenschappen' verderop in dit onderwerp.
De Version eigenschap geeft de SOAP- en WS-Adresseringsversie aan die is gekoppeld aan het bericht, of
None
als SOAP is uitgeschakeld.De IsFault eigenschap retourneert
true
als het bericht een SOAP-foutbericht is.De IsEmpty eigenschap retourneert
true
als het bericht leeg is.
U kunt de GetBodyAttribute(String, String) methode gebruiken om toegang te krijgen tot een bepaald kenmerk op het body wrapper-element (bijvoorbeeld <soap:Body>
) dat is geïdentificeerd door een bepaalde naam en naamruimte. Als een dergelijk kenmerk niet wordt gevonden, null
wordt deze geretourneerd. Deze methode kan alleen worden aangeroepen wanneer de Message
status Gemaakt heeft (wanneer de hoofdtekst van het bericht nog niet is geopend).
Werken met kopteksten
Een Message
kan een willekeurig aantal benoemde XML-fragmenten bevatten, kopteksten genoemd. Elk fragment wordt normaal gesproken toegewezen aan een SOAP-header. Headers worden geopend via de eigenschap van het Headers
type MessageHeaders. MessageHeaders is een verzameling MessageHeaderInfo objecten en afzonderlijke headers kunnen worden geopend via de IEnumerable interface of via de indexeerfunctie. De volgende code bevat bijvoorbeeld de namen van alle headers in een 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
Kopteksten toevoegen, verwijderen, zoeken
U kunt een nieuwe koptekst toevoegen aan het einde van alle bestaande headers met behulp van de Add methode. U kunt de Insert methode gebruiken om een header in te voegen bij een bepaalde index. Bestaande kopteksten worden verplaatst voor het ingevoegde item. Headers worden gerangschikt op basis van hun index en de eerste beschikbare index is 0. U kunt de verschillende CopyHeadersFrom methodeoverbelastingen gebruiken om headers van een ander Message
exemplaar toe MessageHeaders
te voegen. Sommige overbelastingen kopiëren één afzonderlijke koptekst, terwijl anderen ze allemaal kopiëren. Met de Clear methode worden alle headers verwijderd. Met de RemoveAt methode wordt een header in een bepaalde index verwijderd (waarbij alle headers erna worden verplaatst). Met de RemoveAll methode worden alle headers met een bepaalde naam en naamruimte verwijderd.
Haal een bepaalde header op met behulp van de FindHeader methode. Deze methode gebruikt de naam en naamruimte van de header om te zoeken en retourneert de index. Als de header meerdere keren voorkomt, wordt er een uitzondering gegenereerd. Als de header niet wordt gevonden, wordt -1 geretourneerd.
In het SOAP-headermodel kunnen headers een Actor
waarde hebben die de beoogde ontvanger van de header aangeeft. De meest eenvoudige FindHeader
overbelasting doorzoekt alleen headers die zijn bedoeld voor de ultieme ontvanger van het bericht. Met een andere overbelasting kunt u echter opgeven welke Actor
waarden in de zoekopdracht worden opgenomen. Zie de SOAP-specificatie voor meer informatie.
Er wordt een CopyTo(MessageHeaderInfo[], Int32) methode geboden voor het kopiëren van headers van een MessageHeaders verzameling naar een matrix met MessageHeaderInfo objecten.
Als u toegang wilt tot de XML-gegevens in een koptekst, kunt u een XML-lezer aanroepen GetReaderAtHeader en retourneren voor de specifieke headerindex. Als u de inhoud van de koptekst wilt deserialiseren in een object, gebruikt GetHeader<T>(Int32) u of een van de andere overbelastingen. De meest eenvoudige overloads deserialiseren headers met behulp van de DataContractSerializer geconfigureerde op de standaard manier. Als u een andere serialisatiefunctie of een andere configuratie van de DataContractSerializer
wilt gebruiken, gebruikt u een van de overbelastingen die een XmlObjectSerializer
. Er zijn ook overbelastingen die de headernaam, naamruimte en eventueel een lijst met Actor
waarden nemen in plaats van een index; dit is een combinatie van FindHeader
en GetHeader
.
Werken met eigenschappen
Een Message
exemplaar kan een willekeurig aantal benoemde objecten van willekeurige typen bevatten. Deze verzameling wordt geopend via de eigenschap van het Properties
type MessageProperties
. De verzameling implementeert de IDictionary<TKey,TValue> interface en fungeert als een toewijzing van String naar Object. Normaal gesproken worden eigenschapswaarden niet rechtstreeks toegewezen aan een deel van het bericht op de kabel, maar bieden eerder verschillende hints voor berichtverwerking aan de verschillende kanalen in de WCF-kanaalstack of aan het CopyTo(MessageHeaderInfo[], Int32) serviceframework. Zie Voor een voorbeeld een overzicht van de architectuur voor gegevensoverdracht.
Overnemen van de berichtklasse
Als de ingebouwde berichttypen die zijn gemaakt, CreateMessage
niet voldoen aan uw vereisten, maakt u een klasse die is afgeleid van de Message
klasse.
De hoofdtekst van het bericht definiëren
Er bestaan drie primaire technieken voor toegang tot gegevens in een berichttekst: schrijven, lezen en kopiëren naar een buffer. Deze bewerkingen resulteren uiteindelijk in respectievelijk de OnWriteBodyContents, OnGetReaderAtBodyContentsen OnCreateBufferedCopy methoden die worden aangeroepen op uw afgeleide klasse van Message
. De basisklasse Message
garandeert dat slechts één van deze methoden wordt aangeroepen voor elk Message
exemplaar en dat deze niet meer dan één keer wordt aangeroepen. De basisklasse zorgt er ook voor dat de methoden niet worden aangeroepen op een gesloten bericht. U hoeft de berichtstatus in uw implementatie niet bij te houden.
OnWriteBodyContents is een abstracte methode en moet worden geïmplementeerd. De eenvoudigste manier om de hoofdtekst van uw bericht te definiëren, is door deze methode te schrijven. Het volgende bericht bevat bijvoorbeeld 100.000 willekeurige getallen van 1 tot 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.
De OnGetReaderAtBodyContents() en OnCreateBufferedCopy methoden hebben standaard implementaties die voor de meeste gevallen werken. De standaard-implementatie aanroep OnWriteBodyContents, buffer de resultaten en werken met de resulterende buffer. In sommige gevallen is dit echter niet voldoende. In het voorgaande voorbeeld resulteert het lezen van het bericht in 100.000 XML-elementen die worden gebufferd, wat mogelijk niet wenselijk is. Mogelijk wilt u overschrijven OnGetReaderAtBodyContents() om een aangepaste XmlDictionaryReader afgeleide klasse te retourneren die willekeurige getallen verwerkt. U kunt vervolgens overschrijven OnWriteBodyContents om de lezer te gebruiken die door de OnGetReaderAtBodyContents() methode wordt geretourneerd, zoals wordt weergegeven in het volgende voorbeeld.
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
Op dezelfde manier wilt u mogelijk overschrijven OnCreateBufferedCopy
om uw eigen MessageBuffer
afgeleide klasse te retourneren.
Naast de inhoud van de berichttekst moet de afgeleide klasse van uw bericht ook de Version
eigenschappen en Headers
Properties
eigenschappen overschrijven.
Houd er rekening mee dat als u een kopie van een bericht maakt, de kopie gebruikmaakt van de berichtkoppen uit het origineel.
Andere leden die kunnen worden overschreven
U kunt de OnWriteStartEnvelope, OnWriteStartHeadersen OnWriteStartBody methoden overschrijven om op te geven hoe de SOAP-envelop, SOAP-headers en soap-hoofdteksten beginnende tags worden geschreven. Deze komen normaal overeen met <soap:Envelope>
, <soap:Header>
en <soap:Body>
. Deze methoden moeten normaal gesproken niets schrijven als de Version eigenschap retourneert None.
Notitie
De standaard implementatie van OnGetReaderAtBodyContents
aanroepen OnWriteStartEnvelope
en OnWriteStartBody
voordat de resultaten worden aangeroepen en gebufferd OnWriteBodyContents
. Kopteksten worden niet weggeschreven.
Overschrijf de OnWriteMessage methode om de manier te wijzigen waarop het hele bericht is samengesteld op basis van de verschillende onderdelen. De OnWriteMessage
methode wordt aangeroepen vanuit WriteMessage en van de standaard OnCreateBufferedCopy implementatie. Houd er rekening mee dat het overschrijven WriteMessage geen best practice is. Het is beter om de juiste On
methoden te overschrijven (bijvoorbeeld OnWriteStartEnvelope, OnWriteStartHeadersen OnWriteBodyContents.
Overschrijven om te overschrijven OnBodyToString hoe de hoofdtekst van uw bericht wordt weergegeven tijdens foutopsporing. De standaardwaarde is om deze weer te geven als drie puntjes (...). Houd er rekening mee dat deze methode meerdere keren kan worden aangeroepen wanneer de berichtstatus iets anders is dan Gesloten. Een implementatie van deze methode mag nooit leiden tot een actie die slechts één keer moet worden uitgevoerd (zoals lezen vanuit een stream die alleen doorsturend is).
Overschrijf de OnGetBodyAttribute methode om toegang tot kenmerken in het SOAP-hoofdtekstelement toe te staan. Deze methode kan een willekeurig aantal keren worden aangeroepen, maar het Message
basistype garandeert dat deze alleen wordt aangeroepen wanneer het bericht de status Gemaakt heeft. Het is niet vereist om de status in een implementatie te controleren. De standaard implementatie retourneert null
altijd, wat aangeeft dat er geen kenmerken zijn op het hoofdtekstelement.
Als uw Message
object speciale opschoning moet uitvoeren wanneer de hoofdtekst van het bericht niet meer nodig is, kunt u overschrijven OnClose. De standaard implementatie doet niets.
De IsEmpty
eigenschappen en IsFault
eigenschappen kunnen worden overschreven. Standaard retourneren false
beide .