Custom message header
This article explains about customizing the wcf message flowing between service and client.
There are certain scenario in which you to pass some information from client to service, but not as parameter in operation contracts. Example, logging system at the service we need to log user or machine information, which made request to the service. In this kind of scenario we should not pass user or machine information as parameter in operation contract. Instead we can pass the information through message flowing between client and service vice versa. The information we need to send can be appended with message header and it can be received at the server side.
Let as create sample service and client application, in which client will send “User name†information through request message and service will respond with confirmation message.
I have created Math service with Add and Subtract functionality. Client consuming this service will send his user name information as string with requested message. Once request reached the service, it will read the information from the message header and display using console window. When service responding to the client, along with operation result, it will also send confirmation message to client through message header.
Step 1: Create IMathService interface decorated with Service and Operational contract attribute
IMathService.vb
<ServiceContract()> _
Public Interface IMathService
<OperationContract()> _
Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
<OperationContract()> _
Function Subtract(ByVal a As Integer, ByVal b As Integer) As Integer
End Interface
Step 2:In this class, we have implemented Add and Subtract functionality.
PrintRequestedUserID() method will read the “UserID†message header from incoming message using OperationContext. This User information is displayed in console window.
SendResponseWithMessage() method will send a confirmation message to the client as Message header through Operation context.
MathService.vb
Public Class MathService
Implements IMathService
Public Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
Implements IMathService.Add
'This method call will retrive message send from client using MessageHeader
PrintRequestedUserID()
'This method call will send message to client using MessageHeader
SendResponseWithMessage()
Return a + b
End Function
Public Function Subtract(ByVal a As Integer, ByVal b As Integer) As Integer
Implements IMathService.Subtract
'This method call will retrive message send from client using MessageHeader
PrintRequestedUserID()
'This method call will send message to client using MessageHeader
SendResponseWithMessage()
Return a - b
End Function
Private Sub PrintRequestedUserID()
Dim userID As String = String.Empty
'Read the message header using "Name" and "NameSpace"
userID = OperationContext.Current.IncomingMessageHeaders
.GetHeader(Of String)("UserID", "ns")
Console.WriteLine("Requested user: " + userID)
End Sub
Private Sub SendResponseWithMessage()
'Creating new message header with "Content" value assigned in constructor
Dim mess As New MessageHeader(Of String)("This is sample message from service")
'Assigning Name and NameSpace to the message header value at server side
Dim header As System.ServiceModel.
Channels.MessageHeader = mess.GetUntypedHeader("ServiceMessage", "ns")
'Adding message header with OperationContext
'which will be received at the client side
OperationContext.Current.OutgoingMessageHeaders.Add(header)
End Sub
End Class
Step 3: Hosting the MathService using console application
MyServiceHost.vb
Module MyServiceHost
Sub Main()
'Hosting the Math service using console application
Dim host As New ServiceHost(GetType(MyService.MathService))
host.Open()
Console.WriteLine("Service is running... Press to exit.")
Console.ReadLine()
End Sub
End Module
Web.Config
<system.serviceModel>
<services><service name="MyService.MathService"
behaviorConfiguration="MyServiceBehavior">
<endpoint address ="MathService" binding="basicHttpBinding"
contract="MyService.IMathService"/>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8090/MyService"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors >
<behavior name ="MyServiceBehavior">
<serviceMetadata httpGetEnabled ="true"/>
<serviceDebug includeExceptionDetailInFaults ="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Step 4: Created console client application which add “UserID†as message header to service using Operation context before calling Add() functionality. Once the response is received from the service, it is trying to read the confirmation message from service using Operation context.
Sub Main()
'Creating proxy class for service
Dim proxy As IMathService = Nothing
proxy = ChannelFactory(Of IMathService).CreateChannel(New BasicHttpBinding(),
New EndpointAddress("http://localhost:8090/MyService/MathService"))
'Lifetime of OperationContextScope defines the scope for OperationContext.
Dim scope As OperationContextScope = Nothing
scope = New OperationContextScope(proxy)
'Creating new message header with "Content" value assigned in constructor
Dim mess As New MessageHeader(Of String)
(System.Security.Principal.WindowsIdentity.GetCurrent().Name)
'Assigning Name and NameSpace to the message header value at client side
Dim header As System.ServiceModel.Channels.MessageHeader
= mess.GetUntypedHeader("UserID", "ns")
'Adding message header with OperationContext
'which will be received at the server side
OperationContext.Current.OutgoingMessageHeaders.Add(header)
'Making service call
Console.WriteLine("Sum of {0},{1}={2}", 1, 2, proxy.Add(1, 2))
'Displaying confrimation message from service
Console.WriteLine("Response Message: " + OperationContext.Current.
IncomingMessageHeaders.GetHeader(Of String)("ServiceMessage", "ns"))
Console.ReadLine()
End Sub
End Module
<ServiceContract()> _
Public Interface IMathService
Inherits IClientChannel
<OperationContract()> _
Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
<OperationContract()> _
Function Subtract(ByVal a As Integer, ByVal b As Integer) As Integer
End Interface
Step 5: Run the MyServiceHost
Step 6: Run the MyClientApplication
Below figure shows the message flowing between service and client
Client application output
Console hosted service output screen
Conclusion:
This article explain about customizing the wcf message header
Tips!
- Always create the service with Interface->Implementation format, mention the contract in Interface.
- Define the service in Class library and refer the class library in Host project. Don’t use service class in host project.
- Change the instance mode to per call as default.
- Always catch exception using try/catch block and throw exception using FaultException < T >.
- Logging and Include exception should be enable while compiling the project in debug mode. While in production deployment disable the logging and Include exception details.