I ran into an issue recently when in an existing Console Application project we're forced to remove a reference to WSE 3.0. When I tried to remove it from references (because I could not find where it's used) it turned out there is only one place and it's using the SoapEnvelope
class.
A little bit about the application: it's a console application that connects to an Exchange Server and listens to incoming emails, around 2-3k emails daily.
The SoapEnvelope
class is used to read and parse the email body:
/// <summary>
/// Reads content of received HTTP request.
/// </summary>
/// <param name="client">The specified client.</param>
/// <returns>The watermark string if the read is successful; otherwise the last watermark.</returns>
public string Read(TcpClient client)
{
try
{
_myReadBuffer = new byte[client.ReceiveBufferSize];
using (var networkStream = client.GetStream())
{
var httpRequest = new MailboxHttpRequest(networkStream);
if (httpRequest.HasBody)
{
var httpResponse = new MailboxHttpResponse(_mailbox);
httpResponse.ParseBody(httpRequest.Body);
httpResponse.Send(networkStream, httpRequest.Body);
}
return httpRequest.Watermark;
}
}
catch (Exception ex)
{
Logger.WriteErrorLine("[EventsCollector] Error calling Read in MailboxNotificationManager", ex);
return _mailbox.LastWatermark;
}
finally
{
_myReadBuffer = null;
}
}
And the ParseBody methods looks like this:
/// <summary>
/// Parses the XML body content of receive notification and initialized email processing, if new message was received.
/// </summary>
/// <param name="body">XML content of received notification.</param>
public void ParseBody(string body)
{
var soapEnvelope = new SoapEnvelope() { InnerXml = body };
var serializer = new XmlSerializer(typeof(SendNotificationResponseType));
using (var reader = new XmlNodeReader(soapEnvelope.Body.FirstChild))
{
var notificationResponse = (SendNotificationResponseType)serializer.Deserialize(reader);
if (notificationResponse.ResponseMessages != null) // Process notification, if request contains response message
{
_result = processNotification(notificationResponse);
}
}
}
As you can see, it creates a SoapEnvelope class to access the body`s first child.
MailboxHttpRequest class
private class MailboxHttpRequest
{
private readonly Regex _httpRequestBodyLengthPattern = new Regex(@"Content-Length: (?<BodyLength>\d*)", RegexOptions.Compiled);
private readonly Regex _httpRequestBodyPattern = new Regex(@"<\?xml .*", RegexOptions.Compiled);
private readonly Regex _httpRequestWatermarkPattern = new Regex(@"<t:Watermark>(?<Watermark>.*?)<\/t:Watermark>", RegexOptions.Compiled);
private const int _bufferSize = 8192;
public bool HasBody
{
get { return !String.IsNullOrEmpty(Body); }
}
public string Body { get; private set; }
public string Watermark { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="MailboxHttpRequest"/> class and reads incoming messages
/// </summary>
/// <param name="networkStream">The network stream.</param>
public MailboxHttpRequest(NetworkStream networkStream)
{
var completeRequest = new StringBuilder();
var readBuffer = new byte[_bufferSize];
do // Read incoming message that might consist of many parts
{
var newDataLength = networkStream.Read(readBuffer, 0, readBuffer.Length);
completeRequest.Append(Encoding.ASCII.GetString(readBuffer, 0, newDataLength));
}
while (networkStream.DataAvailable || !requestWasFullyReceived(completeRequest.ToString()));
Body = _httpRequestBodyPattern.Match(completeRequest.ToString())
.Value;
Watermark = _httpRequestWatermarkPattern.Match(Body).Groups["Watermark"].Value;
}
}
The downside is that I`m not able test this part of code since I cant listen to same mailbox so I cant check what and how does the passed string look like.
If anybody has any suggestion on how to replace the SoapEnvelope
class, would be greatly appreciate it.
Cosmin