After finding a bug in the way BizTalk executes body xpath expressions in WCF ports (details here) I came up with a custom behavior to remove the leading and trailing whitespace in an inbound xml message.
First the WCF behavior needs to be implemented, it looks like:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.ServiceModel.Description;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using My.Helpers.Xml;
namespace My.Helpers.WcfBehaviors
{
public class NormalizeMessageBehaviorExtension : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(NormalizeMessageEndpointBehavior); }
}
protected override object CreateBehavior()
{
return new NormalizeMessageEndpointBehavior();
}
}
public class NormalizeMessageEndpointBehavior : IEndpointBehavior
{
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{ }
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{ }
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new NormalizeMessageInspector());
}
public void Validate(ServiceEndpoint endpoint)
{ }
#endregion
}
public class NormalizeMessageInspector : IDispatchMessageInspector
{
#region IDispatchMessageInspector Members
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
request = NormalizeMessage(request);
return null;
}
public Message NormalizeMessage(Message inboundMessage)
{
Message normalizedMessage = null;
MessageBuffer buffer = inboundMessage.CreateBufferedCopy(Int32.MaxValue);
Message tempMessage = buffer.CreateMessage();
using (var inputStream = new MemoryStream())
{
using (var writer = XmlDictionaryWriter.CreateTextWriter(inputStream, Encoding.UTF8))
{
tempMessage.WriteBodyContents(writer);
writer.Flush();
inputStream.Position = 0;
using (MemoryStream outputStream = new MemoryStream())
{
XmlParser.Normalize(inputStream, outputStream);
using (var reader = XmlReader.Create(outputStream))
{
normalizedMessage = Message.CreateMessage(inboundMessage.Version, null, reader);
normalizedMessage.Headers.CopyHeadersFrom(inboundMessage);
normalizedMessage.Properties.CopyProperties(inboundMessage.Properties);
buffer = normalizedMessage.CreateBufferedCopy(Int32.MaxValue);
}
}
}
}
return buffer.CreateMessage();
}
public void BeforeSendReply(ref Message reply, object correlationState)
{ }
#endregion
}
}
Then the code for the normalize looks like this:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml.Linq;
using System.Xml;
using My.Helpers.Utility;
namespace My.Helpers.Xml
{
[Serializable]
public class XmlParser
{
public static void Normalize(Stream inputStream, Stream outputStream)
{
try
{
XmlReaderSettings readerSettings = new XmlReaderSettings() { ValidationType = ValidationType.None };
StreamReader tempReader = new StreamReader(inputStream);
Encoding encoding = tempReader.CurrentEncoding ?? Encoding.UTF8;
XmlReader reader = XmlReader.Create(inputStream, readerSettings);
XmlWriterSettings writerSettings = new XmlWriterSettings() { ConformanceLevel = ConformanceLevel.Auto, Encoding = encoding };
XmlWriter writer = XmlWriter.Create(outputStream, writerSettings);
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
if (reader.IsEmptyElement)
writer.WriteEndElement();
else
{
while (reader.MoveToNextAttribute())
{
if (reader.Value.Length > 0)
{
writer.WriteStartAttribute(reader.Prefix, reader.LocalName, reader.NamespaceURI);
writer.WriteString(NormalizeString(reader.Value));
writer.WriteEndAttribute();
}
else
{
writer.WriteStartAttribute(reader.Prefix, reader.LocalName, reader.NamespaceURI);
writer.WriteString(reader.Value);
writer.WriteEndAttribute();
}
}
}
break;
case XmlNodeType.Text:
string text = reader.Value;
if (text.Length > 0)
{
writer.WriteString(NormalizeString(reader.Value));
}
else
writer.WriteString(text);
break;
case XmlNodeType.CDATA:
writer.WriteCData(reader.Value);
break;
case XmlNodeType.EntityReference:
writer.WriteEntityRef(reader.Name);
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.Comment:
writer.WriteComment(reader.Value);
break;
case XmlNodeType.DocumentType:
writer.WriteDocType(
reader.Name,
reader.GetAttribute(Constants.XmlAttribute.Public),
reader.GetAttribute(Constants.XmlAttribute.System),
reader.Value);
break;
case XmlNodeType.Whitespace:
case XmlNodeType.SignificantWhitespace:
writer.WriteWhitespace(reader.Value);
break;
case XmlNodeType.EndElement:
writer.WriteFullEndElement();
break;
}
}
writer.Flush();
outputStream.Position = 0;
}
catch (Exception ex)
{
throw ex;
}
}
#region Normalize Helper Methods
private static string NormalizeString(string input)
{
StringBuilder sb = new StringBuilder();
string[] parts = input.Split(
new char[] {
Constants.Char.Space,
Constants.Char.NewLine,
Constants.Char.Tab,
Constants.Char.CarriageReturn,
Constants.Char.FormFeed,
Constants.Char.VerticalTab
},
StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < parts.Length; i++)
sb.AppendFormat(Constants.GeneralFormat.AppendSpace, parts[i]);
return sb.ToString().Trim();
}
#endregion
}
internal class Constants
{
internal class Char
{
internal const char CarriageReturn = '\r';
internal const char Comma = ',';
internal const char FormFeed = '\f';
internal const char NewLine = '\n';
internal const char Pipe = '|';
internal const char Space = ' ';
internal const char Tab = '\t';
internal const char VerticalTab = '\v';
}
internal class ContextProperty
{
internal const string SchemaStrongName = "SchemaStrongName";
}
internal class ErrorMessageFormat
{
internal const string LeadingWhiteSpaceInString = "Leading whitespace in string field {0}.";
internal const string TrailingWhiteSpaceInString = "Trailing whitespace in string field {0}.";
internal const string ConsecutiveSpacesInString = "Consecutive spaces in string field {0}.";
internal const string CRLFOrTabInString = "Carriage return, line feed or tab in string field {0}.";
}
internal class GeneralFormat
{
internal const string AppendSpace = "{0} ";
}
internal class GuidString
{
internal const string StringNormalizerClassId = "233553fa-b648-40ad-af26-d749d06ce443";
}
internal class PropertyName
{
internal const string ErrorOnNonNormalString = "ErrorOnNonNormalString";
internal const string NormalizeStrings = "NormalizeStrings";
}
internal class ResourceNames
{
internal const string StringNormalizer = "My.BizTalk.PipelineComponents.StringNormalizer";
}
internal class ResourceStrings
{
internal const string ComponentDescription = "COMPONENTDESCRIPTION";
internal const string ComponentIcon = "COMPONENTICON";
internal const string ComponentName = "COMPONENTNAME";
internal const string ComponentVersion = "COMPONENTVERSION";
}
internal class XmlAttribute
{
internal const string Public = "PUBLIC";
internal const string System = "SYSTEM";
}
internal class XmlNamespace
{
internal const string BizTalkSystemProperties = "http://schemas.microsoft.com/BizTalk/2003/system-properties";
}
}
}
To use the behavior in BizTalk just add the assembly to the GAC, and register it in the machine.config file with the rest of the behaviors that ship with .net. Then add the behavior in your WCF port configuration, and the issues with whitespace are solved!
av貼片av貼片網av貼片區av貼片排行榜av貼圖av貼圖免費影片av貼圖區av辣妹av辣妹影片avhelloavhello密碼avhiavhighavhighc2009avhighallrightsavhotnetavi視訊播放av試看av視訊短片av裸體寫真av自拍av自拍無碼免費看av自拍做愛影片av自拍影片av色妹妹av色影片下載av色情a片下載av色情dvdav草莓牛奶av電話電影下載av電影av電影0951av電影免費欣賞av非會員免費影片av裸體照av裸體照片avi播放程式avi播放程式下載av969av免費無碼影片av免費直播室
ReplyDelete目標是什麼不重要,目標能產生什麼樣的效果才重要..............................
ReplyDeletethank for share, it is very important . ̄︿ ̄..................................................
ReplyDelete大奶妹貼圖區0204性影片觀賞露點自拍淫婦女生如何自慰色情站成人笑話av激情網愛視訊美女淫蕩av成人色情電話辣妹視訊聊天性關係情色vcd自慰圖淫美成人論壇台灣色情論壇成人聊天室自拍裸女貼圖視訊成人免費a片影片av成人網成人色情色情台灣辣妹小穴太太陰毛色情訊息裸女自拍色情影片a片論壇性愛技巧美女脫胸罩性情色天堂av寫真色情視訊聊天做愛視訊成人影片床上戲情色聊天網火辣情色台灣女優性愛秘笈台灣av女優手淫自慰影片
ReplyDeleteToday is the first day of the rest of your life.......................................................
ReplyDeleteUnable to give you a heart. so have a reply to push up your post. ........................................
ReplyDeleteI love readding, and thanks for your artical. ........................................
ReplyDelete成人色情圖片激情聊天室火辣美眉520sex赤裸美女成人自拍貼圖18限性影片觀賞av色情影音聊天手淫激情成人聊天室成人色情圖片網sex520自拍走光照片淫慾18禁成人影音聊天美女台灣性網限制級女生手淫成人聊天春宮裙底風光情趣丁字褲極度震撼情色論壇露點成人視訊聊天avlive show愛愛明星露點台灣色情網站自慰少婦成人聊天網美女視訊成人頻道人妻熟女蕩婦一對多激情成人色情聊天室av成人上空秀巨奶視訊網愛聊天室一夜正妹色情貼片一對多免費美女視訊粉紅乳頭作愛影片美女聊天sexy成人色情圖片網女人胸部圖片視訊色情情色網站性關係辣妹聊天室大奶子
ReplyDelete若對自己誠實,日積月累,就無法對別人不忠了。........................................
ReplyDelete待人要誠心,做事要用心,勝負平常心。......................................................
ReplyDeleteIt's great!!............................................................
ReplyDeleteSay not all that you know, believe not all that you hear. ............................................................
ReplyDelete人有兩眼一舌,是為了觀察倍於說話的緣故。............................................................
ReplyDelete男女互悅,未必廝守終生,相愛就是美的。..................................................
ReplyDelete我們不是因為快樂而歌唱,而是唱歌使我們快樂......................................................................
ReplyDelete快樂是你與生俱來的權力,它不應該取決於你完成什麼。 ......................................................................
ReplyDelete初次造訪,安安^^. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ReplyDeletePen and ink is wits plough.................................................................
ReplyDeleteQuality is better than quantity.................................................................
ReplyDelete向著星球長驅直進的人,反比踟躕在峽路上的人,更容易達到目的。............................................................
ReplyDelete成功多屬於那些很快做出決定,卻又不輕易變更的人。而失敗也經常屬於那些很難做出決定,卻又經常變更的人.................................................................
ReplyDelete越來越多人看你的部落格 要繼續加油喔 ..................................................................
ReplyDeleteA bad workman quarrels with his tools...................................................................
ReplyDelete旁觀自己的悲傷是解脫,主觀自己的悲傷是更加悲傷................................................
ReplyDelete教育的目的,不在應該思考什麼,而是教吾人怎樣思考............................................................
ReplyDelete臨淵羨魚,不如退而結網。......................................................
ReplyDelete人應該做自己認為對的事,而不是一味跟著群眾的建議走。..................................................
ReplyDelete一棵樹除非在春天開了花,否則難望在秋天結果。..................................................
ReplyDelete不錯的資訊~我會好好記下來!............................................................
ReplyDelete生存乃是不斷地在內心與靈魂交戰;寫作是坐著審判自己。..................................................
ReplyDelete真正仁慈的人,會忘記他們做過的善行,他們全心投入現在的工作,過去的事已被遺忘。.................................................
ReplyDelete人類的聰明,並非以經驗為依歸,而是以接受經驗的行程為依歸。..................................................
ReplyDelete成熟,就是有能力適應生活中的模糊。............................................................
ReplyDelete從來愛都不知它的深度,非得等到別離的時候..................................................................
ReplyDelete來看看你逛逛blog囉,加油!..................................................................
ReplyDelete感謝你的分享 要繼續發表好文章喔..................................................
ReplyDelete當最困難的時候,也就是離成功不遠的時候。..................................................
ReplyDelete喜歡看大家的文章,祝你順心~^^ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ReplyDelete被你的人氣吸引過來~~.................................[/url]...............
ReplyDelete期待你的下次更新喔^____^..................................................
ReplyDelete