BizTalk 2004 Map, Getting Distinct Values using an Inline XSLT Call Template

Need to get a distinct list of items from an XML message.

For example the XML message containing Order Items is as below:

(Note: That the Order ids are not sorted)

From the above message produce a distinct list of order ids such as below:


The custom XSLT code to get the distinct list of values looks like this:


To use an Inline XSLT Call Template inside of a BizTalk 2004 Map,
a) Create a new Map inside of your BizTalk project
b) Choose the source and destination schemas
c) Drop a Scripting Functoid on the Map, then in the properties window with
the Scripting Functoid selected,  press the -> Configure Functoid Script button.
d) For the Script type choose -> Inline XSLT Call Template. Place the XSLT into the Inline Script Buffer
window.

The map to get the distinct Order Ids looks like the below:

Note : The scripting functoid inside of the map has no incoming or outgoing links.
The Custom XSLT will handle the complete transformation. Ignore any warnings about no incoming
or outgoing links when building the project.

Download the Complete solution HERE

Creating/Modifiying Schemas in BizTalk 2004. Quick Tip.

When BizTalk 2004 is installed on a developer machine, one of the many things that
is installed is the BizTalk Editor. The BizTalk Editor is used to
create and modify .xsd schemas in VS2003 that will eventually be used in a BizTalk process.

The BizTalk Editor is broken up into three parts:
1) The left hand side displays a tree structure to add new nodes to the specification.
2) The centre displays the xml markup representation of the schema.
3) The right hand side displays the properties pane, to edit the properties of the currently
highlighed node on the left hand side tree structure.

This is illustrated below.


One of the limiting factors of the BizTalk Editor is that the centre xml markup representation
is not editable.


To be able to edit the xml markup representation of the .xsd schema do this:
1) Right mouse button on the schema and choose Open With... on the pop up menu.
2) A dialog such as the one below will appear -> In this dialog, choose XML Schema editor.


3) The .xsd schema will now display in the XML Schema Editor. This editor is more object based,
displaying each element in a box. New attributes can be added to the Invoice, Invoices and InvoiceItem
elements. The properties window, can also be used to edit individual attributes.

4) While in the editor, at the bottom choose the XML tab, as below.

5) Now the below schema can be edited directly.

Constructing BizTalk 2004 XML Messages (In an Orchestration) - Choices

Before using a BizTalk XML message inside an Orchestration , it must first be
constructed. In fact ,this is just populating the message with XML. If there is an
attempt to use the message before it is constructed, the following error will appear when 
building the BizTalk project -> use of unconstructed message 'MyMessageNameHere'.
Some messages come pre-constructed, such as messages that originate from a port, but there
will be times when a message needs to be constructed inside of an orchestration.

For example if there is a message inside an Orchestration called msgShippingInfo (that is unconstructed),
and is of type ShippingInfo.xsd and the xsd schema looks like the below:

<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns="http://ConstructingXMLMessages.ShippingInfo" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" targetNamespace="http://ConsltructingXMLMessages.ShippingInfo" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="ShippingInfo">
    <xs:complexType>
      <xs:attribute name="ShipToAddress" type="xs:string" />
      <xs:attribute name="ShipToCity" type="xs:string" />
      <xs:attribute name="ShipToCountry" type="xs:string" />
    </xs:complexType>
  </xs:element>
</xs:schema>

Then at some point, the message must be populated with some xml as below, before that message can
be used:

<ns0:ShippingInfo ShipToAddress="Some Address" ShipToCity="Some City" ShipToCountry="Some Country"
xmlns:ns0="http://ConstructingXMLMessages.ShippingInfo" />


Below are some options for constructing XML messages, inside of an Orchestration.

1) Create new message(s) from a existing message(s) using a BizTalk Map.
This is one of the more common methods. For example,
I need to map my incoming Purchase Order message to an outgoing
Invoice message. Also keep in mind that you can have multiple input messages and output messages
when mapping. For example within an Orchestration, there is an existing constructed Purchase Order and Shipping messages.
I can then use these two messages to create an Order message.

A simple example is as below: 

 

