|
using System;
using System.Diagnostics;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Web.Services.Protocols;
using System.Xml;
using System.Xml.XPath;
using XLANG = Microsoft.XLANGs.RuntimeTypes;
using System.Globalization;
using System.Xml.Xsl;
namespace ESB.ExceptionHandling.ServiceModel.Dispatcher
{
/// <summary>
/// This class can be customized to create a message inspector.
/// </summary>
public class ErrorHandler : IErrorHandler, IServiceBehavior
{
#region Public Constructors
public ErrorHandler()
{
}
#endregion
#region Properties
public string Map { get; set; }
#endregion
#region IServiceBehavior Members
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.AddBindingParameters]");
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.ApplyDispatchBehavior]");
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.ApplyDispatchBehavior] Map: {0}", Map));
ErrorHandler errorHandler = new ErrorHandler();
errorHandler.Map = Map;
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
if (channelDispatcher != null)
{
channelDispatcher.ErrorHandlers.Add(errorHandler);
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.Validate]");
}
#endregion
#region IErrorHandler Members
public bool HandleError(Exception error)
{
//Trace the error for debugging purposes
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.HandleError]");
Exception exception = error;
while (exception != null)
{
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.HandleError] Exception type: {0}", exception.GetType().FullName));
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.HandleError] Exception message: {0}", exception.Message));
exception = exception.InnerException;
}
//WCF must NOT abort the session
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.ProvideFault]");
try
{
if (error != null)
{
//Trace the error for debugging purposes
Exception exception = error;
while (exception != null)
{
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.ProvideFault] Exception type: {0}", exception.GetType().FullName));
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.ProvideFault] Exception message: {0}", exception.Message));
exception = exception.InnerException;
}
}
//Create our custom fault message
fault = CreateErrorMessage(fault, "An unexpected error occured", error);
}
catch (Exception exception)
{
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.ProvideFault] ================ Major error ==============");
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.ProvideFault] " + exception.GetType().FullName));
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.ProvideFault] " + exception.Message));
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.ProvideFault] ===========================================");
//Create our custom fault message
fault = CreateErrorMessage(fault, "An unexpected error occured", error);
}
finally
{
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.ProvideFault]");
}
}
#endregion
#region Private Methods
private Message CreateErrorMessage(Message message, string errorMessage, Exception exception)
{
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.CreateErrorMessage]");
string action = null;
if (message != null &&
message.Headers != null)
action = message.Headers.Action;
string messageType = "http://schemas.xmlsoap.org/soap/envelope/#Fault";
//Prepare to use our body writer to create a message
StringBuilder stringBuilder = new StringBuilder();
//Create the SOAP Fault body
using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder))
{
using (XmlDictionaryWriter xmlDictionaryWriter = XmlDictionaryWriter.CreateDictionaryWriter(xmlWriter))
{
//Create an instance of our body writer
BodyWriter bodyWriter = new ErrorBodyWriter("soap:Receiver",
exception.Message,
action,
errorMessage,
exception);
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.CreateErrorMessage] Creating SOAP Fault");
//Execute the body writer
bodyWriter.WriteBodyContents(xmlDictionaryWriter);
//Flush the stream
xmlDictionaryWriter.Flush();
}
}
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.CreateErrorMessage] SOAP Fault message body: {0}", stringBuilder.ToString()));
if (!string.IsNullOrEmpty(Map))
{
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.CreateErrorMessage] Executing Map: {0}", Map));
//A map has been configured so let's execute it.
// Note: if executing the map fails in any way, we return the
// SOAP Fault created above
using (MemoryStream streamIn = new MemoryStream(Encoding.Unicode.GetBytes(stringBuilder.ToString())))
{
//Perform the transform
Stream streamOut = TransformStream(streamIn, Map, ref messageType);
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.CreateErrorMessage] Getting the new message body");
using (StreamReader streamReader = new StreamReader(streamOut))
{
//Get the contents of the transform stream
stringBuilder = new StringBuilder(streamReader.ReadToEnd());
}
}
}
else
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.CreateErrorMessage] No map to execute");
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.CreateErrorMessage] Response message body: {0}", stringBuilder.ToString()));
TextReader textReader = new StringReader(stringBuilder.ToString());
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.CreateErrorMessage] Creating the response message");
//Convert the raw message (stringBuilder) to a Message
Message replyMessage = Message.CreateMessage(MessageVersion.Default,
messageType,
XmlReader.Create(textReader));
//Return the message
return replyMessage;
}
private Stream TransformStream(Stream streamIn, string mapName, ref string messageType)
{
try
{
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.TransformStream]");
//Get the data type of the map
Type type = Type.GetType(mapName);
if (type == null)
throw new Exception(string.Format("The type for {0} was not a valid map type.", mapName));
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.TransformStream] Map type: {0}", type.FullName));
//Load the map
XLANG.TransformMetaData transformMetaData = XLANG.TransformMetaData.For(type);
//Get the schema information of the source message from the map
XLANG.SchemaMetadata schemaMetadataSource = transformMetaData.SourceSchemas[0];
//Get the schema type of the soruce message in the map
string schemaName = schemaMetadataSource.SchemaName;
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.TransformStream] Map source schema: {0}", schemaName));
//Check that the message type of the input stream matches the message type of the
// source schema in the map
if (!string.Equals(messageType, schemaName, StringComparison.InvariantCultureIgnoreCase))
{
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.TransformStream] Map source schema not the same as the given message type");
//The message type is not the same as the map source schema so don't
// run the map
return streamIn;
}
//Get the schema information of the target message from the map
XLANG.SchemaMetadata schemaMetadataTarget = transformMetaData.TargetSchemas[0];
//Get the message type of the target of the map
messageType = schemaMetadataTarget.SchemaName;
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.TransformStream] Map target schema: {0}", messageType));
//Prepare the input stream
XPathDocument input = new XPathDocument(streamIn);
XslTransform transform = transformMetaData.Transform;
//Create the output stream
Stream streamOut = new MemoryStream();
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.TransformStream] About to map");
//Perform the transform
transform.Transform(input, transformMetaData.ArgumentList, streamOut);
//Finalise the output stream
streamOut.Flush();
streamOut.Seek(0L, SeekOrigin.Begin);
Trace.WriteLine("[ESB Dispatcher.ErrorHandler.TransformStream] Mapping done");
return streamOut;
}
catch (Exception exception)
{
Trace.WriteLine(string.Format("[ESB Dispatcher.ErrorHandler.TransformStream] An error occured executing the map: {0}", exception.Message));
return streamIn;
}
}
#endregion
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I have almost 20 years commercial software development using a number of languages from C++ to C#/VB. My main focus has been in the Microsoft space and, since the early 2000's, most of this has been in the web or integration arena. Over the past few years I have been focusing on building business solutions using a variety of products such as BizTalk and Share Point.
In terms of SDLC's, I have experience with various methodologies such as Agile, RUP, Iterative and Waterfall.
Lastly, the roles I have had in the last few years have given me the opportunity to gain a lot of experience as a consultant. Since, over the last 18 years, I have worked with many customers this has further given me the chance to enjoy many and varying challenges that have helped me grow in my career.
Today, I spend a lot of time talking, designing, documenting and mentoring team members. I also spend quite a bit of time authoring software and find the combination a perfect fit for me.
Specialties
Consultancy, Solution architecture, Solution design, Project costing and tracking, Team lead, Software development, C#, VB, ASP.NET, HTML, DHTML, JavaScript, BizTalk, SharePoint