Interesting tech stuff I come across day-to-day. Mainly around Biztalk and .NET 3.0

MVP Summit 2008

Monday, April 14, 2008

It's exactly 24 hours since I started my journey from London Heathrow to attend the 2008 MVP summit, I'm still travelling. I'm writing this blog post from Chicago O'hare airport at 5:30 AM in the morning. It's not a good start, it looks like I'm going to miss the morning session of the summit.

Lesson Learned: Avoid change overs in US from International to Domestic with short time duration.  Don't plan to reach your destination very late.

To add to my short transit time, my Air India flight was delayed by almost 1hr:45 minutes. I knew very clearly there is no chance of catching my connecting flight. As expected I missed my connecting flight from Chicago to Seattle, to add to my shock list they said they couldn't find any seat availability for whole of Monday to Seattle. Luckily after spending 30 minutes with the Air India staff they found one via St. Louis for next day which will take me to Seattle at around 11AM, but again the transit time is less than 30 minutes to get my connecting flight from St. Louis to Seattle. I was put in a near by Hotel for that night.

I arrived at the airport at around 4:45AM next day, the airport staff gave me two options either to take the flight via St. Louis or take a direct flight to Seattle which will take me 45 minutes later than the original one. With previous night experience I happily grabbed the offer in both hands to take the direct flight. Now I need to wait for another 3 hours in the airport to catch my flight.

Hope this terrible events will end here, and I'll have a good enjoyable conference. I'll miss the morning session, but hopefully there should be plenty more for me to cheer up for rest of the event.

I'll try my level best to convey the message (of course useful technical stuff, not all this blabbing), I can during the course of the conference.

-Saravana




Extended XmlValidation Pipeline Component

Saturday, April 05, 2008

It's always a good practice to validate your incoming messages against schema to make sure you discard useless messages up front and avoiding unnecessary processing.

BizTalk allows you to verify the validity of the incoming Xml message against deployed schema in few different ways. Some of the easy options are

  1. Using XmlReceive pipeline and setting the ValidateDocument property to true.
  2. Create a custom Receive Pipeline and use the XmlValidate pipeline component in the validate stage.

In both the scenarios, the incoming message is validated inside a receive pipeline and an exception is raised if the message fails validation, eventually suspending the pipeline service instance. You'll see description of the error messages both in event log and suspended instance with associated messages in the admin console.

Here are the few challenges in a real world situation:

  1. The default Xml validation component supplied with BizTalk (both the above cases) only notifies you about the very first error message it encounters.
  2. It simply suspends the service instance, and its all your responsibility to take necessary action (configure routing failure, or administrator taking appropriate action etc). If you don't take any action, the consumer won't get any clue about the validation failure.

Our (improved) requirements are:

  1. We need to get all the schema validation exceptions at one go. Say for example, if there are 4 validation errors in the incoming message, then we need to see the reasons for all the 4 errors.
  2. Also, there should be an accessible error message with all the error descriptions, which we can map it to a response to send it back to the consumer (explained later.) in addition to suspending the service instances.

NOTE: Attached sample code got all the relevant materials discussed in this article.

Sample Schema, Extended Pipeline component code, Sample receive pipeline, Sample Orchestration and required binding file.

Test Schema definition:

clip_image002

Restrictions:

employeeId: Is a string that contain only numbers of 5 chars long.

jobSpecification: Manager, Programmer, Analyst.

firstName/lastName: Can only be of alphabets.

Validation using XmlReceive default pipeline:

You can enable validation inside the default XmlReceive pipeline by setting ValidateDocument property to true. But there is a trick, if you enable this property you need to set the DocumentSpecName property as well specifying the schemas. Unfortunately it doesn't resolve the schemas automatically, and you'll see clear exception message saying

