In Part 1 we covered setting up the Royal Mail API on their developer portal and getting the credentials needed to use the API. In Part 2 we will create the request and response logging messages that will be useful for debugging in test and production.
Request and Response
For the request message we want to log the headers as well as the body of the message, this is useful for debugging, especially with Royal Mail IT support who will want to know what headers were sent with the request.
I was not interested in the headers coming via the response message, so I haven’t logged them, although you could add this. For the response message I wanted to add something that references back to the request. I have used a guid, but you could use any object.
System.ServiceModel.Channels.Message Class
The Message class holds the entire communication between sender and receiver. So a message is either a Request from the client to the external endpoint, or a response.
Each message can only be consumed or written to once, so we need to copy the message to a MessageBuffer to be able to read it. We therefore leave the referenced message unaffected allowing us to consume the copy.
The Message.ToString() method calls a XmlDictionaryWriter which read the message and write it out as xml string to our log file.
using System; | |
using System.IO; | |
using System.ServiceModel.Channels; | |
using System.Text; | |
using System.Xml; | |
namespace RoyalMail | |
{ | |
public class LogMessage | |
{ | |
protected string fileName; | |
public void WriteLog(ref Message message) | |
{ | |
try | |
{ | |
MessageBuffer buffer = message.CreateBufferedCopy(Int32.MaxValue); | |
message = buffer.CreateMessage(); | |
Message copyMessage = buffer.CreateMessage(); | |
using (StreamWriter sw = File.CreateText(fileName)) | |
{ | |
CreateMessage(copyMessage, sw); | |
if (copyMessage.IsEmpty) return; | |
sw.WriteLine(); | |
sw.WriteLine(copyMessage.ToString()); | |
} | |
} | |
catch | |
{ | |
// ignored | |
} | |
} | |
protected virtual void CreateMessage(Message message, StreamWriter sw) { } | |
protected string GetDateStamp() | |
{ | |
return string.Format("{0}{1}{2}T{3}{4}{5}_{6}", DateTime.Now.Year, DateTime.Now.Month, | |
DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, | |
DateTime.Now.Second, DateTime.Now.Millisecond); | |
} | |
} | |
} |
Request Message Log
Using the copy of the message, extract the HTTPRequestMessageProperty headers that we added in the ClientMessageInspector and write them out to the log file with the body of the message.
using System; | |
using System.IO; | |
using System.ServiceModel.Channels; | |
namespace RoyalMail | |
{ | |
public class RequestMessage: LogMessage | |
{ | |
public RequestMessage(Guid guid) | |
{ | |
fileName = string.Format("{0}RoyalMailLog_{1:000}_{2}_Outgoing.txt", | |
Properties.Settings.Default.RoyalMailLog, GetDateStamp(), guid); | |
} | |
protected override void CreateMessage(Message message, StreamWriter sw) | |
{ | |
Uri requestUri = message.Headers.To; | |
HttpRequestMessageProperty httpReq | |
= (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name]; | |
sw.WriteLine("{0} {1}", httpReq.Method, requestUri); | |
foreach (var header in httpReq.Headers.AllKeys) | |
{ | |
sw.WriteLine("{0}: {1}", header, httpReq.Headers[header]); | |
} | |
} | |
} | |
} |
Response Message Log
Add the guid to the top of the file to reference back to the request message log. Then get the StatusCode from the HttpResponseMessageProperty and write this along with the message body out to the log file.
using System; | |
using System.IO; | |
using System.ServiceModel.Channels; | |
namespace RoyalMail | |
{ | |
public class ResponseMessage: LogMessage | |
{ | |
private Guid guid; | |
public ResponseMessage(Guid guid) | |
{ | |
fileName = string.Format("{0}RoyalMailLog_{1:000}_{2}_Incoming.txt", | |
Properties.Settings.Default.RoyalMailLog, GetDateStamp(), guid); | |
this.guid = guid; | |
} | |
protected override void CreateMessage(Message message, StreamWriter sw) | |
{ | |
sw.WriteLine("Response to request to {0}:", guid); | |
HttpResponseMessageProperty httpResp = | |
(HttpResponseMessageProperty)message.Properties[HttpResponseMessageProperty.Name]; | |
sw.WriteLine("{0} {1}", (int)httpResp.StatusCode, httpResp.StatusCode); | |
} | |
} | |
} |
In the next Post
We will finish off the .Net part of the solution adding classes that will implement IEndpointBehaviour, IClientMessageFormatter and IOperationBehaviour.
[…] have already built a ClientMessageInspector class (see Part 1 and 2) implementing the IClientMessageInspector interface. Now we need to add this message inspector to […]
LikeLike