If you have not done it before :
To create a map with multiple inputs and outputs, create the needed messages
in the Orchestration View. For example , in this case an Order message,
PurchaseOrder Message and the Shipping Message.
Drop a transform shape on your orchestration and then choose the source(input) message(s).
In this case there are two : PurchaseOrder message and Shipping message.
Choose the destination(output) message(s) : Order message.
In the Transform Configuration dialog box, choose -> new map. In this case
a new map is created that looks like the above (minus any of the links and functoids between source and
destination messages). These were put in later.

2) Assign one message to another.
At some point you may need a copy of another message. If msgOrderCopy is of the same type
as msgOrderOriginal, then the below assignment can be done.


Construct msgOrderCopy
{

  msgOrderCopy = msgOrderOriginal;
  //Once the new message is constructed, it can now be modified.
  // For example if the schema for the order has distinguished fields,
  // these can now be set. XPATH can also be used to set the data in (Some xpath examples are further down).
  msgOrderCopy.OrderedBy = "Bob";

}


3) Create a message with the help of a System.XML.XMLDocument variable.

In the below example, the XML to populate the message is hardcoded inside the
expression shape. The XMLDocument variable is initially assigned to the hardcoded XML. The BizTalk message is
then assigned to the XMLDocument variable. The BizTalk message is now good to go.
This is a handy technique especially when the schemas/xml instance messages are small. If the schema
has distinguished fields, then these can then be used to set the attributes in the message with real data, otherwise XPATH
can be used to populate the ID and Name attributes of the below simple XML message. It is also
possible to alter the hardcoded XML with the real data, and then do the message assignments.

construct msgShipping
{
  // Use the Variable varXMLDom to load in some XML
 varXMLDom.LoadXml(@"<ns0:ShippingInfo ShipToAddress=""Some Address"" ShipToCity=""Some City"" ShipToCountry=""Some Country"" xmlns:ns0=""http://ConstructingXMLMessages.ShippingInfo"" />");
  // Assign the BizTalk message to the XMLDom variable. Note this can be accomplished becuase a BizTalk message derives from an XMLDocument.
  msgShipping = varXMLDom;
  // If there are Distinguished Fields available, then
  msgShipping.ShipToAddress = "1 Main Street";
  msgShipping.ShipToCity = "Toronto";
  msgShipping.ShipToCountry = "Canada";
  // If there are no distinguished fields, then XPATH can be used to set the attributes in the message.
  xpath(msgShipping , "//@ShipToAddress") = "1 Main Street";
  xpath(msgShipping, "//@ShipToCity") = "Toronto";
  xpath(msgShipping, "//@ShipToCountry") = "Canada";
 


4) Creating a more complex message using : System.XML.Document, System.XML.XMLNode,System.XML. XMLAttribute, Interim BizTalk Message
The below example, uses the same method as in 3) , but the message is more complicated.
A Looping shape is used to add the order items to an order message. The part of the orchestration that does this
is as below:

 


In the the First Expression Shape, Construct the initial Order Message (With just the Order Header), with the help of a XMLDocument variable
construct msgOrderFromAppending
{
   // Initially create the Order Header part of the Order Message
   varOrderXMLDom.LoadXml(@"<ns0:Order OrderedBy=""SomeBody"" TotalOrderAmount=""0"" xmlns:ns0=""http://ConstructingXMLMessages.Orders""></ns0:Order>");
   msgOrderFromAppending = varOrderXMLDom;

}


In the next expression shape add the order items. Note that in the Orchestration this expression
shape is in a loop, so there are multiple order items being added.


// Construct the Temp Order Message to Append the Node.
construct msgOrderFromAppendingTemp
{
   // First set the XMLDOM variable to the msgOrderFromAppending in the first shape.
   varOrderXMLDom = msgOrderFromAppending;
   // use CloneNode to make a fresh copy of msgOrderFromAppending
   varOrderXMLDom = (System.Xml.XmlDocument) varOrderXMLDom.CloneNode(true);
   // Create a new Order Item Node
   varXMLNodeOrderItemNode = varOrderXMLDom.CreateElement("OrderItems");
   // Create Amount Attribute
   varXMLAttribute = varOrderXMLDom.CreateAttribute("Amount");
   varXMLAttribute.InnerText = "0";
   varXMLNodeOrderItemNode.Attributes.Append(varXMLAttribute);
   // Create Description Attribute
   varXMLAttribute = varOrderXMLDom.CreateAttribute("Description");
   varXMLAttribute.InnerText = "A Description";
   varXMLNodeOrderItemNode.Attributes.Append(varXMLAttribute);    
   // Create Qty Attribute
   varXMLAttribute = varOrderXMLDom.CreateAttribute("Qty");
   varXMLAttribute.InnerText = "0";
   varXMLNodeOrderItemNode.Attributes.Append(varXMLAttribute);    
   // Now append the actual Order Item Node to the XML Instance
   varOrderXMLDom.FirstChild.AppendChild(varXMLNodeOrderItemNode);
   // Now actually construct the Temp message.
   msgOrderFromAppendingTemp = varOrderXMLDom;
   System.Diagnostics.Debug.WriteLine("The output is " + varOrderXMLDom.OuterXml);
}

