Showing posts with label BizTalk 2006. Show all posts
Showing posts with label BizTalk 2006. Show all posts

Monday, October 4, 2010

BizTalk: HTTP Adapter and preventing Cached Responses

A while back I blogged about a service that would go fetch Natural Gas Prices, the price of Oil and Stock Quotes from Yahoo.    The information that is returned from BizTalk is surfaced in an Xcelsius dashboard along with a lot of other business critical data from SAP.  Our executive team accesses this information from a web part in SharePoint site.  As people launch their browsers, they see the Stock Quotes and other commodity prices get updated.  Since this is a dashboard, people will view the data for a few minutes and then close their browser.  This type of user behavior never uncovered a flaw in the application.  It is not like someone sat on the dashboard all day long waiting for the stock price to change.

A request came in to turn this Dashboard into a Windows 7 widget.  Once this widget was in place, we uncovered that the stock quotes were not being updated.   The Widget simply acts as a container for the dashboard.  So we dug out Fiddler and could determine that the BizTalk service was not being called on a regular interval.  The reason?  Caching.  There was no cache command or expiration date sent on the HTTP header going back to the dashboard so it would not be called on a regular basis.  Since this Widget does not get restarted like a Web Browser does, the stock quotes would remain static for the duration of a user’s desktop session.

To avoid this situation, I needed to provide an explicit command in a Message Assignment Shape to prevent my responses from being cached:

msgStockQuoteResponse(HTTP.UserHttpHeaders) ="Cache-Control: no-cache";

Since the client was instructed not to cache the response, it would now go ahead and call the service when it goes to refresh the rest of its data.

 

image

 

There are many options that you can set within the HTTP Header.  For example,  if you wanted to expire content every 2 minutes, you could set your header to  Cache-Control: max-age=120.  If you are interested in what other features can be set in an HTTP Header, I recommend checking out this site.

Saturday, June 20, 2009

Clustering MQ Series and BizTalk Send/Receive

We have a 3rd party application that uses MQ Series as an integration bridge. BizTalk is used to manage a business process and perform message transformation between this system and our ERP.

We have been using this configuration for the past couple years and it came time to upgrade this 3rd party application. This application now supports Websphere MQ 6.0 where as we were previously running Websphere MQ 5.3. Since it was time for an upgrade and we do have a pretty large BizTalk farm with a team that is responsible for supporting both BizTalk and MQ we decided to install MQ 6.0 on this same cluster(as BizTalk)...for better or worse(it is
supported).

In our previous configuration we had MQ 5.3 running on an Active/Passive Cluster that did not include BizTalk. When running BizTalk 2006 and wanting to use the MQ Series Adapter, there is a component that you must install on the MQ Series servers. The component that is installed is called MQSAgent*. Now if you are running BizTalk 2004 then the component is called MQSAgent where as if you are running BizTalk 2006 it is called MQSAgent2. According to this doc, the component is still called MQSAgent2 for BizTalk 2009. In our previous configuration, I must admit it was rock solid. We never had any fail over issues whatsoever.

We recently ran into some issues in the Test environment with the new configuration. We found that you needed to ensure that MS Distributed Transaction Coordinator (MS DTC) and MQ Series on the same node in order for it to function correctly. MSDTC is leveraged to support Guaranteed Reliable message delivery.

The specific problem that we ran into was that when we failed the MQ Resource group over to a new node, BizTalk would essentially just hang(with respect to MQ message processing). We couldn't send or receive messages with MQ. I then ran into this kb: The BizTalk Server Adapter for MQSeries version 2.0 no longer retrieves messages from a clustered MQSeries queue manager when the queue manager fails over to a different cluster node. This paragraph accurately describes our scenario:

You may configure the Microsoft BizTalk Server Adapter for MQSeries version 2.0 to receive messages from a clustered MQSeries queue manager. If the queue manager fails over to a different cluster node, the BizTalk Server Adapter for MQSeries no longer retrieves messages from the clustered MQSeries queue. When this behavior occurs, the following event is logged in the Application event log:

Event Type: Warning
Event Source: BizTalk Server 2006
Event Category: BizTalk Server 2006
Event ID: 5740
Date: 6/20/2009Time: 10:16:40 AM
User: N/A
Computer:
Description:The adapter "MQSeries" raised an error message. Details "Error encountered on opening Queue Manager name = ISVC.MSG4.QM.T Reason code = 2059.".
For more information, see Help and Support Center at
http://go.microsoft.com/fwlink/events.asp.

Later on in the kb it describes a "Workaround" *cough* HACK */cough* that is suppose to terminate the MQSAgent from the node that previously was hosting the MQ/MSDTC Resource group.


Option Explicit
On Error Resume Next

Dim sComputerName, oWMIService, colRunningServices, oService, colProcessList, objProcess

If Wscript.Arguments.Count = 0 Then

sComputerName = "."
Call ServStat
Wscript.Quit
End If

Sub ServStat
Set oWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & sComputerName& "\root\cimv2")
Set colRunningServices = oWMIService.ExecQuery _
("Select * from Win32_Service where DisplayName='Distributed Transaction Coordinator'")

