I am consuming a WCF service that requires headers

2019-06-07 12:05发布

I have a WCF service that uses a custom instance provider (implements IInstanceProvider) for which the GetInstance method expects a message that contains a few headers, like this:

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        string token = null;

        if (message != null)
        {
            token = message.Headers.GetHeader<string>("Token", "urn:userinfo");
        }

        Bootstrapper bootstrapper = new Bootstrapper();
        bootstrapper.InitialiseSession(token);

        return new MyServiceHost(bootstrapper.ServiceModel);
    }

This service now needs to be called from a .NET 2 web application, so I added a basicHttpBinding endpoint to the WCF service and successfully added the web reference to that .NET 2 application which added an App_WebReferences folder with a MyService folder inside including the WSDL file and several .XSD files.

Just to clarify a little, that web application is written in VB.Net instead of C# and I'm not as familiar with VB.Net as I am with C#.

So, in the web application's code I wrote this:

    Private myService As MyService.MyServiceHost
    myService.Url = "http://myserver:1234/MyService"
    myService.MyMethod()

This all works fine, the service receives the message to execute MyMethod, but, as expected, it returns an error message: "There is not a header with name Token and namespace urn:userinfo in the message."

With my other clients (C#, .NET 4.5), all I do in code when creating the client that will call the service is:

    MessageHeader<string> headerToken;
    OperationContext.Current = new OperationContext((IContextChannel)serviceClient);
    headerToken = new MessageHeader<string>("insert-token-here");
    OperationContext.Current.OutgoingMessageHeaders.Add(headerToken.GetUntypedHeader("Token", "urn:userinfo"));

How can I do something similar in the .NET 2 application?

Thanks!


UPDATE:

I have now managed to pass a header to the service by creating a different class that inherits the class MyService.MyServiceHost and then overriding the method GetWriterForMessage, like this:

    Protected Overrides Function GetWriterForMessage(ByVal message As System.Web.Services.Protocols.SoapClientMessage, ByVal bufferSize As Integer) As System.Xml.XmlWriter
        Dim myWriterForMessage As System.Xml.XmlWriter

        Dim myHeader As MySoapHeader
        myHeader = New MySoapHeader()
        myHeader.Token = "myToken"

        message.Headers.Add(myHeader)
        myWriterForMessage = MyBase.GetWriterForMessage(message, bufferSize)

        Return myWriterForMessage
    End Function
End Class

And I created a new class called MySoapHeader that inherits from System.Web.Services.Protocols.SoapHeader and has a Token property.

Looking at the WCF service side, the message is coming with the header, but unfortunately the header name is the name of the class (MySoapHeader) and the namespace of the header is "http://tempuri.org", which is incorrect.

How can I change that without having to name my class "Token" (which is very undesirable for a class name but it is the name of the header my service is expecting) and the header's namespace to "urn:userinfo"?

Thanks again!

1条回答
贪生不怕死
2楼-- · 2019-06-07 12:57

Ok, I managed to sort this one out.

I created my own service class as I mentioned in the update, and created my own GetWriterForMessage method, like this:

Partial Public Class MyExtendedServiceHost
    Inherits MyService.MyServiceHost

    Private _token As String

    Public Sub New(ByVal token As String)
        _token = token
    End Sub

    Protected Overrides Function GetWriterForMessage(ByVal message As System.Web.Services.Protocols.SoapClientMessage, ByVal bufferSize As Integer) As System.Xml.XmlWriter
        Dim myWriterForMessage As System.Xml.XmlWriter

        Dim myTokenHeader As TokenSoapHeader
        myTokenHeader = New TokenSoapHeader()
        myTokenHeader.Value = _token

        message.Headers.Add(myTokenHeader)
        myWriterForMessage = MyBase.GetWriterForMessage(message, bufferSize)

        Return myWriterForMessage
    End Function
End Class

I also had to create a class for my token header:

<XmlRoot(Namespace:="urn:userinfo", ElementName:="Token", DataType:="string", IsNullable:=False)> _
Public Class TokenSoapHeader
    Inherits System.Web.Services.Protocols.SoapHeader

    <XmlText()> _
    Public Value As String
End Class

Now I can run this code without any issues and the header is being passed down correctly:

Private myService As New MyExtendedServiceHost("my-token-here")
myService.Url = "http://myserver:1234/MyService"
myService.MyMethod()
查看更多
登录 后发表回答