Message 클래스 사용

Message 클래스는 WCF(Windows Communication Foundation)의 기본 사항입니다. 클라이언트와 서비스 간의 모든 통신에서 결국 Message 인스턴스의 전송과 수신이 발생합니다.

일반적으로 Message 클래스와 직접 상호 작용하지는 않습니다. 대신 데이터 계약, 메시지 계약, 작업 계약 등의 WCF 서비스 모델 생성자가 사용되어 들어오는 메시지와 보내는 메시지를 설명합니다. 그러나 일부 고급 시나리오에서는 Message 클래스를 직접 사용하여 프로그래밍할 수 있습니다. 예를 들어 다음과 같은 경우 Message 클래스를 사용할 수 있습니다.

  • .NET Framework 개체를 직렬화하는 대신 보내는 메시지 내용을 만드는 다른 방법(예: 디스크의 파일에서 직접 메시지 만들기)이 필요한 경우.

  • .NET Framework 개체로 역직렬화하는 대신 들어오는 메시지 내용을 사용하는 대체 방법이 필요한 경우(예: 원시 XML 콘텐츠에 XSLT 변환을 적용하려는 경우)

  • 메시지 내용에 관계없이 일반적인 방법으로 메시지를 처리해야 하는 경우(예: 라우터, 부하 분산 장치 또는 게시-구독 시스템을 구축할 때 메시지를 라우팅 또는 전달하는 경우)

Message 클래스를 사용하기 전에 데이터 전송 아키텍처 개요에서 WCF 데이터 전송 아키텍처를 숙지합니다.

Message는 데이터의 범용 컨테이너이지만 그 디자인은 SOAP 프로토콜의 메시지 디자인과 유사합니다. SOAP와 마찬가지로 메시지에는 메시지 본문과 헤더가 있습니다. 메시지 본문에는 실제 페이로드 데이터가 들어 있고 헤더에는 명명된 추가 데이터 컨테이너가 들어 있습니다. 본문과 헤더를 읽고 쓰는 규칙은 서로 다릅니다. 예를 들어 헤더는 항상 메모리에 버퍼링되고 순서와 횟수에 관계없이 액세스할 수 있지만 본문은 한 번만 읽을 수 있고 스트리밍할 수 있습니다. 일반적으로 SOAP를 사용하는 경우 메시지 본문은 SOAP 본문에 매핑되고 메시지 헤더는 SOAP 헤더에 매핑됩니다.

작업에서 메시지 클래스 사용

Message 클래스를 작업의 입력 매개 변수, 작업의 반환 값 또는 둘 다로 사용할 수 있습니다. 작업에서 Message를 사용하는 경우 다음 제한 사항이 적용됩니다.

  • 작업에 out 또는 ref 매개 변수를 사용할 수 없습니다.

  • input 매개 변수를 둘 이상 사용할 수 없습니다. 매개 변수가 있는 경우 메시지 또는 메시지 계약 형식이어야 합니다.

  • 반환 형식은 void, Message 또는 메시지 계약 형식이어야 합니다.

다음 코드 예제에는 올바른 작업 계약이 포함되어 있습니다.