// Now Set the Real Order Message From the Temp Message.
// This is so we can keep adding messages to the real message, without losing them.

construct msgOrderFromAppending
{
   msgOrderFromAppending = msgOrderFromAppendingTemp;
   // Set the Data in the newly added Order Item Node.
  
   // Now use XPAth to set the Data in the attributes,
   // NOTE: I could of also done this by setting the real data
   // on the XMLAttribute object -> varXMLAttribute.InnerText = "Description for Order Item : " +  System.Convert.ToString(varOrderItemCount) ;

   strvarOrderItemCount = System.Convert.ToString(varOrderItemCount); 
   xpath(msgOrderFromAppending,"//OrderItems[" + strvarOrderItemCount + "]//@Amount") = System  m.Convert.ToString(varOrderItemCount) ;
   xpath(msgOrderFromAppending,"//OrderItems[" + strvarOrderItemCount + "]//@Qty") = System.Convert.ToString(varOrderItemCount) ;
   xpath(msgOrderFromAppending,"//OrderItems[" + strvarOrderItemCount + "]//@Description") = "Description for Order Item : " +  System.Convert.ToString(varOrderItemCount) ; 
}


5) Use a .Net helper class to create the message.

As in the above example , instead of using XMLDOM type code in the orchestration, a helper
.NET class could of been called in the orchestration to create the message.
An example helper class would look like the below, just returning an XMLDocument that could be assigned to
the message inside the orchestration.

public static XmlDocument GetXmlDocumentOrderTemplate()
{
// Code to create the message.

}

Now inside the orchestration, the code to call the .Net helper class to construct the message.

Construct myOrderMessage
{

  myOrderMessage = HelperClass.GetXmlDocumentOrderTemplate 


}

Also look here


Download the above examples , Here

BizTalk 2004 Map. Mapping two input messages into one output message , plus matching content from one message to another.

I have had the problem of having a message such as a Order message, being delivered 
as two separate messages. For example, the Order header Records delivered as one XML message,
and then all the Order Items that belong to Order header Records delivered as a separate XML message.

The two separate messages being delivered look something like below:

Order Headers:

<ns0:Orders Correlator="1" xmlns:ns0="http://IDREFTest.Orders">
  <Order OrderID="6" OrderedBy="BillyBobJim" />
  <Order OrderID="1" OrderedBy="Bob" />
  <Order OrderID="2" OrderedBy="Bobby" />
  <Order OrderID="3" OrderedBy="BobbyJohn" />
  <Order OrderID="4" OrderedBy="BobbyNoItems" />
  <Order OrderID="5" OrderedBy="BillyBob" />
  <Order OrderID="0022" OrderedBy="BillyBobJim" />
</ns0:Orders>
  
  
Order Items:

<ns0:Order Correlator="1" xmlns:ns0="http://IDREFTest.OrderItems">
  <OrderItems OrderID="1" Qty="1" />
  <OrderItems OrderID="1" Qty="11" />
  <OrderItems OrderID="1" Qty="111" />
  <OrderItems OrderID="2" Qty="2" />
  <OrderItems OrderID="2" Qty="22" />
  <OrderItems OrderID="2" Qty="222" />
  <OrderItems OrderID="3" Qty="3" />
  <OrderItems OrderID="3" Qty="33" />
  <OrderItems OrderID="3" Qty="333" />
  <OrderItems OrderID="3" Qty="3333" />
  <OrderItems OrderID="5" Qty="5" />
  <OrderItems OrderID="5" Qty="1" />
  <OrderItems OrderID="5" Qty="11" />
  <OrderItems OrderID="5" Qty="111" />
  <OrderItems OrderID="6" Qty="333" />
  <OrderItems OrderID="6" Qty="3333" />
  <OrderItems OrderID="0022" Qty="3" />
  <OrderItems OrderID="0022" Qty="33" />
