You can find my thoughts on a really simple message replay
(message re-processing) technique for BizTalk in Stephen Thomas' The
BizTalker newsletter. Check it out
here. For additional clarification, I've created a quick Visio
here.
I worked through a problem recently with a client that really took me by
surprise - because I would think that many BizTalk shops would be running into
this issue regularly. So! Here goes with an explanation and a
solution.
We ran into this problem initially using the MSMQ (not MSMQT) adapter with
BizTalk 2004. We had roughly 10 MSMQ receive locations, as well as a few
send ports that were using the
loopback adapter. These were all executing in the same host.
The initial symptom was that the loopback adapter appeared to not work -
messages were just not getting through! They sat in the "delivered, not
consumed state" for no good reason. But we quickly reproduced the problem
with just MSMQ receive locations (i.e. without the loopback adapter.)
On a single processor virtual machine, the repro looked like this: Create
four MSMQ receive locations, and one MSMQ send port (with the send
port subscribed to one of the receive ports, just to keep things
easy.) No messages will flow through the send port at all.
To repro:
This download has a binding file with receive ports/locations for local
(non-tx) private queues Q1-Q4, plus a send port for local private queue
NONTXQ with a filter for the first receive port. There is also a bit of
VB script to put a message into a queue...If you turn off one of the receive
locations for Q2-Q4, you'll find things work just fine. If you don't,
then (reiterating) no messages will flow through the send port.
What was the resolution? Well, with BizTalk 2004 Service Pack 1
installed, you can create a "CLR Hosting" key under the registry service
definition.
-
Open the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
-
Under BTSSvc{some GUID}, create a key called 'CLR Hosting'. (Note that
there will be a BTSSvc3.0 entry present...but you must add the key under a
BTSSvc{some GUID} key, where the GUID corresponds to the host you are dealing
with, as shown by the DisplayName value.). Example:
BTSSvc{DDEF238B-2D21-4B1E-8845-C6C67C6A86C0}.
-
Under the "CLR Hosting" key (which you will create), create the following DWORD
entries with the following values:
-
MaxIOThreads – 75 (actual # tbd)
-
MaxWorkerThreads – 75 (actual # tbd)
-
MinIOThreads – 55 (actual # tbd)
-
MinWorkerThreads – 55 (actual # tbd)
-
Restart the BizTalk host service.
In our case, we actually had to increase these values - you should determine
the values you need through testing. Consider having min worker threads
equal to 7x the number of MSMQ receive locations, and max
worker threads equal to 10x the number of MSMQ receive
locations. (More on these numbers later...)
Does the documentation address this? Good question. If you
look at the topic "Managing Multiple Receive Locations" in the MSMQ
adapter documentation, you will find some reference to this. It
indicates you should create a "CLR Hosting" key as described above...but
no actual values are mentioned (clearly just a documentation mishap.)
But why do these have to be tweaked at all? Good question.
The documentation for the MSMQ adapter has some unfortunate quotables, like:
To increase performance, Microsoft BizTalk® 2004 Adapter for MSMQ is
multi-threaded. If you have many receive locations, there may not be enough
threads available for all the receive locations. This prevents some of the
receive locations from picking up messages.
The reality is that you really shouldn't have to starve any particular receive
location because of a lack of threads...you should just wind up with increased
latency. But, such is not the implementation of the MSMQ adapter (at
least for BizTalk 2004.)
Some background: The MSMQ adapter has a "Batch Size" parameter and
a "Serial Processing" parameter that can be set per receive
location. "Batch Size" determines how many messages the adapter will
attempt to read from the queue (and submit to the message box) on each
iteration. "Serial Processing" determines whether one thread is
engaged in the peek/get/submit activity per receive location (Serial
Processing = 'true') or multiple threads (Serial Processing =
'false'). If "Serial Processing" is true, the "Batch Size" is forced to
one regardless of the actual setting.
So what is the execution flow for a given receive location? The internal
class MsmqReceiverEndpoint is instantiated per receive location, and when it
initializes, it calls
ThreadPool.QueueUserWorkItem with a reference to itself. If
"Serial Processing" is false...it does this exactly seven (7)
times.
What does it do with the QueueUserWorkItem callback? Well, when
MsmqReceiverEndpoint.ProcessWorkItem is called, it enters into a do/while
loop that doesn't exit until the endpoint (receive location)
becomes invalid (i.e. the receive location is shut town.) In other words,
ProcessWorkItem sits on a .NET thread pool thread - and if Serial Processing is
false, it sits on seven of them. The do/while loop executes a
peek on the queue (with a hard-coded 10 second timeout), and if there are
messages waiting, it receives up to "Batch Size" and submits them to the
message box. (It will give up attempting to receive a "Batch Size" worth
of messages if the 10 second timeout is reached on any attempt within the batch
receive loop - i.e. if you drop a single message on a queue, and the batch size
is greater than one, expect to wait 10 seconds before further activity
begins...) The behavior of consuming seven threads per queue leads to the
recommendation of MinWorkerThreads = 7x MSMQ receive locations provided above.
Now, I confess - I'm not a BizTalk adapter expert. But, this
design seems to be in conflict with the advice offered in "Writing
Effective BizTalk Server Adapters", where it says:
Don't starve the .NET thread pool: ...While starving
the .NET thread pool is a risk to all asynchronous programming in .NET, it is
particularly important for the BizTalk Server adapter programmer to watch out
for this. It has impacted many BizTalk Server adapters: take great care
not to starve the .NET thread pool. The .NET thread pool is a limited but
widely shared resource. It is very easy to write code that uses one of
its threads and holds onto it for ages and in so doing blocks other work items
from ever being executed....If you have multiple pieces of work to do (for
example copying messages out of MQSeries into BizTalk Server), you should
execute one work item (one batch of messages into BizTalk Server) and simply
requeue in the thread pool if there is more work to do. What ever you do,
don't sit in a while loop on the thread.
Is this fixed in BizTalk 2006? Surely it is... And, in
fact, it sure seems to be in Beta 1. The design of the adapter is a bit
different...First, "Serial Processing" refers to whether additional
messages will be received from the queue prior to
the "EndBatchComplete" event being set (downstream of
IBTDTCCommitConfirm.Done.) (This part of "Serial
Processing" is true for BizTalk 2004 as well, along with forcing the batch
size to one.) "Serial Processing" in BizTalk 2006 does not
affect how many threads will be reading from your queue - you will
have just one (despite what the Beta 1 docs say...), unless you have multiple
host instances in play. (That one thread using a large batch
size and operating with serial processing set to 'false' - not blocking on
the actual message box submission - should keep up with a fairly large
message arrival rate, but multiple host instances might be needed for your
particular case.)
More importantly, the ProcessWorkItem implementation returns immediately after
a single peek/get/submit operation (and simply calls QueueUserWorkItem again,
per the advice cited above.) (Side note: There seems to be some room in
the design for the idea that you in fact woudn't return immediately if
more than a threshold number of messages were received, but currently this
condition is "if # of messages received > BatchSize", which won't ever
happen.)
So what should I do for now with BizTalk 2004? For those using
the MSMQ Adapter with BizTalk 2004...consider whether you can set "Serial
Processing" equal to true. Keep in mind this forces you to a batch
size of 1, so this might not work depending on your message arrival rate.
If you test this configuration and find an unacceptable performance loss,
consider setting the MinWorkerThreads value to 7x the number
of MSMQ receive locations you are maintaining, and MaxWorkerThreads to roughly
10x (to provide breathing room.) As an alternative, spread
your receive locations among multiple hosts (though avoid an over-proliferation
of hosts - that has its own issues.)
And never draw any conclusions until you have performance tested at load with
your final host configuration - that is, your final allocation of send
handlers, receive handlers, send ports, and receive locations among your
hosts! Other adapters may affect the outcome if they involve polling on
the receive side, or polling on the "response" side of a solit-response send
port. (If they use a thread pool thread to do their work, they can be
affected by any adapter that consumes threads whether they themselves are
written correctly or not!) Finally, I've heard from a gentlemen who has
done extensive testing that the threading parameters above are
useful/necessary when using large numbers of MSMQT receive locations as well.
Never a dull day in BizTalk land...!
I’ve been involved a bit in getting a local BizTalk user group started – and really looking forward to seeing it get off the ground! The first time we’ll meet is Thursday, September 22nd from 6:00pm – 7:30pm, at the Microsoft offices in Bloomington.
You can expect the focus to be both on present development and operational issues for BizTalk 2004, as well as early hands-on time with BizTalk 2006. Food, beverages, fellow biztalkers…gotta love it.
Unfortunately, I won't be able to make it to the PDC this year...However, a good colleague by the name of Jordan Terrell has put together this great PST file for the PDC with all the sessions as calendar appointments. (Open as a data file in Outlook, and in the Calendar view, you will be able to select a calendar corresponding to each of the conference tracks.)
In my last entry, I discussed some ways that can making working with binding
files a bit easier. Here is another post in that same vein that addresses
a common pain point...
Un-escaping TransportTypeData
One of the annoying things about binding files is that adapters only have a
string element available to store adapter-specific information for send ports
and receive locations. As a result, adapters will store escaped XML (or
even "doubly escaped" xml...) This can be extremely hard to manage,
especially for adapters such as MQSeries that keep quite a bit of information
in this form. To solve this problem, I introduced a new command-line tool in the most
recent version of the
Deployment Framework called "ElementTunnel.exe" (the source for which is
in the
Tools download.) This utility will take in an xml file, along with
a file containing xpaths to elements that should be "encoded" or
"decoded". The end result is that you can choose to manage a "master"
binding file (not directly useable) and run ElementTunnel on it immediately
prior to deployment. (You may also run XmlPreProcess on the same file for
macro expansion! The sample in the deployment framework shows both occurring -
XmlPreProcess should occur first!)
So what does this mean? An example for a single Send Port snippet: It
means that, in the case of MQSeries, instead of storing and maintaining this
mess:
<SendPort Name="SomeQueue" IsStatic="true"
IsTwoWay="false">
<TransmitPipeline Name="SomeAssembly.SomeQueue"
FullyQualifiedName="SomeAssembly.SomeQueue,
SomeAssembly, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=bb955d799cc915b9" Type="2" />
<PrimaryTransport>
<Address>MQS://SomeServer/SomeQM/SomeQueue</Address>
<TransportTypeData><CustomProps><AdapterConfig
vt="8">&lt;Config xmlns:xsd=
;"http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&
amp;gt;&lt;uri&gt;MQS://SomeServer/SomeQM/ SomeQueue& amp;lt;/uri&gt;&lt;queueDetails&
amp;gt;SomeServer/SomeQM/SomeQueue&lt;/queueDetails& amp;gt;&lt;transactionSupported&gt;yes&
amp;lt;/transactionSupported&gt;&lt;dataConversion&gt;no&lt;/dataConversion&
amp;gt;&lt;segmentationAllowed&gt;no&lt; /segmentationAllowed&gt;&lt;fragmentationSize&
amp;gt;500&lt;/fragmentationSize&gt;&lt;ordered& amp;gt;no&lt;/ordered&gt;&lt;/Config&
amp;gt;</AdapterConfig& gt;</CustomProps></TransportTypeData>
<RetryCount>3</RetryCount>
<RetryInterval>5</RetryInterval>
...
</SendPort>
You can store and maintain this:
<SendPort Name="SomeQueue" IsStatic="true" IsTwoWay="false">
<TransmitPipeline Name="SomeAssembly.SomeQueue"
FullyQualifiedName="SomeAssembly.SomeQueue,
SomeAssembly, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=bb955d799cc915b9" Type="2" />
<PrimaryTransport>
<Address>MQS://SomeServer/SomeQM/SomeQueue</Address>
<TransportTypeData> <CustomProps>
<AdapterConfig vt="8">
<Config>
<uri>MQS://SomeServer/SomeQM/SomeQueue</uri>
<queueDetails>SomeServer/SomeQM/SomeQueue</queueDetails>
<transactionSupported>yes</transactionSupported>
<dataConversion>no</dataConversion>
<segmentationAllowed>no</segmentationAllowed>
<fragmentationSize>500</fragmentationSize>
<ordered>no</ordered>
</Config>
</AdapterConfig>
</CustomProps> </TransportTypeData>
<RetryCount>3</RetryCount>
<RetryInterval>5</RetryInterval>
...
</SendPort>
Ahhh, isn't that better? Of course, similar goodness for all other
adapters. And, in the clean version, you'll find it easier to
place/maintain XmlPreProcess macros.
In the Deployment Framework sample, you'll see that we pass the following xpaths to
ElementTunnel (along with the "master" binding file itself):
/BindingInfo/ReceivePortCollection/ReceivePort/ReceiveLocations/ReceiveLocation/
ReceiveLocationTransportTypeData/CustomProps/AdapterConfig
/BindingInfo/ReceivePortCollection/ReceivePort/ReceiveLocations/ReceiveLocation/
ReceiveLocationTransportTypeData
/BindingInfo/SendPortCollection/SendPort/*/TransportTypeData/CustomProps/AdapterConfig
/BindingInfo/SendPortCollection/SendPort/*/TransportTypeData
If you want to "unescape" your binding file (generally a one-time thing, just
to get clean content) you'll want to pass these xpaths in a slightly different order,
because of the "double escaping":
/BindingInfo/ReceivePortCollection/ReceivePort/ReceiveLocations/ReceiveLocation/
ReceiveLocationTransportTypeData
/BindingInfo/ReceivePortCollection/ReceivePort/ReceiveLocations/ReceiveLocation/
ReceiveLocationTransportTypeData/CustomProps/AdapterConfig
/BindingInfo/SendPortCollection/SendPort/*/TransportTypeData
/BindingInfo/SendPortCollection/SendPort/*/TransportTypeData/CustomProps/AdapterConfig
So! If you are managing large binding files (where escaped xml is getting in
your way), you might find this technique handy...Grab the tool, and give it a go.
With BizTalk 2004, it can be quite helpful to eventually maintain binding files as "source code". After a solution has reached a certain point of stability (where port definitions are not changing often), many projects will use the Deployment Wizard to do one last export of the binding information -- and then maintain it by hand for any future changes (storing it in version control along with the rest of the solution.)
There are some interesting benefits that come along with this. One such benefit is the ability to use the XmlPreProcess tool to merge environment-specific elements into the binding file (like URIs, retry counts, etc.), using the SettingsFileGenerator.xls spreadsheet to assist -- as has been discussed on this blog before. Even if you are not using the Deployment Framework (which uses XmlPreProcess extensively), you should consider using XmlPreProcess as a standalone tool. The ability to easily maintain a matrix of logical names (for physical endpoints, etc.) versus "environment names" (development, QA, production, etc.) is a huge help. See the example spreadsheet below. (The Deployment Framework also shows how to extend use of this same spreadsheet to manage run-time configuration settings that are stored in the BizTalk SSO.)
 (click) Optional Deployment of Port Definitions
On to a bit more advanced topic: If you have a set of port definitions that you want to conditionally deploy into a given environment, you can define a true/false value within the spreadsheet and use simple "ifdef" logic in your binding file around the port definition. For instance, you might want a particular File Send Port or Receive Location to only be active in your development and test environments. To do this, define a name such as "LogInboundPODocsToFile", and set the default value to "true" - and set it to "false" in the "production" column. Mark up your binding file accordingly. See the example spreadsheet and binding file snippet below. (When XmlPreProcess is run on this binding file, the port definition will only be included for environments where the LogInboundPODocsToFile value is true.)
 (click)
<!-- ifdef ${LogInboundPODocsToFile} --> <SendPort Name="LogSalesOrderResponse_FILE" IsStatic="true" IsTwoWay="false"> <TransmitPipeline Name="SendWithDefaultNamespaceFormat" FullyQualifiedName="SendWithDefaultNamespaceFormat, XYZCo.BizTalk.Pipelines, Version=1.0.0.0, Culture=neutral, PublicKeyToken=343bd7a15fff8d6e" Type="2" /> <PrimaryTransport> <Address>C:\Dev\FileLog\%MessageID%.xml</Address> <TransportType Name="FILE" Capabilities="11" ConfigurationClsid="5e49e3a6-b4fc-4077-b44c-22f34a242fdb" /> ... </SendPort> <!-- endif -->
Why would you want to conditionally deploy ports? Like many, I have found it useful to have an additional file-based Receive Location (associated with a Receive Port bound to an orchestration) to kick off orchestrations during development - even if the actual transport used in production will be something different. In addition, binding an orchestration to a Send Port Group allows you to have an additional file-based Send Port that will create an easy log of outbound traffic. Finally, you might create a file-based Send Port that acts as an "additional" subscriber (by Receive Port Name) to your inbound messages for an easy log of inbound traffic. (And, combined with a file-based receive port, these two mechanisms give you an easy re-processing mechanism - just drag/drop in Explorer.) But you might want all of this machinery shut off in production, hence the technique we just discussed.
Macro Recursion
Another feature within XmlPreProcess is the ability to use "macro" recursion with XmlPreProcess. This means you can define a macro (logical name) such as QueueServer (with a different value for development, QA, and production, etc.) and then define additional values in the spreadsheet that build on this such as: POAckQueue = {$QueueServer}\private$\POAckQueue. This indirection can make maintaining large numbers of endpoint URIs even easier...See the example below - where POAckQueue can now appear in the "default" column (applicable to all environments.)
 (click)
Multiple Environments
Note that the SettingsFileGenerator.xls spreadsheet provided with the Deployment Framework sample (and with XmlPreProcess) has room for four environments (development, QA, staging, and production.) However, you can simply add columns to manage additional environments if need be. One such use of this would be to create a column for "unit testing", where the URIs and other binding file substitutions point to resources under the control of your unit testing framework.
More to say on binding file management in another post...
Version 2.6 of the Deployment Framework is now available (see the download
links - the
full download,
core, and
tools have all been updated.) Future work in this area will be
about augmenting the already-great deployment story in BizTalk 2006!
The release notes below will (likely) only be interesting for folks that are
using the framework extensively.
Interesting Features:
-
If you populate the bizTalkHosts property with the name of the
Hosts that you are using, the 'servicecontroller' nant task is used for the
stop/start of BizTalk services, with a configurable timeout stored in the
'biztalkHostResetTime' nant property. This requires recopying the
BizTalk.nant.tasks.dll
to your \program files\nant\bin directory. This alleviates the problem some
users were having with timeouts in service restarts.
-
IISReset now uses configurable reset time from nant property iisResetTime.
-
Modified the sample application to demonstrate how you can maintain adapter
configuration in binding files (i.e. the TransportTypeData sections) in its
"unescaped" form -- rather than having to maintain it as escaped
xml-within-xml. This relies on a new tool - ElementTunnel.exe, which is also in
the Tools download. This is a huge help with adapters such as MQSeries
that have many configuration elements. More on this in another post.
Administrivia:
-
SSOSettingsFileImport.exe opens files with read access only, eliminating some
file locking issues.
-
Permissions on the physical directories associated with virtual directories are
now granted to the account specified as the application pool account (instead
of just aspnet account.)
-
Now using NAnt .85 RC3
-
Now using log4net 1.2.9 (thanks Campbell McNeill
for work on this!)
-
Now using the July 2005 release of
WiX (thanks to Loren Halvorsen
for work on compatibility with this.)
-
Now using XmlPreProcess
1.0 RC3 (and the associated SettingsFileGenerator.xls.) One new feature here is
the ability to use URLs that contain query strings in the spreadsheet. The
name/value pair XML files that are generated will wrap as CDATA where
appropriate. Thanks Loren!
-
Modified the sample application to demonstrate how file receive and drop
locations can be made relative to the a) project directory on a developer
workstation or b) installation directory on a server. This has actually be in
the sample application before - but it relied on the xmlpoke nant task, whereas
now it uses the XmlPreProcess mechanism we use for all other binding file
modifications.
-
Modified the deployment verification unit test in the sample application to
rely on a NUnitUtility helper class that you can pull into your own projects.
One included method allows you to examine the event log (on multiple machines)
looking for errors that BizTalk might have raised during the test - very handy,
and a potentially important component of your test.
-
Support for a local_settings file used with XmlPreProcess. It can be handy to
have an "environment specific" set of macro values that are particular to a
local workstation, and the sample application shows how this is done now.
-
Added transforms and schemas to the list of what is re-gac'd for the
updateOrchestrations target. See here
for more detail. In a recent release, I made changes that allowed for the use
of a single binding file, so that binding files as emitted by the deployment
wizard could be used (rather than splitting them by hand, which was required
early on with the Deployment Framework.) This was a good change…but the
implementation broke the "messaging only" scenario (where you have no
orchestrations.) I don't have a good fix for this yet. The workaround is as
follows: In your project's nant file, set includeOrchestrations to "true" (even
though you don't have any), and define the orchestration assembly list to be an
empty string, as shown here:
<property name="includeOrchestrations" value="true" />
<property name="orchestrations" value="" />
How do you upgrade? Extract the "core" zip file on "top" of your existing
project, and then fix up the WiX directory manually (since it will be
named BizTalkSample.WiXSetup after the unzip.) All tools and scripts will
be updated as a result. Then test...Leave a comment with any issues you
encounter. Good luck!
Will this be the last place on the web that trumpets the BizTalk 2006
beta? Likely not, but I did see it in quite a few places today.
Head to http://beta.microsoft.com with
your passport and 'BizTalkBetaTeam' for a guest ID, and then wait
patiently. (While you're waiting, consider building out a VPC image with
VS2005 beta 2 and, presumably, the latest SQL 2005 bits. SQL 2000
would be fine as well, as BizTalk 2006 will not require SQL 2005.)
This...is going to be a great release. Nothing so revolutionary that you
can't leverage all the skills that you (or your staff) have already
learned. Yet, there are many, many important feature additions and "rough
edges" removed.
Rattling off a few of the new items:
-
In-order delivery for any adapter that supports it (i.e. MSMQ, MQSeries,
etc.) In 2004, only MSMQ/T supported this. (Of course, a faulty
orchestration can break first-in-first-out - more on that in a later post.)
-
The introduction of an "Application" concept for grouping BizTalk
assets - which extends to orchestrations, role links, send port groups, send
ports, receive ports, receive locations, policies, schemas, maps,
pipelines, other resources (e.g. soap proxies), you name it!
Just as importantly, the management infrastructure understands applications -
so health/management views can be narrowed down appropriately.
-
The management infrastructure has been completely encapsulated in an MMC - HAT
is largely hidden. More interesting is that the MMC can manage multiple
BizTalk groups - and can do so remotely (by definition...)
-
A packaging/deployment solution that looks good - we'll have more to say about
that in the coming weeks! The developer experience in particular looks to
be quite good. Likely still some value-add to be done on the server side.
-
Ability to route failed messages - and subscribe in your orchestrations.
-
Calling pipelines from within orchestrations (no more loopback adapter or
similar solutions needed...)
-
Zoom and expand/collapse-state-preservation within orchestrations. (So
when you collapse that big group or scope shape, it will stay collapsed
across close/re-open.)
-
BAM integration with SQL Notification Services.
-
"Operator Role" has been defined to make allocating administration tasks a bit
easier from a security perspective.
-
Pipelines can have per-instance configuration - saving you from recreating what
were essentially a lot of duplicate pipelines! (This was possible in
2004, I believe - but not exposed cleanly.)
This will be fun...I look forward to exploring the beta bits (man, the CTP was
pretty short-lived...!)
A whole raft of whitepapers for BizTalk have been released over the last
several weeks - see here
and
here.
I completed
a whitepaper a short while back (though just released) on getting
the most out of the
BizTalk 2004 Management Pack and Microsoft
Operations Manager 2005. The paper serves as a good reference for
the management pack, but I hope it also serves another useful purpose.
Specifically, the "operational hand-off" phase of the software
development life cycle often gets short shrift - and it can cost
organizations a lot of money, downtime, and late nights. So, much of the
paper discusses the importance of having a development
team accurately communicate the "instrumentation surface area" of their
completed efforts to an operations team.
What do I mean by "instrumentation surface area"? To start, we can
consider the sum of all diagnostic logging, event logging, WMI events,
performance counters (custom or built-in), and all other mechanisms
your application uses to communicate its current operational & health
state. Moreover, we need to capture "interpretations" of this information
stream that are specific to the application. (Not just "this send port
isn't working..." but "We are currently not talking to our primary
shipping provider...") Finally, we need to capture suggested
responses and remediation - also specific to the application.
"Communicated to the operations team"...how exactly? With a Word
doc? Well, in particular, I talk about how to do this for a
BizTalk-focused solution using a custom MOM Management Pack that "derives" from
the Microsoft-supplied BizTalk 2004 Management Pack. Done right, this
will provide the highest fidelity knowledge transfer from development to
operations.
See what you think - the paper is titled "Advanced
Microsoft BizTalk Server 2004 and Microsoft Operations Manager 2005 Scenarios."
(What a mouthful...)
Comment on this post (if you like) with your thoughts on the paper or
experience in this area...
|