For Each oService in colRunningServices
'Wscript.Echo oService.DisplayName & VbTab & oService.State
if (oService.State="Stopped") Then
'Wscript.Echo "Stopped"
' find the dllhost
Set colProcessList = oWMIService.ExecQuery ("SELECT * FROM Win32_Process WHERE Name = 'DLLHOST.EXE'")

For Each objProcess in colProcessList
if inStr(objProcess.CommandLine, "6D06157A-730B-4CB3-BD11-D48AC6B8A4BB")>0 then

'Wscript.Echo objProcess.ProcessId
Dim objShell
Set objShell = CreateObject("WScript.Shell")
objShell.Run "cmd /k kill -f " & objProcess.ProcessId & "& exit"
WScript.Quit
end if
Next
end if
Next

End Sub
I have highlighted two issues with this script in red:


  1. The ID 6D06157A-730B-4CB3-BD11-D48AC6B8A4BB that they are referring to in the script is for the MQSAgent (BizTalk 2004) and not BizTalk 2006. The MQSAgent2 ID (BizTalk 2006) is C691D827-19A0-42E2-B5E8-2892401481F5.



  2. The other issue is that the script will issue the following command to kill the MQSAgent# process on the server that use to host the DTC/MQ Resource group. objShell.Run "cmd /k kill -f " & objProcess.ProcessId & "& exit The problem with this is that the kill command is not available on Windows 2003 and I suspect Windows 2008 as well. This command has been replaced with Taskkill. I opted to go a different route since the script they have provided is based upon WMI and VBscript I have replaced this line with objProcess.Terminate()

My testing to this point have been very successful. I have not had to manually intevene whatsoever and have not lost any messages when failing resources over or rebooting servers. The only delay that you will see is if you have messages inflight while you bounce resources is that if the Queue is still down that BizTalk will use the Send Port's configuration to issue retries. This is very standard BizTalk behaviour and is performing as expected.

So what does this script do? It essentially looks to see if the DTC service is running on the node that this script is running on. If the DTC service is running, the script will exit since we still need the MQSAgent to run on this server with DTC. If DTC is not running then it will look for a process called 'DLLHOST.EXE' that has a Process ID (PID) of the MQSAgent. If it finds an instance of this process it will terminate it so that this process does not lock up BizTalk from sending or receiving messages with MQ Series.

This sounds like an opportunity to cluster the MQSAgent application. However, the guidance from Microsoft is to not cluster it:

There is no requirement to cluster the MQSAgent (MQSAgent2) COM+ application that is used with the BizTalk Server MQSeries adapter. To provide high availability for this component, install the component on each cluster node. If the COM+ application stops, the next call from the client will start it.

I don't know...seems pretty clunky to me. I will have to follow up further with support.

Sunday, June 7, 2009

Adventures with the HTTP Adapter and Yahoo Finance API

I was asked to investigate what would be involved in connecting BizTalk to a Yahoo Finance "api" in order to retrieve stock quotes. This is not a mission critical application but they wanted to be able to consume this information. The client "COTS" application can consume a WSDL, but not a HTTP response that includes comma delmitted data. So we figured that we could expose this data via a web service. There are certainly many ways to expose this data and this is not the point of this post.

The point of the post is to discuss some of the pitfalls that I ran into when trying to connect to this Yahoo API using the BizTalk HTTP Adapter. At first, I thought the problem was rather trivial, I opened IE, pointed it at the Yahoo URL, included the Stock Ticker and the format that I was interested in. The browser returned a string of data that included the stock quote and the other relevant data.

http://download.finance.yahoo.com/d/quotes.csv?s=MSFT&d=t&f=sl1d1t1c1ohgvj1pp2wern


I then saved a copy of this data into a text file, ran it through the BizTalk Flat file schema wizard, created a Receive Pipeline based upon this schema and now had "typed" data for use inside of BizTalk.

At this point, I was a little unsure of what Yahoo was expecting when I made this Http Request. I created a "dummy" schema which only had a root node and figured that I would submit the request to Yahoo to see what was going to happen. Initially, I had a static send port where I hard coded the URL. The URL was very important since it contains the HTTP Request query parameters. I figured that once I get this working, then I will focus on making it dynamic so that the client application can drive which stock quote is returned.

However, this is when I started to run into issues. When I tried to run my application using this configuration I was prompted with the following response from YAHOO: Missing Symbols List.

Based upon this error, I figured that something was up with the query parameters. Yahoo is expecting something along the lines of ?s=MSFT&d=t&f=sl1d1t1c1ohgvj1pp2wern to be past as part of the HTTP Request. After performing some BING searches someone suggested using a dynamic send port to pass these query parameters in. That didn't help either.

I then decided to open up Fiddler to see what was being passed as a successful request. Fiddler is a tool that can be used to inspect HTTP Requests and Responses.
When you use the Request Builder feature in Fiddler, it will default the HTTP request mode to "GET". It makes sense, but I then thought what if I switch this to POST? Look for the red line towards the bottom of the next image: "Missing Symbols List".

