When you look at how a disassembling component is
structured, essentially you are building new documents that get
submitted to the Messagebox. In our previous examples, we used the SchemaWithNone and SchemaWithList objects as properties to allow the user to choose what type of document should be accepted through the IProbeMessage
interface. If you take this one step further, you could build a generic
disassembling component that allows the user to select what type of
document they want to accept and that provides them with an interface to
choose what type of document will be produced. The custom logic will
still need to be created to extract the values for the new document, but
at least the schema type will be available. But how can you actually
create a new message? You will know the schema type of the message, but
how do you create a new XMLDocument with all the available nodes already inserted but empty?
There are two ways to
accomplish this task: the right way and not-so-right way. The
not-so-right way is the simplest. What most people do is hard-code the
XML for the new empty document in a string and assign it to a new XMLDocument
object. This approach can be cumbersome for a number of reasons, the
most important being that if the structure of the message ever changes,
the code will need to be recompiled. Another "wrong," but more correct,
way would be to load the XML from a configuration file at runtime or
include it as a resource file that is imported when the assembly is
loaded. This is still a pain, since you will have to manually keep this
in sync with the actual BizTalk schema.
A different way to do this is to use an undocumented API, which allows you to create a new blank XMLDocument based on the DocumentSpec
class. Unfortunately, this class is unsupported and is not made public
by the BizTalk product team. It does work well, however, but you need to
think about the support implications of using this class in your
solution. For most, this isn't an issue, because the other alternative
is to create a schema walker class as documented at http://msdn.microsoft.com/en-us/library/aa302296.aspx.
Our only issue is that a significant amount of code is required to
implement the schema walker. Also, depending on how you create your
schema, certain attributes and imports may not be picked up in the new
empty document. We have also found a few compatibility issues between
the documents that it generates and BizTalk's validation engine. In the
end, it is a good solution if you are wary about using an undocumented
class, but using the class that exists within the BizTalk Framework
guarantees that your documents will match the schema within the engine
and will validate properly.
The first thought that comes
to many people's minds when they think about creating documents is
"Okay, I agree that having an external resource file and keeping it in
sync with the actual schema is a pain, but won't my code need to change
anyway if I have a schema change?" The answer to this is maybe. In many
cases, the code that creates and populates new document instances uses
only certain fields. Often schema changes involve adding new elements to
the schema, not removing them, or changing element names. In this case,
should the BizTalk schema be modified to include new elements, then no
code needs modification, and new XML instances will be created with
empty elements as you would expect. In the case where fields have been
renamed or removed, you will need to determine whether your pipeline
component has explicitly added values to those nodes via an XPath
expression. If the component has, then you will need a code change.
In order to generate the
new empty document in your pipeline component or orchestration, you need
to create an instance of the following class:
Microsoft.Biztalk.Component.Interop.DocumentSpec.
This class is found in the Microsoft.BizTalk.Pipeline assembly.
Imports Microsoft.BizTalk.Component.Interop
Imports Microsoft.BizTalk.ExplorerOM
Imports System.Xml
Imports System.Text
Imports System.IO
'schemaFullName has to match the value
'in the docspec_name column of the bt_DocumentSpec table in the
'BizTalkMgmtDb database
Public Function CreateNewBTSDoument(ByVal schemaFullName As String) As XmlDocument
Dim newDocument As XmlDocument = Nothing
Dim catExplorer As New BtsCatalogExplorer
Dim Schemas As SchemaCollection
Dim myDocSpec As DocumentSpec = Nothing
Dim mySchema As Schema
Dim sbuilder As New StringBuilder()
catExplorer.ConnectionString = "Integrated Security=SSPI; " & _
" Persist Security_Info=false; Server=(local); Database=BizTalkMgmtDb;"
Schemas = catExplorer.Schemas
mySchema = Schemas(schemaFullName)
If Not (mySchema Is Nothing) Then
myDocSpec = New DocumentSpec(schemaFullName, _
mySchema.BtsAssembly.DisplayName)
If Not (myDocSpec Is Nothing) Then
Dim writer As New StringWriter(sbuilder)
Try
newdocument = New XmlDocument()
'create and load the new instance into the return value
newdocument.Load(myDocSpec.CreateXmlInstance(writer))
Finally
writer.Dispose()
End Try
End If
End If
Return newDocument
End Function