</ns0:Order>

My goal then was to create a final Order XML Message that looks like the below (combining
information from the two messages into one message, plus also matching the correct order items with
the correct order headers). I wanted to accomplish this by just using BTS maps and functoids
that are installed with BTS2004.

<ns0:Orders xmlns:ns0="http://IDREFTest.OrdersandOrderItems">
 <Order OrderedBy="BillyBobJim" OrderID="6">
    <OrderItems OrderID="6" Qty="333" />
    <OrderItems OrderID="6" Qty="3333" />
</Order>
 <Order OrderedBy="Bob" OrderID="1">
    <OrderItems OrderID="1" Qty="1" />
    <OrderItems OrderID="1" Qty="11" />
    <OrderItems OrderID="1" Qty="111" />
 </Order>
    <Order OrderedBy="Bobby" OrderID="2">
    <OrderItems OrderID="2" Qty="2" />
    <OrderItems OrderID="2" Qty="22" />
    <OrderItems OrderID="2" Qty="222" />
  </Order>
  <Order OrderedBy="BobbyJohn" OrderID="3">
     <OrderItems OrderID="3" Qty="3" />
     <OrderItems OrderID="3" Qty="33" />
     <OrderItems OrderID="3" Qty="333" />
     <OrderItems OrderID="3" Qty="3333" />
  </Order>
 <Order OrderedBy="BobbyNoItems" OrderID="4" />
 <Order OrderedBy="BillyBob" OrderID="5">
     <OrderItems OrderID="5" Qty="5" />
     <OrderItems OrderID="5" Qty="1" />
     <OrderItems OrderID="5" Qty="11" />
     <OrderItems OrderID="5" Qty="111" /> 
  </Order>
 <Order OrderedBy="BillyBobJim" OrderID="0022">
     <OrderItems OrderID="0022" Qty="3" />
     <OrderItems OrderID="0022" Qty="33" />
 </Order>
</ns0:Orders> 

Therefore to accomplish this:

1) Created an Orchestration that contains a parallel convoy, that correlates on
the Correlator attribute on both the Orders.xsd and OrderItems.xsd properties.

2) Created a Map with two inputs (Order Header and Order Items) and one output (OrdersAndOrderItemsAll). 
To create a map with multiple inputs and outputs, create the needed messages
in the Orchestration View. For example , in this case an OrdersOnly message,
OrderItemsOnly Message and the OrdersAndOrderItemsAll Message.
Drop a transform shape on your orchestration and then choose the source(input) message(s).
In this case there are two : OrdersOnly message and OrderItemsOnly message.
Choose the destination(output) message(s) : OrdersAndOrderItemsAll message.
In the Transform Configuration dialog box, choose -> new map. In this case
a new map is created that looks like the below (minus any of the links and functoids between source and
destination messages). These were put in later.

 


3) In the map as above, links and two looping functoids were used to create an interim message (OrdersAndOrderItemsAll)
All OrderHeader records will contain all the OrderItem records.

4) Create another map that looks like the below, using the OrdersAndOrderItemsAll message as the source and using a new
message OrdersAndOrderItems as the destination. The equal functoid is used to include only the correct orderitems with each
order header. This map creates the desired resultant xml instance.

 

Download the complete solution Here.

What I like about this solution, is that it works. What I don't like about this solution is the interim message, with each order header message
including all the order items. In my case the incoming OrderHeader message and OrderItem messages were not terribly large, therefore
the interim message was not huge. Of course there may be other ways to accomplish this, possibly using custom xslt.

Passing an XML instance to a Web Service Method via a BizTalk 2004 Orchestration Web Port -> Choices.

Need to call a web method from a BizTalk 2004 Orchestration Web Port and pass an instance of XML to the web method.
Below are some options:


1) Pass the XML as a string.

For example your Web Method that you need to call from your orchestration might look something like this:

[WebMethod]
ProcessOrder (string myOrder)
{

 System.XML.XMLDocument myOrderDom = new System.XML.XMLDocument()
 myOrderDom.load(myOrder)
   // Now have code to process the order
 System.Xml.XmlNodeList nodeList = myOrderDom.GetElementsByTagName("OrderItems");
 System.Diagnostics.Debug.WriteLine("The number of Order Items passed in with the XMLDocument is: " + nodeList.Count.ToString());
 foreach(System.Xml.XmlNode orderItemNode in nodeList)
 {
  System.Diagnostics.Debug.WriteLine("The order item node is : " + orderItemNode.OuterXml);

 } 
 

}

In the Orchestration :
To create the XML string representation of the message in your orchestration:
a) In your orchestration create a variable of type System.XML.XMLDocument

System.XML.XMLDocument varXMLDOM

b) In an expression shape assign the XMLDocument type variable to the message that
you want to pass to the XMLDocument.

varXMLDOM = msgIncomingOrder;

c) Finally set the message that contains the string parameter that will be passed to the Web Method:

msgXMLStringRequest.XMLAsString = varXMLDOM.OuterXml;


2) Pass the XML as a System.XML.XMLDocument
For example your Web Method that you need to call from your Orchestration might look something like this:


[WebMethod]
ProcessOrder (system.XMl.XMLDocument myOrder)
{

 System.Xml.XmlNodeList nodeList = myOrder.GetElementsByTagName("OrderItems");
 System.Diagnostics.Debug.WriteLine("The number of Order Items passed in with the XMLDocument is: " + nodeList.Count.ToString());
 foreach(System.Xml.XmlNode orderItemNode in nodeList)
 {
  System.Diagnostics.Debug.WriteLine("The order item node is : " + orderItemNode.OuterXml);

 }

}


In the Orchestration :
To set the message that contains the XMLDocument parameter that will be passed to the Web Method , simply set the web message to the orchestration message :
msgXMLDomRequest.XMLAsXMLDocument = msgIncomingOrder;


3) Pass the XML as a Strongly Typed Class

Your order class (defined on the Web Service side) might look something like this :

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://PassingXMLToWS.Orders")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://PassingXMLToWS.Orders", IsNullable=false)]
public class Orders
{   
 [System.Xml.Serialization.XmlElementAttribute("OrderItems", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
 public OrdersOrderItems[] OrderItems;

 [System.Xml.Serialization.XmlAttributeAttribute()]
 public string OrderId;
   
 [System.Xml.Serialization.XmlAttributeAttribute()]
 public string TotalAmount;
}


[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://PassingXMLToWS.Orders")]
public class OrdersOrderItems
{
   
 [System.Xml.Serialization.XmlAttributeAttribute()]
 public string OrderItemId;
   
 [System.Xml.Serialization.XmlAttributeAttribute()]
 public string ItemAmount;
}

Note: I created the above class by using the xsd utility that is installed with VS.Net.
a) I created an xsd BizTalk Schema, and called it Orders.xsd
b) I then generated the above class, by opening up the Visual Studio Command Prompt and then
typing in the following :
c:\passxmltowebservice> xsd Orders.xsd /c /l:cs
c) The xsd utility then created a class for me called, Orders.cs, which I then copied over to
my web service project.


Your Web method that accepts an Order class might look like the below:

[WebMethod]
public void AcceptOrderClass(Orders myOrders)
{
 System.Diagnostics.Debug.WriteLine("In AcceptOrderClass");
 System.Diagnostics.Debug.WriteLine("The Id of the Order passed in is: " + myOrders.OrderId);
 foreach (OrdersOrderItems orderItem in myOrders.OrderItems)
 {
  System.Diagnostics.Debug.WriteLine("The Id of the Order Item is " + orderItem.OrderItemId); 
 }
}


In your BizTalk project, when the Web Reference is added,
an XSD schema will be created that represents the Orders class (Called Reference.xsd).
Inside your Orchestration you create a message of type Reference.xsd and then construct this message, just like any other message.
When your message reaches the web service side it will automatically be converted to an instance of -> public class Orders  


Here is a sample of each.

 

 


 

Passing a Binary as a parameter to a Web Method from a BizTalk 2004 Orchestration Web Port

Christof Claessens has an excellent entry on how to pass a binary object
to a Send Port, such as a file send port. The binary that is saved by the 
send port using his method will automatically be saved to its native format when written out to a file. For
example : c:\myBTS2004SendLocation\MyExcelFile.xls

But using the above will not necessarily work when calling a web method
via a BizTalk Orchestration Web Port as below:

[WebMethod]
ProcessBinary (System.XML.XMLDocument binaryDocument)
{

}

The Web Method is expecting well formed XML that is not present in the binary document.
When the Web Service is called from the orchestration, the Web Service will throw an error.

A possible solution is to convert the binary document to an array Of bytes
and then call a web method via a BizTalk Orchestration Web Port as below:

[WebMethod]
ProcessBinary (System.Byte[] binaryDocument)
{

}

But when you try to add the Web Reference to a BizTalk project, you will get an error such as:
Could not generate BizTalk files. An (WebMethodName) operation parameter
or return type is an Array. Array types are not supported.

A very simple solution is to convert the binary document to an array of bytes,
then convert the array of bytes to a string using something like the code below:

byte[] myBytes;
FileStream fs = new FileStream(@"C:\myExcelDoc.xls",FileMode.Open, FileAccess.Read);
BinaryReader r = new BinaryReader(fs);
myBytes = r.ReadBytes(Convert.ToInt32(r.BaseStream.Length));
// Now convert the array of bytes to a string.
string myBase64String;
myBase64String = Convert.ToBase64String(myArrayofBytes);

The above string can now be passed to the below web method via a
BizTalk Orchestration Web Port as below:

[WebMethod]
ProcessBinary (System.String binaryDocument)
{

 byte[] arrayOfBytes;
 arrayOfBytes = Convert.FromBase64String(binaryDocument);
 FileStream fs = new FileStream(@“c:\fileout.xls“, FileMode.CreateNew);
 BinaryWriter w = new BinaryWriter(fs);
 w.Write(arrayOfBytes);  

}


Here download the complete solution.

 

 


 

BizTalk 2004 Presentation

I am doing a BizTalk 2004 presentation on Wed. June 16 at the Metro Toronto .NET User Group. So if you can make it please come.

http://www.metrotorontoug.com/User+Group+Events/97.aspx

 

 

DebugView/OutputDebugString Lives in .NET

Back in my COM+ VB6 days I always had a tough time  to
debug into my VB6 components that were running in a dllhost (COM+ Server Application
environment). Basically when the call jumped into the component that was hosted
by COM+ , it would sometimes do funny things like hang the VB6 debug session.

So one method to help debug, was to use an api in the code called OutputDebugString in addition with a little application called DBWIN32.exe, to capture and display the OutputDebugString calls in the code.   
In a nutshell DBWIN32 is a little window that captures and displays any Win32 debug output.
 
So in the VB6 COM+ component code , basically when I needed to debug something I would put in the
code:

OutputDebugString("I am debugging")

Then if the DBWIN32 window was up and running it would append to it's output:

July 7 2003 10:02:03    I am debugging


Does this work in .NET? -> Yes. But the nice thing about it is that you do not have to
use OutputDebugString API calls to add to the Win32 debug output.

Instead all I have to do is call something that I am sure you are familiar with such as:

System.Diagnostics.Debug.WriteLine("I am debugging"); or
System.Diagnostics.Trace.WriteLine("I am Tracing");

To try this out (if you haven't already, go ahead do it, you might find this useful later!) go to the following
site and download debugview :

http://www.sysinternals.com/

This is not a full blown install, but only a zip file with a little exe in it. Once you have unzipped Dbgview.exe:

1) Run Dbgview.exe. The little DebugView window will be launched.
2) Create a new .NET windows or .NET ASP application.
3) Somewhere in the code put (make sure the code is called on startup)

System.Diagnostics.Debug.WriteLine("I am debugging");
System.Diagnostics.Trace.WriteLine("I am Tracing");

4) Compile it, (but make sure that it is the debug version).
5) Run the .exe (Windows) or navigate to the URL (ASP.Net) to run the debug version.
(Note if you are in VS.NET go to menu choice Debug/Start Without Debugging or
the VS.NET Output Window will grab the debug Win32 output)
6) In the Dbgview.exe output window you should see something like:

20 3:35:37  [3476] I am debugging
20 3:35:38  [3476] I am Tracing


Why is this useful? :

1) If you have not set up a listener for your Debug or Trace output, you will
not see the debug or trace output if your are running outside the VS.NET environment.
2) This is extremely useful for Biztalk 2004 debugging , but go here to
see why :
http://blogs.msdn.com/darrenj/archive/2004/04/29/123254.aspx
3) If you are bored you can always see what else is logging Win32 debug output.
4) For other Win32 debug output listeners and discussions go here :
http://weblogs.asp.net/cszurgot/archive/2003/05/21/7368.aspx