There was a failure executing the receive pipeline: "Microsoft.BizTalk.DefaultPipelines.XMLReceive, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Source: "XML disassembler" Receive Port: "Receive.XmlReceive" URI: "C:\@Blog\XmlValidation\FileDrop\XmlReceive\In\*.xml" Reason: Validation can only be performed when document schemas are provided.

DocumentSpecName property must be specified in this format (it's not documented clearly and took me a while to figure out)

DDL.Demo.Schemas.EmployeeRequest, DDL.Demo.Schemas, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c2b0cafd9314ef3e

DDL.Demo.Schemas: Schema .net namespace

EmployeeRequest: Type name defined for the Schema

DDL.Demo.Schemas: Fully qualified assembly name.

(You can easy get these values from BizTalk Admin Console by opening the schema)

If you receive more than one message type inside the same pipeline, you can add multiple DocumentSpecNames by splitting it with a pipe (|) symbol.

Validation using XmlValidator pipeline component:

Configuring and performing validation using the out of the box XmlValidator component is simple. Follow these easy steps:

  1. Create a blank BizTalk project and add New item of type Receive Pipeline
  2. From the BizTalk tool box, drag and drop the XmlValidator component into the Validate Stage
  3. Assign strong key and deploy the pipeline.
  4. In the BizTalk administration console, create a receive port/ location utilizing the pipeline deployed in #3.
  5. Get a message into the configured receive port via your choice of adapter File, HTTP, etc

The XmlValidator component should resolve the schema dynamically and validate the message against the schema. If there are any exceptions it will raise an exception and suspends the instance.

Testing:

I created a sample message as shown below

clip_image004

There are 3 invalid elements in the schema. employeeId is not in the right format and both first name and last name got some invalid characters (according to our schema definition only alphabets are allowed).

Firing the above message with validation enabled (either one of the above methods) will raise the exception and suspends the service instance. The exception message will be:

The document failed to validate because of the following error:"The 'employeeId' element has an invalid value according to its data type." .

Correcting the above error in the message and firing it second time will show the second validation failure as below

The document failed to validate because of the following error:"The 'firstName' element has an invalid value according to its data type." .

Extended XmlValidation pipeline component:

In most of the cases it not useful to get one error message at a time, consumers would like to receive all the validation failure messages at one go, so that they correct all of them and send the message back.

This problem forces us to write the extended XmlValidation pipeline component, which basically extend the functionality of the default BizTalk XmlValidation component to raise all the errors at one go and also give a serialized exception message, which you can easily to map it to a customer specific response message.

The complete source code is available for download here.

Firing the message via the extended validation component will raise the following error description.

There was a failure executing the receive pipeline: "DDL.Pipeline.ExtendedXmlValidation, DDL.Pipeline, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c2b0cafd9314ef3e" Source: "Pipeline " Receive Port: "Receive.ExtendedXmlValidation" URI: "C:\@Blog\XmlValidation\FileDrop\ ExtendedXmlValidation.In.ReceivePort\In\*.xml" Reason: Exception of type 'DDL.PipelineComponents.XmlValidationException' was thrown.NodeName: employeeIdNodeValue: 12 NodeNameSpace: . Severity: Error. Description: The 'employeeId' element has an invalid value according to its data type.. NodeName: firstNameNodeValue: firstName007 NodeNameSpace: . Severity: Error. Description: The 'firstName' element has an invalid value according to its data type.. NodeName: lastNameNodeValue: lastName008 NodeNameSpace: . Severity: Error. Description: The 'lastName' element has an invalid value according to its data type..

So, you can see clearly you got all the validation failures at one go and also you got extra information like the node value, severity of the error (whether its error or warning) etc.

Sending the validation failure message back to caller:

One of the other big challenges is sending this exception message to the caller or to some other system to process. Just plainly terminating the service is instance is not useful most of the time.

We utilised BizTalk 2006 ability to call Receive pipeline within orchestration to achieve this.

First a response schema is defined as shown below, which contains an errors collection node with description and nodeName elements inside.

clip_image006

The sample orchestration looks like:

clip_image008

Inside the Schema Validation expression shape we called our custom pipeline as shown below:

Microsoft.XLANGs.Pipeline.XLANGPipelineManager.ExecuteReceivePipeline((typeof(DDL.Pipeline.ExtendedXmlValidation)),MSG_EMP_REQ);

An exception handler is created to catch exceptions of type Microsoft.XLANGs.Pipeline.XLANGPipelineManagerException

Exception message is created inside the 2nd construct shape using the following statement

schemaException = (DDL.PipelineComponents.XmlValidationException)exSchemaValidation.InnerException;

MSG_XML_VALIDATION_ERROR = schemaException.ErrorCollection;

Note we are accessing the innerException property of the XLANGPipelineManager exception. 

If there are no schema validation exceptions a response message will be constructed normally (first construct shape). Else if the control goes to the exception handler block a map is applied to transform the errors from XmlValidation to the response message as shown below

clip_image010

The response message will look like:

clip_image012

Setting up the sample file:

Unzip the content to C:\@blog\XmlValidation folder. Open DDL.Demo.PipelineComponent solution and compile it, open XmlValidation.sln build and deploy it. Binding file is present.

Nandri!

Saravana




BizTalk Web Service: Enum's picking default values automatically and resulting in Xml Schema validation issues.

Thursday, February 14, 2008

Recently I encountered a serious problem with BizTalk generated web service while doing Xml validation that uses mandatory elements with enumeration.

System Background:

  1. Schemas are exposed as web services using "BizTalk Web Publishing Wizard".
  2. The messages come into BizTalk via Web Service and SOAP adapter.
  3. A custom XML schema validation pipeline component was build, which is capable of returning all the validation errors (the default out of the box BizTalk one only returns the first validation error) in a serializable error collection.
  4. Published messages are picked up by our business process Orchestration, whose first job is to validate it against the schema using the custom pipeline component created in step #3 (by using XLANGPipelineManager.ExecuteReceivePipeline inside an expression shape and capturing exception). If any validation errors are identified, then they are mapped to response message with appropriate error codes.

Our system heavily depends on the schema validation and different error codes it generates. For example, say if a mandatory element called "channel" is not supplied then an error code called INVALID_CHANNEL will be returned, the consumer will kick off different work flow based on the critical error codes. So, it's crucial for us to get the schema validation and correct error codes generation spot on.

Problem:
In our schemas, some of the critical elements are expressed as enums using "derivation-by-restriction" on xs:string. Example: An element named "channel”"(mandatory, min=1) will have enumeration values "Postal", "Email", "Fax".

Sample Valid Message:

image  

Sample Invalid Message (because mandatory "channel" element is missing):

image

If the invalid message is passed to our orchestration as it's, everything will work fine. The orchestration will do the schema validation, will detect the missing channel element and generates the appropriate response message with correct error code (INVALID_CHANNEL). But the problem lies in the web service through which the message travels. When the web service receives the above invalid message it identifies the missing "channel" and substitutes the first enumeration value as default for the missing element "channel". So, by the time the message reaches the orchestration it will look like

image

You can clearly see the problem here. The orchestration won't throw any schema validation exception since the mandatory "channel" element is present but with completely random value. This might have serious implication on the down line business systems.

Solution:
The solution to the problem is quite straight forward. All you need to know is set the "nillable" property of the "channel" element to "true".

image

We are using BizTalk Server 2006, and thanks mainly go to .NET Framework 2.0 "Nullable<T>" type. I assume the problem still persist in BizTalk Server 2004 based solution which runs on top of .NET 1.1

Under the hood:
When we don’t specify the "nillable" property, the default value is "false". This will result in web service code being generated in a normal way as shown below

image 

If you recollect in .NET data types are separated into "value" types and "reference" types. "Reference" types are allocated on the CLR heap and the value types are allocated on the stack. Most of the basic data types like int, char, bool etc fall under "value" type so as Enum and Struct.

A value type cannot be nullable because it has enough capacity to express only the values appropriate for that type; it does not have the additional capacity required to express a value of null.

When the web service deserialize the incoming message it will assign null values to the missing the properties. Since a null value cannot be assigned to the Enum type, by default it puts the first value in the list.

You need to remember, the internal representation of enum's is integers, by default it will start from "0". So, from the web service perspective it's assigning the initial value "0" to the property.

(NOTE: The heading of the post is concentrating on Enum, but you will experience similar problem with basic data types like "int" as well, if the mandatory element of type int is not supplied, after serialization an element with value "0" will automatically be inserted by the web service.)

Effect of assigning nullable = true

When we set the nullable property to true in our schema, the way web service code is generated is slightly different as shown below

image

Nullable<T> Generic structure is new in .NET 2.0 to accommodate the usage of null on value types. See this link for more information http://msdn2.microsoft.com/en-us/library/b3h38hb0.aspx

Now the web service serialization won't assing the default value to the "channel" element. It will be null instead, so when the message gets serialized it, the "channel" element wont be there.

Losing Messages:

During this exercise I also identified a strange behaviour, which is not acceptable on an enterprise system. If the serialization fails for some reason, say for example you put a wrong value for the enum, Example <channel>Pigeon</channel> or even put wrong case for example <channel>postal</channel> ('p' is lower case). There won't be any errors or warning raised by the web service and message won’t be submitted to BizTalk. (NOTE: This is applicable only to one-way web service operations).

Nandri!
Saravana




It's biztalk247.com 's first birthday

Hello readers,

image

I need to thank everyone for their overwhelming support and interest on http://www.biztalk247.com/v1 I launched the site same time last year on valentines day, to support the BizTalk community.

The site acts as a single portal containing all sort of information relevant to BizTalk Server 2004, 2006, and R2 like Search, Videos, Articles, white papers, newsgroups, aggregated blogs, and many more.

I have received numerous emails during this one year giving me suggestions, improvements and of course broken links. Thanks for everyone.

Below is the unique visitors count to http://www.biztalk247.com in the past 1 year, averaging around 3000 / month from various parts of the world.

mapoverlay

I'll try my level best to keep up the site with latest content relevant to BizTalk community.

Nandri!

Saravana




Off to Microsoft SOA and Business Process Conference

Tuesday, October 23, 2007

I'm going to Microsoft SOA and Business Process Conference running between Oct 29th to Nov 2nd. To make most out of my trip (going to spend 13hrs each way in flight) I decided to attend the 2 days pre-conference session by PluralSight presented by Matt Milner, Jon Flanders and Aaron Skonnard.

image

On the second day of the conference I'm hosting a round table session at "Ask the Expert (ATE)" reception, to cover the topic  "BizTalk Overview".

Hope to see some of you there. Please ping me if you are going to be there.

Nandri!

Saravana




SOAP Adapter and BizTalk Web Publishing Wizard - things you need to know.

Friday, August 17, 2007

Exposing an Orchestration as Web Service:

This is the safest option you can choose, when you want to expose your business process as an industry standard web service, which can later be consumed by a client (consumer) either using a web service proxy or HTTP post of correctly formatted SOAP message.

There is a very good article in MSDN http://msdn2.microsoft.com/en-US/library/ms935219.aspx explaining how you can expose your orchestration as web service.

Let's assume you have exposed your orchestration as web service, bound the inbound logical port to the auto-generated SOAP receive port (created by the wizard) and enlisted-started the Orchestration. Now, when you look at the activation subscription details for the Orchestration it will look something similar to the one shown below:

SNIPPET #1

http://schemas.microsoft.com/BizTalk/2003/system-properties.ReceivePortID == {73684F88-8D5C-4659-9E8F-F1B5E6E9A780} And

http://schemas.microsoft.com/BizTalk/2003/system-properties.MessageType == http://www.digitaldeposit.net/samples/schema/1.0#personRequest And

http://schemas.microsoft.com/BizTalk/2003/system-properties.InboundTransportType != SOAP

Or

http://schemas.microsoft.com/BizTalk/2003/system-properties.ReceivePortID == {73684F88-8D5C-4659-9E8F-F1B5E6E9A780} And

http://schemas.microsoft.com/BizTalk/2003/soap-properties.MethodName == GetPersonDetail

When you are receiving the messages via the auto-generated SOAP receive port the properties MethodName and ReceivePortID will get promoted by the SOAP adapter and the orchestration will get the message due to second subscription condition. (MethodName will equate to the Operation name you defined inside the logical port within your Orchestration)

If you inspect the first condition carefully, you'll see "if MessageType property is present then the receive adapter should NOT be SOAP". Also, the auto-generated SOAP ReceiveLocation uses PassThru pipeline, which results in MessageType property not being promoted.

This design introduces two potential problems

 (LISTING #1)

    1. Configuring MAP(S) on the auto-generated SOAP receive port will be ignored.
    2. Properties (distinguished and promoted) defined in the schema wont get into the context.

Maps will be ignored on the auto-generated SOAP Receive Port:

Usage of PassThru pipeline inside the auto-generated SOAP ReceiveLocation is bit contrary when you are using Orchestrations and dealing with XML messages. Majority of the time Orchestration subscriptions will be based on MessageType you specified on the Activation receive shape and you'll be using XmlReceive pipeline on your ReceiveLocation, so that MessageType and other property promotions (both distinguished and promoted properties defined in the schema) gets into the context. Since the MessageType property is NOT promoted anywhere in the ReceivePort (mainly due to the usage of PassThru pipeline), any MAP you configure on the ReceivePort will be ignored.

Due to the configuration of PassThru pipeline by default, any properties (both distinguished and promoted) defined in your schema won't get into to the context, which creates potential problem if you want to use content based routing.

We can fix these problems easily, by modifying the auto-generated SOAP ReceiveLocation to use XmlReceive pipeline instead of PassThru. As I mentioned in the beginning "Exposing orchestration as web-service" is the safest option, it doesn't introduce too much head aches. The problem really starts when you just want to expose your schemas as web services as explained in next topic.

Exposing schemas as web services:

The MSDN article http://msdn2.microsoft.com/en-US/library/ms935219.aspx got clear explanation of exposing schemas as web services.

After exposing your schemas as web-services using "BizTalk Web Publishing" wizard, you can create an Orchestration to consume the messages published by the auto-generated SOAP ReceivePort. The important thing to note here is the name of the "Operation" you define inside the logical port, make sure it matches the WebMethod name you have specified while generating the web-service. As shown in the below figure:

image

When you bind the logical orchestration port to physical auto-generated SOAP ReceivePort and start (enlist) the orchestration, the subscription for the orchestration will look identical to the one shown in SNIPPET #1 (earlier).

We'll hit the same problems (explained in detail earlier) outlined under "Exposing an Orchestration as web service"

  1. Map won't get applied
  2. Properties (distinguished and promoted) won't get into context

Due to the fact, the auto-generated SOAP ReceiveLocation uses PassThru pipeline by default.

If you modify the auto-generated SOAP ReceiveLocation to use XmlReceive pipeline instead of PassThru (hoping its going to fix all the problems, as we did with "Exposing an Orchestration as web service") the run-time will generate the following exception when it receives the message:

There was a failure executing the receive pipeline: "Microsoft.BizTalk.DefaultPipelines.XMLReceive, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Source: "XML disassembler" Receive Port: "WebPort_SK.ws.viaSchemas.1_0/WebService1" URI: "/SK.ws.viaSchemas.1_0/WebService1.asmx" Reason: The type SK.Schemas.Person_1_0 is not a valid part type for a message. This invalid type may be from a property schema.

The exception is mainly raised because SOAP adapter puts the wrong DocumentSpecName property in the message context and hands over the message to the pipeline. PassThru pipeline (DEFAULT Configuration on auto-generated SOAP ReceiveLocation) doesn't do any processing, so whatever value present in the property DocumentSpecName is ignored. On the other hand if you configure XmlReceive pipeline which uses XmlDisassembler, it will utilizes the "DocumentSpecName" property to resolve the schema.

Behavior of XmlDissambler inside the XmlReceive pipeline:

Having the DocumentSpecName property in the context, will force XmlDissambler pipeline component to use it, to locate your schema. If DocumentSpecName is NOT present then XmlDissambler pipeline component will go through dynamic schema resolution mechanisms to get the correct schema. Since DocumentSpecName is present with wrong value, XmlDissambler throws the exception and it clearly states "This invalid type may be from a property schema".

There are few ways you can get away from this problem

Solution #1: Use PassThru pipeline and Orchestration (DEFAULT config):

If you don't have any inbound maps to be applied on the port level and you are not dependant on promoted properties (distinguished and promoted) defined in the schema outside the orchestration, then you can use PassThru pipeline (configured by default by auto-generated SOAP receive location). The Orchestration gets the message by other subscription conditions (ex: MethodName) without the need for MessageType.

  1. You can get away from the MAP problem by applying it inside your orchestration, and
  2. You automatically get away from property promotion problem. Because when the orchestration receives a message the IBaseMessage (from adapter/pipeline) is converted into a XLANG message, which results in the process of new message construction (since messages are immutable in BizTalk server). During this step all the distinguished and promoted properties gets into the context. [This is my own prediction of how distinguished fields and promoted properties gets into the context automatically within Orchestration even though we used PassThru pipeline, I couldn't find clear documentation explaining it] and available within the Orchestration.

Solution #2: Modify the generated .asmx.cs code. Passing null instead of bodyTypeAssemblyQualifiedName:

By passing the value “null” instead of bodyTypeAssemblyQualifiedName both the problems defined in Listing #1 can be solved

//Original Code

string bodyTypeAssemblyQualifiedName = "SK.Schemas.Person_2_0, SK.Schemas, Version=1.0.0.0, Culture=neutral, PublicKeyTok" +

"en=c2b0cafd9314ef3e";

// BizTalk invocation

object[] invokeResults = this.Invoke("GetPersonDetail", invokeParams, inParamInfos, outParamInfos, 0, bodyTypeAssemblyQualifiedName, inHeaders, inoutHeaders, out inoutHeaderResponses, out outHeaderResponses, null, null, null, out unknownHeaderResponses, false, false);

//Modified Code

// BizTalk invocation

object[] invokeResults = this.Invoke("GetPersonDetail", invokeParams, inParamInfos, outParamInfos, 0, null, inHeaders, inoutHeaders, out inoutHeaderResponses, out outHeaderResponses, null, null, null, out unknownHeaderResponses, false, false);

If the value null is passed instead of bodyTypeAssemblyQualifiedName, SOAP adapter won't add the DocumentSpecName property to the context. Now, when we configure our auto-generated SOAP ReceiveLocation to use XmlReceive pipeline, the XmlDisassembler component inside XmlReceive will go through the process of automatic dynamic schema resolution mechanism, pick up the correct schema and promotes all the required properties (distinguished and promoted) defined in the schema and it also promotes the MessageType property.

Solution #3: Modify the generated .asmx.cs code. Change bodyTypeAssemblyQualifiedName property to include the schema root node.

We are going to follow a similar approach here, but instead of passing null”for bodyTypeAssemblyQualifiedName, we are actually going to pass the correct value.

//Original Code

string bodyTypeAssemblyQualifiedName = "SK.Schemas.Person_2_0, SK.Schemas, Version=1.0.0.0, Culture=neutral, PublicKeyTok" +

"en=c2b0cafd9314ef3e";

//Modified Code

string bodyTypeAssemblyQualifiedName = "SK.Schemas.Person_2_0+personRequest, SK.Schemas, Version=1.0.0.0, Culture=neutral, PublicKeyTok" +

"en=c2b0cafd9314ef3e";

The only difference is we are appending the schema root element name to the schema Type Name. You can see the correct DocumentSpecName name by

  1. Add a Receive Pipeline to your project (or to a dummy project),
  2. Drag-Drop a XmlDisassembler component
  3. Select XmlDisassembler and in the properties window, click on button next to the "Document Schemas" property. You’ll see "Schema collection property editor" window as shown in the below figure, which clearly shows the expected "DocumentSpecName" name.

image

When you expose your Orchestration as web service the auto generated code will look similar to our modified code.

NOTE: You need to be careful with Solution #2 and #3, because regenerating the web-service code will result in losing the manual changes you performed.

You can download the ZIP file containing all the sample projects I used for this research.

Nandri!

Saravana




Code Snippet: Sort nodes in an Xml Document

Friday, July 13, 2007

Scenario: Need to produce a new xml document with particular node list sorted in ascending/descending order

Code:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(@"Input.xml");

XmlDocument xmlDocCopy = new XmlDocument();
xmlDocCopy.LoadXml(xmlDoc.OuterXml);
xmlDocCopy.SelectSingleNode("//Links").RemoveAll();

XmlNode node = xmlDoc.SelectSingleNode("//Links");
XPathNavigator navigator = node.CreateNavigator();
XPathExpression selectExpression = navigator.Compile("Link/Title");
selectExpression.AddSort(".", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Text);
XPathNodeIterator nodeIterator = navigator.Select(selectExpression);
while (nodeIterator.MoveNext())
{
    XmlNode linkNode = xmlDoc.SelectSingleNode("//Link[Title=\"" + nodeIterator.Current.Value + "\"]");
    XmlNode importedLinkNode = xmlDocCopy.ImportNode(linkNode, true);
    xmlDocCopy.SelectSingleNode("//Links").AppendChild(importedLinkNode);
}

xmlDocCopy.Save(@"Output.xml");

Input:

<Section>
    <Links>
        <Link Id="1">
            <Title>Jupiter Line</Title>
            <AddedDate>27/05/2007</AddedDate>
        </Link>
        <Link Id="2">
            <Title>Alfa Line</Title>
            <AddedDate>27/05/2007</AddedDate>
        </Link>
        <Link Id="3">
            <Title>Zebra Line</Title>
            <AddedDate>27/05/2007</AddedDate>
        </Link>
        <Link Id="4">
            <Title>Copper Line</Title>
            <AddedDate>27/05/2007</AddedDate>
        </Link>
    </Links>
</Section>

Output:

<Section>
  <Links>
    <Link Id="2">
      <Title>Alfa Line</Title>
      <AddedDate>27/05/2007</AddedDate>
    </Link>
    <Link Id="4">
      <Title>Copper Line</Title>
      <AddedDate>27/05/2007</AddedDate>
    </Link>
    <Link Id="1">
      <Title>Jupiter Line</Title>
      <AddedDate>27/05/2007</AddedDate>
    </Link>
    <Link Id="3">
      <Title>Zebra Line</Title>
      <AddedDate>27/05/2007</AddedDate>
    </Link>
  </Links>
</Section>




Subject: [MVP] Congratulations! You have received the Microsoft MVP Award

Monday, July 02, 2007

mvplogo.png

Yeah, its official now. I have received the 2007 Microsoft MVP award for BizTalk Server. It's been a really fun year blogging, writing white paper, launching BizTalk 24 * 7 and just generally getting more involved in the community.

I feel proud and honored to be part of the select few that Microsoft recognizes as community leaders. I'll take this opportunity to thank each and everyone who nominated me for this award behind the scene.

 Nandri!

Saravana