[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

기본 메시지 만들기

Message 클래스는 기본 메시지를 만드는 데 사용할 수 있는 정적 CreateMessage 팩터리를 제공합니다.

모든 CreateMessage 오버로드는 메시지에 사용할 SOAP 및 WS-Addressing 버전을 나타내는 MessageVersion 형식의 버전 매개 변수를 사용합니다. 들어오는 메시지와 동일한 프로토콜 버전을 사용하려면 IncomingMessageVersion 속성에서 가져온 OperationContext 인스턴스의 Current 속성을 사용합니다. 대부분의 CreateMessage 오버로드에는 메시지에 사용할 SOAP 동작을 나타내는 문자열 매개 변수도 있습니다. 버전을 None으로 설정하여 SOAP 봉투 생성을 비활성화할 수 있습니다. 메시지가 본문으로만 구성됩니다.

개체에서 메시지 만들기

버전과 동작만 사용하는 가장 기본적인 CreateMessage 오버로드는 빈 본문이 있는 메시지를 만듭니다. 다른 오버로드는 추가 Object 매개 변수를 사용하며, 본문이 지정된 개체의 serialize된 표현인 메시지를 만듭니다. 기본 serialization 설정으로 DataContractSerializer를 사용합니다. 다른 serializer를 사용하거나 DataContractSerializer를 다르게 구성하려면 CreateMessage 매개 변수도 받아들이는 XmlObjectSerializer 오버로드를 사용합니다.

예를 들어 메시지에 개체를 반환하려면 다음 코드를 사용할 수 있습니다.

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

XML 판독기에서 메시지 만들기

개체 대신 본문으로 CreateMessage 또는 XmlReader를 사용하는 XmlDictionaryReader 오버로드가 있습니다. 이 경우 메시지의 본문에는 통과한 XML 판독기 읽기에서 발생한 XML이 포함됩니다. 예를 들어 다음 코드는 XML 파일에서 읽은 본문 내용이 포함된 메시지를 반환합니다.

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

또한 본문뿐 아니라 전체 메시지를 나타내는 CreateMessage 또는 XmlReader를 사용하는 XmlDictionaryReader 오버로드가 있습니다. 이 오버로드는 정수 maxSizeOfHeaders 매개 변수도 사용합니다. 헤더는 메시지를 만드는 즉시 항상 메모리에 버퍼링되며, 이 매개 변수는 발생하는 버퍼링 양을 제한합니다. 서비스 거부 공격의 가능성을 줄이기 위해 XML이 신뢰할 수 없는 소스에서 제공되는 경우 이 매개 변수를 안전한 값으로 설정하는 것이 중요합니다. XML 판독기에서 나타내는 메시지의 SOAP 및 WS-Addressing 버전은 버전 매개 변수를 사용하여 표시된 버전과 일치해야 합니다.

BodyWriter를 사용하여 메시지 만들기

CreateMessage 오버로드는 BodyWriter 인스턴스를 사용하여 메시지 본문을 설명합니다. BodyWriter는 메시지 본문을 만드는 방법을 사용자 지정하기 위해 파생될 수 있는 추상 클래스입니다. 고유한 BodyWriter 파생 클래스를 만들어 사용자 지정 방식으로 메시지 본문을 설명할 수 있습니다. BodyWriter.OnWriteBodyContents를 사용하는 XmlDictionaryWriter 메서드를 재정의해야 합니다. 이 메서드는 본문을 쓰는 작업을 담당합니다.

본문 작성기를 버퍼링하거나 버퍼링하지 않을(스트리밍) 수 있습니다. 버퍼링된 본문 작성기는 횟수에 관계없이 콘텐츠를 쓸 수 있지만 스트리밍된 본문 작성기는 한 번만 콘텐츠를 쓸 수 있습니다. IsBuffered 속성은 본문 작성기의 버퍼링 여부를 나타냅니다. BodyWriter 부울 매개 변수를 사용하는 보호된 isBuffered 생성자를 호출하여 본문 작성기에 대해 이 속성을 설정할 수 있습니다. 본문 작성기는 버퍼링되지 않은 본문 작성기에서 버퍼링된 본문 작성기를 만드는 기능을 지원합니다. OnCreateBufferedCopy 메서드를 재정의하여 이 프로세스를 사용자 지정할 수도 있습니다. 기본적으로, OnWriteBodyContents에서 반환한 XML이 들어 있는 메모리 내 버퍼가 사용됩니다. OnCreateBufferedCopymaxBufferSize 정수 매개 변수를 사용합니다. 이 메서드를 재정의할 경우 이 최대 크기보다 큰 버퍼를 만들면 안됩니다.

BodyWriter 클래스는 기본적으로 각각 WriteBodyContentsCreateBufferedCopy 메서드를 둘러싼 가는 래퍼인 OnWriteBodyContentsOnCreateBufferedCopy 메서드를 제공합니다. 이 메서드는 상태를 확인하여 버퍼링되지 않은 본문 작성기를 두 번 이상 액세스하지 않도록 합니다. 이 메서드는 Message에 기초한 사용자 지정 BodyWriters 파생 클래스를 만들 때만 직접 호출됩니다.

오류 메시지 만들기

특정 CreateMessage 오버로드를 사용하여 SOAP 오류 메시지를 만들 수 있습니다. 이 중에서 가장 기본적인 오버로드는 오류를 설명하는 MessageFault 개체를 사용합니다. 다른 오버로드는 편의상 제공됩니다. 첫 번째 오버로드는 FaultCode 및 원인 문자열을 사용하고 이 정보를 통해 MessageFault를 사용하여 MessageFault.CreateFault를 만듭니다. 다른 오버로드는 세부 개체를 사용하고 오류 코드 및 원인과 함께 이 개체를 CreateFault로 전달합니다. 예를 들어 다음 작업은 오류를 반환합니다.

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

메시지 본문 데이터 추출

Message 클래스는 본문에서 정보를 추출하는 여러 방법을 지원합니다. 이러한 방법을 다음 범주로 분류할 수 있습니다.

  • 한 번에 전체 메시지 본문을 XML 작성기에 씁니다. 이를 메시지 쓰기라고 합니다.

  • 메시지 본문에 XML 판독기를 적용합니다. 이렇게 하면 필요할 경우 나중에 부분별로 메시지 본문에 액세스할 수 있습니다. 이를 메시지 읽기라고 합니다.

  • 본문을 비롯한 전체 메시지를 MessageBuffer 형식의 메모리 내 버퍼로 복사할 수 있습니다. 이를 메시지 복사라고 합니다.

액세스 방법에 관계없이 Message 본문에는 한 번만 액세스할 수 있습니다. 메시지 개체에는 처음에 Created로 설정되는 State 속성이 있습니다. 앞의 목록에서 설명한 세 가지 액세스 방법은 상태를 각각 Written, Read 및 Copied로 설정합니다. 또한 Close 메서드는 메시지 본문 내용이 더 이상 필요하지 않을 경우 상태를 Closed로 설정할 수 있습니다. 메시지 본문은 만듦 상태에서만 액세스할 수 있으며 상태가 변경된 후에는 만듦 상태로 돌아갈 수 없습니다.

메시지 쓰기

WriteBodyContents(XmlDictionaryWriter) 메서드는 지정된 Message 인스턴스의 본문 내용을 지정된 XML 작성기에 씁니다. WriteBody 메서드는 본문 내용을 적절한 래퍼 요소에 포함(예: <soap:body>)한다는 점을 제외하고 동일한 작업을 수행합니다. 마지막으로 WriteMessage는 래핑 SOAP 봉투와 헤더를 비롯한 전체 메시지를 씁니다. SOAP가 꺼져 있으면(VersionMessageVersion.None임) 세 가지 메서드 모두 동일한 작업을 수행합니다. 즉, 메시지 본문 내용을 작성합니다.

예를 들어 다음 코드는 들어오는 메시지의 본문을 파일에 씁니다.

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

두 개의 추가 도우미 메서드는 특정 SOAP 시작 요소 태그를 씁니다. 이 메서드는 메시지 본문에 액세스하지 않으므로 메시지 상태를 변경하지 않습니다. 여기에는 다음이 포함됩니다.

해당하는 끝 요소 태그를 쓰려면 해당 XML 작성기에서 WriteEndElement를 호출합니다. 이 메서드는 직접 호출되는 경우가 거의 없습니다.

메시지 읽기

메시지 본문을 읽는 기본 방법은 GetReaderAtBodyContents를 호출하는 것입니다. 메시지 본문을 읽는 데 사용할 수 있는 XmlDictionaryReader가 반환됩니다. MessageGetReaderAtBodyContents를 호출하는 즉시 Read 상태로 전환되며, 반환된 XML 판독기를 사용하는 경우에는 전환되지 않습니다.

GetBody 메서드를 사용하여 형식화된 개체로 메시지 본문에 액세스할 수도 있습니다. 내부적으로 이 메서드는 GetReaderAtBodyContents를 사용하므로 메시지 상태를 Read 상태로 전환합니다(State 속성 참조).

IsEmpty 속성을 확인하는 것이 좋습니다. 이 경우 메시지 본문이 비어 있으며 GetReaderAtBodyContents에서 InvalidOperationException을 throw합니다. 받은 메시지(예: 회신)인 경우 메시지에 오류가 있는지 여부를 나타내는 IsFault를 확인할 수도 있습니다.

GetBody의 가장 기본적인 오버로드는 기본 설정으로 구성되고 DataContractSerializer 할당량이 비활성화된 MaxItemsInObjectGraph를 사용하여 제네릭 매개 변수가 나타내는 형식의 인스턴스로 메시지 본문을 역직렬화합니다. 다른 serialization 엔진을 사용하거나 기본값이 아닌 방식으로 DataContractSerializer를 구성하려면 GetBody를 받아들이는 XmlObjectSerializer 오버로드를 사용합니다.

예를 들어 다음 코드는 serialize된 Person 개체를 포함하는 메시지 본문에서 데이터를 추출하고 개인의 이름을 인쇄합니다.

    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

메시지를 버퍼에 복사

경우에 따라 메시지 본문을 두 번 이상 액세스해야 할 수 있습니다. 예를 들어 게시자-구독자 시스템의 일부로 동일한 메시지를 여러 대상에 전달할 수 있습니다. 이 경우 본문을 비롯한 전체 메시지를 메모리에 버퍼링해야 합니다. 이렇게 하려면 CreateBufferedCopy(Int32)를 호출합니다. 이 메서드는 최대 버퍼 크기를 나타내는 정수 매개 변수를 사용하며 이 크기보다 크지 않은 버퍼를 만듭니다. 메시지가 신뢰할 수 없는 소스에서 제공되는 경우 이 메서드를 안전한 값으로 설정하는 것이 중요합니다.

버퍼는 MessageBuffer 인스턴스로 반환됩니다. 여러 방법으로 버퍼의 데이터에 액세스할 수 있습니다. 기본 방법은 CreateMessage를 호출하여 버퍼에서 Message 인스턴스를 만드는 것입니다.

버퍼의 데이터에 액세스하는 다른 방법은 IXPathNavigable 클래스가 내부 XML에 직접 액세스하기 위해 구현하는 MessageBuffer 인터페이스를 구현하는 것입니다. 일부 CreateNavigator 오버로드를 사용하면 방문할 수 있는 XML 노드 수를 제한하여 노드 할당량으로 보호되는 System.Xml.XPath 탐색기를 만들 수 있습니다. 이 탐색기는 긴 처리 시간을 기반으로 서비스 거부 공격을 방지하는 데 유용합니다. 이 할당량은 기본적으로 사용되지 않습니다. 일부 CreateNavigator 오버로드를 사용하면 기본값이 XmlSpaceXmlSpace.None 열거를 사용하여 XML에서 공백을 처리하는 방법을 지정할 수 있습니다.

메시지 버퍼의 내용에 액세스하는 마지막 방법은 WriteMessage를 사용하여 버퍼 내용을 스트림에 쓰는 것입니다.

다음 예제에서는 MessageBuffer 작업 프로세스를 보여 줍니다. 들어오는 메시지가 여러 수신자에게 전달된 다음 파일에 기록됩니다. 버퍼링 기능이 없으면 메시지 본문에 한 번만 액세스할 수 있으므로 이 작업을 수행할 수 없습니다.

[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

MessageBuffer 클래스에는 주목할 만한 다른 멤버가 있습니다. 버퍼 내용이 더 이상 필요하지 않으면 Close 메서드를 호출하여 리소스를 확보할 수 있습니다. BufferSize 속성은 할당된 버퍼의 크기를 반환합니다. MessageContentType 속성은 메시지의 MIME 콘텐츠 형식을 반환합니다.

디버깅을 위해 메시지 본문에 액세스

디버깅 목적으로 ToString 메서드를 호출하여 문자열로 메시지 표현을 가져올 수 있습니다. 이 표현은 일반적으로 XML 형식이 사람이 인식하는 데 더 적합하다는 점을 제외하고 텍스트 인코더로 인코딩된 경우 통신 중에 메시지가 표시되는 방식과 일치합니다. 단, 메시지 본문은 예외입니다. 본문은 한 번만 읽을 수 있으며 ToString에서 메시지 상태를 변경하지 않습니다. 따라서 ToString 메서드가 본문에 액세스할 수 없으며 메시지 본문 대신 자리 표시자(예: "…" 또는 세 개의 점)를 대체할 수 있습니다. 메시지의 본문 내용이 중요한 경우 ToString을 사용하여 메시지를 기록하지 마세요.

다른 메시지 부분에 액세스

본문 내용 이외의 메시지 정보에 액세스할 수 있도록 다양한 속성이 제공됩니다. 그러나 메시지가 닫힌 후에는 이러한 속성을 호출할 수 없습니다.

  • Headers 속성은 메시지 헤더를 나타냅니다. 이 항목의 뒷부분에 있는 "헤더 작업" 단원을 참조하세요.

  • Properties 속성은 일반적으로 메시지가 전송될 때 내보내지 않는 메시지에 첨부된 명명된 데이터 부분인 메시지 속성을 나타냅니다. 이 항목의 뒷부분에 있는 "속성 작업" 단원을 참조하세요.

  • Version 속성은 메시지와 연결된 SOAP 및 WS-Addressing 버전을 나타내거나 SOAP를 사용하지 않는 경우 None을 나타냅니다.

  • 메시지가 SOAP 오류 메시지인 경우 IsFault 속성에서 true를 반환합니다.

  • 메시지가 비어 있으면 IsEmpty 속성에서 true를 반환합니다.

GetBodyAttribute(String, String) 메서드를 사용하여 특정 이름과 네임스페이스로 식별된 본문 래퍼 요소(예: <soap:Body>)의 특정 특성에 액세스할 수 있습니다. 이러한 특성이 없으면 null이 반환됩니다. 이 메서드는 Message가 만듦 상태인 경우(메시지 본문에 아직 액세스하지 않은 경우)에만 호출할 수 있습니다.

헤더 작업

Message헤더라는 명명된 XML 조각을 개수에 관계없이 포함할 수 있습니다. 각 조각은 일반적으로 SOAP 헤더에 매핑됩니다. Headers 형식의 MessageHeaders 속성을 통해 헤더에 액세스합니다. MessageHeadersMessageHeaderInfo 개체의 컬렉션이고 개별 헤더는 해당 IEnumerable 인터페이스나 인덱서를 통해 액세스할 수 있습니다. 예를 들어 다음 코드는 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

헤더 추가, 제거, 찾기

Add 메서드를 사용하여 모든 기존 헤더의 끝에 새 헤더를 추가할 수 있습니다. Insert 메서드를 사용하여 특정 인덱스에 헤더를 삽입할 수 있습니다. 기존 헤더는 삽입된 항목에 대해 이동됩니다. 헤더는 인덱스에 따라 순서가 지정되며 사용 가능한 첫 번째 인덱스는 0입니다. 다양한 CopyHeadersFrom 메서드 오버로드를 사용하여 다른 Message 또는 MessageHeaders 인스턴스에서 헤더를 추가할 수 있습니다. 일부 오버로드는 개별 헤더를 복사하고 다른 오버로드는 모든 헤더를 복사합니다. Clear 메서드는 모든 헤더를 제거합니다. RemoveAt 메서드는 특정 인덱스의 헤더를 제거하고 뒤에 있는 모든 헤더를 이동합니다. RemoveAll 메서드는 특정 이름과 네임스페이스를 가진 모든 헤더를 제거합니다.

FindHeader 메서드를 사용하여 특정 헤더를 검색합니다. 이 메서드는 찾을 헤더의 이름과 네임스페이스를 사용하고 해당 인덱스를 반환합니다. 헤더가 여러 번 발생하는 경우 예외가 throw됩니다. 헤더가 없으면 -1을 반환합니다.

SOAP 헤더 모델에서는 헤더의 의도된 수신자를 지정하는 Actor 값이 헤더에 포함될 수 있습니다. 가장 기본적인 FindHeader 오버로드는 메시지의 최종 수신자에 대한 헤더만 검색합니다. 그러나 다른 오버로드를 사용하여 검색에 포함할 Actor 값을 지정할 수 있습니다. 자세한 내용은 SOAP 사양을 참조하세요.

CopyTo(MessageHeaderInfo[], Int32) 메서드는 MessageHeaders 컬렉션의 헤더를 MessageHeaderInfo 개체의 배열로 복사하기 위해 제공됩니다.

헤더의 XML 데이터에 액세스하려면 GetReaderAtHeader를 호출하고 특정 헤더 인덱스에 대한 XML 판독기를 반환합니다. 헤더 내용을 개체로 역직렬화하려면 GetHeader<T>(Int32) 또는 다른 오버로드 중 하나를 사용합니다. 가장 기본적인 오버로드는 기본 방식으로 구성된 DataContractSerializer를 사용하여 헤더를 역직렬화합니다. 다른 serializer나 DataContractSerializer의 다른 구성을 사용하려면 XmlObjectSerializer를 받아들이는 오버로드 중 하나를 사용합니다. 인덱스 대신 헤더 이름, 네임스페이스 및 선택적으로 Actor 값의 목록을 사용하는 오버로드도 있습니다. 이 오버로드는 FindHeaderGetHeader의 조합입니다.

속성 작업

Message 인스턴스는 임의 형식과 개수의 명명된 개체를 포함할 수 있습니다. Properties 형식의 MessageProperties 속성을 통해 이 컬렉션에 액세스합니다. 이 컬렉션은 IDictionary<TKey,TValue> 인터페이스를 구현하며 String에서 Object로의 매핑으로 작동합니다. 일반적으로 속성 값은 통신 중인 메시지 부분에 직접 매핑되지 않고 대신 WCF 채널 스택의 다양한 채널이나 CopyTo(MessageHeaderInfo[], Int32) 서비스 프레임워크에 다양한 메시지 처리 힌트를 제공합니다. 예는 데이터 전송 아키텍처 개요를 참조하세요.

Message 클래스에서 상속

CreateMessage를 사용하여 만든 기본 제공 메시지 형식이 요구 사항에 맞지 않을 경우 Message 클래스에서 파생된 클래스를 만듭니다.

메시지 본문 내용 정의

메시지 본문 내의 데이터에 액세스하는 세 가지 기본 방법은 쓰기, 읽기 및 버퍼에 복사입니다. 이러한 작업을 수행하면 결국 OnWriteBodyContents의 파생 클래스에서 각각 OnGetReaderAtBodyContents, OnCreateBufferedCopyMessage 메서드가 호출됩니다. 기본 Message 클래스는 각 Message 인스턴스에 대해 이 메서드 중 하나만 호출되며 여러 번 호출되지 않도록 합니다. 또한 기본 클래스는 닫힌 메시지에 대해 메서드가 호출되지 않도록 합니다. 구현에서 메시지 상태를 추적할 필요는 없습니다.

OnWriteBodyContents는 추상 메서드이며 구현해야 합니다. 메시지의 본문 내용을 정의하는 가장 기본적인 방법은 이 메서드를 사용하여 쓰는 것입니다. 예를 들어 다음 메시지에는 1에서 20까지 100,000개의 난수가 포함됩니다.

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.

OnGetReaderAtBodyContents()OnCreateBufferedCopy 메서드에는 대부분의 경우에서 작동하는 기본 구현이 있습니다. 기본 구현에서는 OnWriteBodyContents를 호출하고 그 결과를 버퍼링한 다음 결과 버퍼로 작업합니다. 그러나 일부 경우에서는 이 기능만으로 충분하지 않을 수 있습니다. 앞의 예제에서 메시지를 읽으면 100,000개의 XML 요소가 버퍼링되며 이는 바람직하지 않을 수 있습니다. OnGetReaderAtBodyContents()를 재정의하여 난수를 제공하는 사용자 지정 XmlDictionaryReader 파생 클래스를 반환할 수 있습니다. 그런 후에 다음 예와 같이 OnGetReaderAtBodyContents() 메서드가 반환하는 판독기를 사용하도록 OnWriteBodyContents을 재정의할 수 있습니다.

    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

마찬가지로 OnCreateBufferedCopy를 재정의하여 고유한 MessageBuffer 파생 클래스를 반환할 수 있습니다.

메시지 본문 내용 제공 외에도 메시지 파생 클래스는 Version, HeadersProperties 속성을 재정의해야 합니다.

메시지 복사본을 만드는 경우 복사본은 원본의 메시지 헤더를 사용합니다.

재정의할 수 있는 기타 멤버

OnWriteStartEnvelope, OnWriteStartHeadersOnWriteStartBody 메서드를 재정의하여 SOAP 봉투, SOAP 헤더 및 SOAP 본문 요소 시작 태그가 작성되는 방식을 지정할 수 있습니다. 일반적으로 <soap:Envelope>, <soap:Header><soap:Body>에 해당합니다. Version 속성에서 None을 반환할 경우 아무 내용도 쓰면 안 됩니다.

참고 항목

OnGetReaderAtBodyContents의 기본 구현에서는 OnWriteStartEnvelope를 호출하고 결과를 버퍼링하기 전에 OnWriteStartBodyOnWriteBodyContents를 호출합니다. 헤더는 쓰지 않습니다.

OnWriteMessage 메서드를 재정의하여 다양한 부분에서 전체 메시지가 생성되는 방법을 변경합니다. OnWriteMessage 메서드는 WriteMessage 및 기본 OnCreateBufferedCopy 구현에서 호출됩니다. WriteMessage 재정의는 최선의 방법이 아닙니다. 적절한 On 메서드(예: OnWriteStartEnvelope, OnWriteStartHeadersOnWriteBodyContents)를 재정의하는 것이 좋습니다.

OnBodyToString을 재정의하여 디버깅 중에 메시지 본문을 나타내는 방법을 재정의합니다. 기본값은 메시지 본문을 세 개의 점("…")으로 나타냅니다. 메시지 상태가 Closed가 아니면 이 메서드는 여러 번 호출할 수 있습니다. 이 메서드의 구현에서는 한 번만 수행해야 하는 작업(예: 정방향 전용 스트림에서 읽기)을 발생시키면 안 됩니다.

OnGetBodyAttribute 메서드를 재정의하여 SOAP 본문 요소의 특성에 대한 액세스를 허용합니다. 이 메서드는 횟수에 관계없이 호출할 수 있지만 Message 기본 형식에서 메시지가 만듦 상태인 경우에만 메서드가 호출되도록 합니다. 구현에서 상태를 확인할 필요는 없습니다. 기본 구현에서는 항상 본문 요소의 특성이 없음을 나타내는 null을 반환합니다.

메시지 본문이 더 이상 필요하지 않을 때 Message 개체에서 특별한 정리 작업을 수행해야 하는 경우 OnClose를 재정의할 수 있습니다. 기본 구현은 아무 작업도 수행하지 않습니다.

IsEmptyIsFault 속성을 재정의할 수 있습니다. 기본적으로 두 메서드는 모두 false를 반환합니다.