Biztalk Server 2004 / InfoPath,Excel / Sharepoint.

 

In the last month or so I have been using the Sharepoint Adapter for Biztalk 2004.
http://www.gotdotnet.com/Community/Workspaces/viewuploads.aspx?id=0d1aa85c-cf8d-497e-84f4-3ffec8db115f

What the Sharepoint Adapter does in a nutshell is allow Biztalk
Server to poll for documents posted to a Sharepoint Document Library, grab them
and process them. Biztalk Server can also post a document up to a Sharepoint Document Library.

Why should anyone care about this?

1) Sharepoint Web Sites are a snap to set up.
For example : I can easily set up a Sharepoint Site for employees to
submit vacation requests or timesheets.

2) InfoPath and Excel (part of Office 2003) easily integrate with XML Schemas.
For example: The Vacation Request or timesheets that the employee must fill in
can be easily be created using InfoPath or Excel using an XML Schema as a datasource.

3) InfoPath Scares me.
Not because it's difficult to use , but because it is a snap to design a powerful functional 
InfoPath form using an existing XML Schema or a database as a datasource.
With an InfoPath form, you can connect to a Web Service to populate a dropdown,
do validations, and very easily create a smart client interface with minimal coding. InfoPath has a whole host of 
controls such as DropDowns,  Calendars, Buttons , Repeating Tables  Master Detail Tables and many 
more. When the InfoPath document is saved it will automatically populate the XML Schema(s) that it 
is bound to.

Just to give you a high level  workflow that incorporates
Biztalk 2004/ InfoPath / and Sharepoint.


1) The user will go into the Sharepoint Web Site.
Navigate to the Vacation Request Document Library
2) Hit the New Vacation Request form button.
3) Fill out the form.
4) Hit Save.
5) The InfoPath XML document will be saved to the Sharepoint Document Libray.
6) Biztalk will pick up the XML document from Sharepoint and process it.
7) Optionally Biztalk could post the same or another XML document back up to Sharepoint.


Scott Woodgate ( http://blogs.msdn.com/scottwoo ) was absolutely correct in saying that -> What Outlook is to Exchange Server ,
InfoPath is to Biztalk 2004. InfoPath provides a human interface to Biztalk Server.
As for Sharepoint, it is and will continue to be a very popular product.
Mainly because of its powerful configuration properties and I love it because it
integrates seamlessly with InfoPath and Biztalk 2004.

 

Setting focus back to the control that caused the PostBack in an ASP.NET Form

SmartNavigation can be set to true on your ASP.NET webform so that when postbacks occur , the page when rendered back to the browser, will navigate back to the control that caused the postback.

But SmartNavigation can be problematic especially when dynamically loading controls onto your webform.

Therefore if you have SmartNavigation turned off = false, below is a piece of code that you can call from your webform  that will add javascript to your page, to automatically navigate back to the control that originally caused the postback.

I tested the code against IE6 and Netscape 7.1.

  ///


  /// This method will take passed webPage, and find the control that caused the postback. If it finds
  /// one it will set javascript on the page to set focus to that control
  ///

  /// The web page
  public void SetFocusPostBackControl(System.Web.UI.Page webPage)
  {
   string[] ctlPostBack;
   
   ctlPostBack = webPage.Page.Request.Form.GetValues("__EVENTTARGET");
   if (ctlPostBack != null && ctlPostBack.Length > 0)
   {
    string ctlUniqueId;
    ctlUniqueId = ctlPostBack[0];
    System.Web.UI.Control findControl = webPage.Page.FindControl(ctlUniqueId);
    if ((findControl != null) &&
     (findControl is DropDownList ||
     findControl is TextBox ||
     findControl is RadioButton ||
     findControl is RadioButtonList))
    {
     string ctlClientId;
     ctlClientId = findControl.ClientID;
     string jScript;
     jScript = "<SCRIPT language=\"javascript\"> document.getElementById('" + ctlClientId + "').focus(); document.getElementById('"
     + ctlClientId + "').scrollIntoView(true) </SCRIPT>";;
     
     webPage.Page.RegisterStartupScript("focus",jScript ); 

    }
   }
  }