Niestandardowy koder komunikatów: Niestandardowy koder tekstu
W przykładzie Text pokazano, jak zaimplementować niestandardowy koder komunikatów tekstowych przy użyciu programu Windows Communication Foundation (WCF).
Program TextMessageEncodingBindingElement WCF obsługuje tylko kodowanie UTF-8, UTF-16 i big-endian Unicode. Niestandardowy koder komunikatów tekstowych w tym przykładzie obsługuje wszystkie kodowania znaków obsługiwane przez platformę, które mogą być wymagane do współdziałania. Przykład składa się z programu konsolowego klienta (.exe), biblioteki usług (.dll) hostowanej przez usługi Internet Information Services (IIS) oraz biblioteki kodera komunikatów tekstowych (.dll). Usługa implementuje kontrakt, który definiuje wzorzec komunikacji typu żądanie-odpowiedź. Kontrakt jest definiowany przez ICalculator
interfejs, który uwidacznia operacje matematyczne (Dodawanie, Odejmowanie, Mnożenie i Dzielenie). Klient wysyła synchroniczne żądania do danej operacji matematycznej, a usługa odpowiada z wynikiem. Zarówno klient, jak CustomTextMessageEncoder
i usługa używają wartości zamiast domyślnej TextMessageEncodingBindingElement.
Implementacja kodera niestandardowego składa się z fabryki kodera komunikatów, kodera komunikatów, elementu powiązania kodowania komunikatów i procedury obsługi konfiguracji oraz demonstruje następujące kwestie:
Tworzenie niestandardowego kodera i fabryki kodera.
Tworzenie elementu powiązania dla kodera niestandardowego.
Używanie niestandardowej konfiguracji powiązania do integrowania niestandardowych elementów powiązania.
Tworzenie niestandardowej procedury obsługi konfiguracji w celu umożliwienia konfiguracji pliku niestandardowego elementu powiązania.
Aby skonfigurować, skompilować i uruchomić przykład
Zainstaluj ASP.NET 4.0 przy użyciu następującego polecenia.
%windir%\Microsoft.NET\Framework\v4.0.XXXXX\aspnet_regiis.exe /i /enable
Upewnij się, że wykonano procedurę instalacji jednorazowej dla przykładów programu Windows Communication Foundation.
Aby skompilować rozwiązanie, postępuj zgodnie z instrukcjami w temacie Building the Windows Communication Foundation Samples (Tworzenie przykładów programu Windows Communication Foundation).
Aby uruchomić przykład w konfiguracji pojedynczej lub między maszynami, postępuj zgodnie z instrukcjami w temacie Uruchamianie przykładów programu Windows Communication Foundation.
Fabryka kodera komunikatów i koder komunikatów
Po otwarciu ServiceHost kanału klienta lub składnik CustomTextMessageBindingElement
czasu projektowania tworzy element CustomTextMessageEncoderFactory
. Fabryka tworzy obiekt CustomTextMessageEncoder
. Koder komunikatów działa zarówno w trybie przesyłania strumieniowego, jak i w trybie buforowania. Używa odpowiednio poleceń XmlReader i XmlWriter do odczytywania i zapisywania komunikatów. W przeciwieństwie do zoptymalizowanych czytników XML i składników zapisywania WCF, które obsługują tylko kodowanie UTF-8, UTF-16 i big-endian Unicode, te czytniki i autorzy obsługują wszystkie kodowanie obsługiwane przez platformę.
Poniższy przykład kodu przedstawia element CustomTextMessageEncoder.
public class CustomTextMessageEncoder : MessageEncoder
{
private CustomTextMessageEncoderFactory factory;
private XmlWriterSettings writerSettings;
private string contentType;
public CustomTextMessageEncoder(CustomTextMessageEncoderFactory factory)
{
this.factory = factory;
this.writerSettings = new XmlWriterSettings();
this.writerSettings.Encoding = Encoding.GetEncoding(factory.CharSet);
this.contentType = $"{this.factory.MediaType}; charset={this.writerSettings.Encoding.HeaderName}";
}
public override string ContentType
{
get
{
return this.contentType;
}
}
public override string MediaType
{
get
{
return factory.MediaType;
}
}
public override MessageVersion MessageVersion
{
get
{
return this.factory.MessageVersion;
}
}
public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
{
byte[] msgContents = new byte[buffer.Count];
Array.Copy(buffer.Array, buffer.Offset, msgContents, 0, msgContents.Length);
bufferManager.ReturnBuffer(buffer.Array);
MemoryStream stream = new MemoryStream(msgContents);
return ReadMessage(stream, int.MaxValue);
}
public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
{
XmlReader reader = XmlReader.Create(stream);
return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);
}
public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
{
MemoryStream stream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
message.WriteMessage(writer);
writer.Close();
byte[] messageBytes = stream.GetBuffer();
int messageLength = (int)stream.Position;
stream.Close();
int totalLength = messageLength + messageOffset;
byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);
ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
return byteArray;
}
public override void WriteMessage(Message message, Stream stream)
{
XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
message.WriteMessage(writer);
writer.Close();
}
}
Poniższy przykład kodu pokazuje, jak utworzyć fabrykę kodera komunikatów.
public class CustomTextMessageEncoderFactory : MessageEncoderFactory
{
private MessageEncoder encoder;
private MessageVersion version;
private string mediaType;
private string charSet;
internal CustomTextMessageEncoderFactory(string mediaType, string charSet,
MessageVersion version)
{
this.version = version;
this.mediaType = mediaType;
this.charSet = charSet;
this.encoder = new CustomTextMessageEncoder(this);
}
public override MessageEncoder Encoder
{
get
{
return this.encoder;
}
}
public override MessageVersion MessageVersion
{
get
{
return this.version;
}
}
internal string MediaType
{
get
{
return this.mediaType;
}
}
internal string CharSet
{
get
{
return this.charSet;
}
}
}
Element powiązania kodowania komunikatów
Elementy powiązania umożliwiają konfigurację stosu czasu wykonywania WCF. Aby użyć niestandardowego kodera komunikatów w aplikacji WCF, wymagany jest element powiązania, który tworzy fabrykę kodera komunikatów z odpowiednimi ustawieniami na odpowiednim poziomie w stosie czasu wykonywania.
Element CustomTextMessageBindingElement
pochodzi z klasy bazowej BindingElement i dziedziczy z MessageEncodingBindingElement klasy . Dzięki temu inne składniki programu WCF mogą rozpoznawać ten element powiązania jako element powiązania kodowania komunikatów. Implementacja zwraca wystąpienie zgodnej fabryki kodera komunikatów CreateMessageEncoderFactory z odpowiednimi ustawieniami.
Ustawienia CustomTextMessageBindingElement
uwidacznia dla MessageVersion
właściwości , ContentType
i Encoding
za pośrednictwem. Koder obsługuje wersje Soap11Addressing i Soap12Addressing1. Wartość domyślna to Soap11Addressing1. Wartość domyślna to ContentType
"text/xml". Właściwość Encoding
umożliwia ustawienie wartości żądanego kodowania znaków. Przykładowy klient i usługa używają kodowania znaków ISO-8859-1 (Latin1), które nie jest obsługiwane przez TextMessageEncodingBindingElement program WCF.
Poniższy kod pokazuje, jak programowo utworzyć powiązanie przy użyciu niestandardowego kodera komunikatów tekstowych.
ICollection<BindingElement> bindingElements = new List<BindingElement>();
HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
CustomTextMessageBindingElement textBindingElement = new CustomTextMessageBindingElement();
bindingElements.Add(textBindingElement);
bindingElements.Add(httpBindingElement);
CustomBinding binding = new CustomBinding(bindingElements);
Dodawanie obsługi metadanych do elementu powiązania kodowania komunikatów
Każdy typ pochodzący z MessageEncodingBindingElement programu jest odpowiedzialny za aktualizowanie wersji powiązania protokołu SOAP w dokumencie WSDL wygenerowanym dla usługi. Jest to realizowane przez zaimplementowanie ExportEndpoint
metody w interfejsie IWsdlExportExtension , a następnie zmodyfikowanie wygenerowanego pliku WSDL. W tym przykładzie użyto CustomTextMessageBindingElement
logiki eksportu WSDL z pliku TextMessageEncodingBindingElement
.
W tym przykładzie konfiguracja klienta jest ręcznie skonfigurowana. Nie można użyć Svcutil.exe do wygenerowania konfiguracji klienta, ponieważ CustomTextMessageBindingElement
nie eksportuje asercji zasad w celu opisania jego zachowania. Interfejs należy zazwyczaj zaimplementować IPolicyExportExtension w niestandardowym elemecie powiązania w celu wyeksportowania niestandardowej asercji zasad opisujących zachowanie lub możliwość zaimplementowaną przez element powiązania. Przykład eksportowania asercji zasad dla niestandardowego elementu powiązania można znaleźć w przykładzie Transport: UDP .
Procedura obsługi konfiguracji powiązania kodowania komunikatów
W poprzedniej sekcji pokazano, jak programowo używać niestandardowego kodera komunikatów tekstowych. Implementuje CustomTextMessageEncodingBindingSection
procedurę obsługi konfiguracji, która umożliwia określenie użycia niestandardowego kodera komunikatów tekstowych w pliku konfiguracji. Klasa CustomTextMessageEncodingBindingSection
pochodzi z BindingElementExtensionElement klasy . Właściwość BindingElementType
informuje system konfiguracji o typie elementu powiązania, który ma zostać utworzony dla tej sekcji.
Wszystkie ustawienia zdefiniowane przez CustomTextMessageBindingElement
program są uwidocznione jako właściwości w obiekcie CustomTextMessageEncodingBindingSection
. Pomoc ConfigurationPropertyAttribute w mapowaniu atrybutów elementu konfiguracji na właściwości i ustawiania wartości domyślnych, jeśli atrybut nie jest ustawiony. Po załadowaniu i zastosowaniu wartości z konfiguracji do właściwości typu CreateBindingElement wywoływana jest metoda, która konwertuje właściwości na konkretne wystąpienie elementu powiązania.
Ta procedura obsługi konfiguracji mapuje następującą reprezentację w pliku App.config lub Web.config dla usługi lub klienta.
<customTextMessageEncoding encoding="utf-8" contentType="text/xml" messageVersion="Soap11Addressing1" />
W przykładzie użyto kodowania ISO-8859-1.
Aby użyć tej procedury obsługi konfiguracji, należy ją zarejestrować przy użyciu następującego elementu konfiguracji.
<extensions>
<bindingElementExtensions>
<add name="customTextMessageEncoding" type="
Microsoft.ServiceModel.Samples.CustomTextMessageEncodingBindingSection,
CustomTextMessageEncoder" />
</bindingElementExtensions>
</extensions>