At this point, I am starting to understand the problem a little better. After another Bing search, I found the following document that indicates: "The HTTP send adapter gets messages from BizTalk Server and sends them to a destination URL on an HTTP POST request". Using Fiddler, I was able to determine that using a GET request worked without issue. Now knowing that the BizTalk HTTP Adapter is going to use a POST request, I figured that I needed to be able to get Fiddler to work with a POST request and then get BizTalk to use this same approach when posting data to Yahoo.

I am not going to get into the differences between POST and GET here as it has been done so many times before, but here is a good summary of the differences.

Since the query string is essentially being ignored anyways, I removed it from the URL Address text box. I then copied the query parameters into the "Request Body" text box without the '?'

Success! The next challenge is to get BizTalk to pass this data through the HTTP adapter as a POST request.

I found an old forum post by CranCran77 that discussed sending a message of type RawString to a different website that was also looking for HTTP Get. I have used the RawString class before when sending emails via BizTalk, so I was able to add this class to my project quickly.




In the image above, I have highlighted the "Construct Yahoo Request" Message Assignment shape. Below, I have the details of what is inside this message construct shape. Here I am assigning values to my message body that is of type "RawString". This RawString class has been added to a .Net Helper Assembly.


After the message is sent, I can look in the tracking database and can see that this data was transmitted as part of the message body.


Since the parameters that Yahoo requires are being sent as part of the message body, we may use a static Send Port and do not have to provide a query string.

With the emergence of SOAP and now WCF, the use of the HTTP adapter is limited. But as you can see there are still some "services" that exist on the web that rely upon HTTP. Unfortunately there is not a lot of good documentation on the HTTP adapter so hopefully this post fills in some of the gaps.

Sunday, January 4, 2009

BizTalk 2006 - Message Viewer HAT Plugin

A tool that I have been using for a few months now, that I have not had a chance to blog about, is the Message Viewer HAT Plugin. The tool is available for free download on codeplex and was written/posted by someone with the handle of faizelk.

What does the tool do?
The tool allows you to view messages from within the Health and Activity Tracking (HAT) tool without having to save each message to disk.

Why should I use this tool?
If you have every played the "blame" game then you know that searching for messages inside of HAT can be a time consuming process. Especially if you don't have a promoted property to limit your search. You usually end up saving messages to disk to inspect them. This goes on for a bit until you actually find the message that you are looking for.

This tool will save you a lot of time as you don't have to leave the HAT tool to actually view message bodies. This of course assumes you have enabled message body tracking.

For those of you who are unfamiliar with the "blame" game that is when you are on an integration project with multiple parties and the finger pointing begins. HAT, with message body tracking enabled, becomes the tool of choice because you can provide "the evidence" of what BizTalk did. The conversation usually goes something like this: "BizTalk did what it was suppose to do, this is the message that I received and this is what I sent". The stakes and intensity of the game usually increase with the number of participants and systems involved. :-)

Install process
It is a simple process:
  • Download the zip file from here

  • Extract the Bizspoke.BizTalk.HATPlugIn.dll to the following BizTalk directory: X:\Program Files\Microsoft BizTalk Server 2006\Tracking\Plugins where 'X:' is the drive in which you have installed BizTalk on.

Running the Tool
The first thing you will need to do is launch HAT. Once HAT is available, click on "Queries" - "Most recent 100 service instances". Modify your query if desired.

Right mouse click on your desired message. You will now see a new item added to the menu. Click on the item called "(Bizspoke) View tracked messages...".


A .Net form will launch that will contain the "goods". From within this form you will find:

  • The Message Body displayed on the right hand side

  • The Message's context properties in the lower left

  • The ability to Save the Message(s). This function works the same way that it does from within HAT; it will save all of the messages and context files

  • The ability to view the XML file in Internet Explorer

  • If you have selected a bunch of messages that you want to view, you can use the "Previous" and "Next" buttons to navigate through them.

Consider the scenario where you are tracking messages before and after port processing. These scenarios would include dealing with Flat Files where you have built a Flat File schema and are calling it in a Pipeline or when using the SAP Adapter to receive/send IDocs. In these scenarios, you have the ability to choose which message(s) that you want to track from within the Port - Tracking configuration in BizTalk Admin. If you choose to track both messages, the Message Viewer Plug-in will list both messages in the left frame and you can then choose which file you want displayed in the message body frame.

In my example, I have tracked a SAP IDoc(which is essentially a flat file) so it will get displayed in the "Text" tab. This message represents one that has been tracked before port processing (I received the message).

The second message body is the XML version of the IDoc; the one that BizTalk will use internally. By selecting this message and the "XML" tab, I can see it in a XML friendly format.


BizTalk Versions?
I have been using this tool with BizTalk Server 2006 R1. We have it deployed in all of our environments including Production - it is that valuable. If you have been keeping up with this blog, you may have noticed that I have a post regarding HAT's status in BizTalk 2009 Beta. For kicks, I copied the dll into the equivalent folder in my BizTalk 2009 installation folder and it didn't have any affect(it does not show up in any BizTalk Admin Console menus). So I am not sure how this tool will fit in moving forward, but if you are running BizTalk Server 2006, I recommend installing this tool.