3. Validating and Storing Properties in the Designer
As in any
component development model, it is necessary to store properties that a
user selects for your component so you can load them at runtime and also
validate that the values chosen by the user are appropriate. To perform
validation, you need to use the IComponentUI interface and implement the Validate function. To store and load information for runtime use, you use the IPersistPropertyBag interface and implement the Load and Save functions. Example method implementations are given in the following text.
3.1. Validating User Input
IComponentUI.Validate
is used to validate any property information and display an error
message to the user when the project is compiled if properties are not
set up properly or if they're set up inconsistently. Most
implementations use either a collection or an ArrayList to store the errors. You then need to return the IEnumeratorArrayList or collection at the end of the method with all the error messages you want displayed populated. object from the
The following example
demonstrates how you can validate a developer's input from within the
IDE. Any errors are returned to the user as errors in the IDE's error
window.
'<summary>
'The Validate method is called by the BizTalk Editor during the build
'of a BizTalk project.
'</summary>
'<param name="obj">An Object containing the configuration 'properties.</param>
'<returns>The IEnumerator enables the caller to enumerate through a collection of
'strings containing error messages. These error messages appear as compiler error
'messages. To report successful property validation, the method should return an
'empty enumerator.</returns>
Public Function Validate(ByVal obj As Object) As System.Collections.IEnumerator_
Implements Microsoft.BizTalk.Component.Interop.IComponentUI.Validate
'example implementation:
Dim errorArray As New ArrayList
errorArray.Add("This is an error that will be shown...")
return errorArray.GetEnumerator
End Function
3.2. Using the Property Bag to Store Property Information
In order to store property information for pipeline components, you need to implement the IPersistPropertyBag interface and give an implementation to the Save and Load methods. These methods pass in the representative IPropertyBag object that will be used to store the property information. The IPropertyBag
is simply a structure that will hold a set of key/value pairs. The key
is a string, and the value is of type Object so it can accept any type.
You may ask yourself, "Why not store the object itself rather than
storing the name of the schema and constructing a New() object in the Load method?" The answer is because the Save function of the component will fail if you do this. When the properties are written to the ContextPropertyBag,
they are actually expressed within the BTP file as XML so that they can
be used for per-instance pipeline configuration.
The following code snippet shows how you can use the property bag to read and write custom properties from a pipeline component:
'<summary>
'Loads configuration properties 5for the component
'</summary>
'<param name="pb">Configuration property bag</param>
'<param name="errlog">Error status</param>
Public Overridable Sub Load(ByVal pb As _
Microsoft.BizTalk.Component.Interop.IPropertyBag, ByVal errlog As Integer) _
Implements Microsoft.BizTalk.Component.Interop.IPersistPropertyBag.Load
Dim val As Object = Nothing
val = Me.ReadPropertyBag(pb, "MyDocSpec")
If (Not (val) Is Nothing) Then
Me._MyDocSpec = New _
Microsoft.BizTalk.Component.Utilities.SchemaWithNone(CType(val, String))
End If
val = Me.ReadPropertyBag(pb, "OutboundDocumentSpecification")
If (Not (val) Is Nothing) Then
Me._OutboundDocumentSpecification = New _
Microsoft.BizTalk.Component.Utilities.SchemaWithNone(CType(val, String))
End If
val = Me.ReadPropertyBag(pb, "FileRootNode")
If (Not (val) Is Nothing) Then
Me._FileRootNode = val
End If
val = Me.ReadPropertyBag(pb, "DataElementNode")
If (Not (val) Is Nothing) Then
Me._DataElementNode = val
End If
End Sub
'<summary>
'Saves the current component configuration into the property bag
'<summary>
'<param name="pb">Configuration property bag</param>
'<param name="fClearDirty">not used</param>
'<param name="fSaveAllProperties">not used</param>
Public Overridable Sub Save(ByVal pb As _
Microsoft.BizTalk.Component.Interop.IPropertyBag, ByVal fClearDirty As Boolean, _
ByVal fSaveAllProperties As Boolean) Implements _
Microsoft.BizTalk.Component.Interop.IPersistPropertyBag.Save
Me.WritePropertyBag(pb, "MyDocSpec", Me.MyDocSpec.SchemaName)
Me.WritePropertyBag(pb, "OutDocSpec", Me.OutboundDocumentSpecification.SchemaName
Me.WritePropertyBag(pb, "FileRootNode", Me.FileRootNode)
Me.WritePropertyBag(pb, "DataElementNode", Me.DataElementNode)
End Sub
'<summary>
'Reads property value from property bag
'</summary>
'<param name="pb">Property bag</param>
'<param name="propName">Name of property</param>
'<returns>Value of the property</returns>
Private Function ReadPropertyBag(ByVal pb As _
Microsoft.BizTalk.Component.Interop.IPropertyBag, _
ByVal propName As String) As Object
Dim val As Object = Nothing
Try
pb.Read(propName, val, 0)
Catch e As System.ArgumentException
Return val
Catch e As System.Exception
Throw New System.ApplicationException(e.Message)
End Try
Return val
End Function
'<summary>
'Writes property values into a property bag.
'</summary>
'<param name="pb">Property bag.</param>
'<param name="propName">Name of property.</param>
'<param name="val">Value of property.</param>
Private Sub WritePropertyBag(ByVal pb As _
Microsoft.BizTalk.Component.Interop.IPropertyBag, _
ByVal propName As String, ByVal val As Object)
Try
pb.Write(propName, Val)
Catch e As System.Exception
Throw New System.ApplicationException(e.Message)
End Try
End Sub
3.3. Custom Properties and Per-Instance Pipeline Configuration
Per-instance pipeline configuration allows you to change
the values of custom properties using the BizTalk Administration Tools.
The user interface provides you with a mechanism to set the values for
pipeline properties dynamically for a receive location without having to
create a new custom pipeline for every new receive location. A few
points of interest when attempting to use this feature with a custom
pipeline and pipeline components are described here.
Custom pipeline
component properties for per-instance pipeline configuration are
actually stored within the .btp file for the pipeline definition. A
sample of the file follows. If you find that your custom properties are
not appearing in the per-instance pipeline configuration document, you
can manually add them to the XML of the .btp file, and they will appear.
<?xml version="1.0" encoding="utf-16"?>
<Document xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
PolicyFilePath="BTSReceivePolicy.xml" MajorVersion="1" MinorVersion="0">
<Description />
<Stages>
<Stage CategoryId="9d0e4103-4cce-4536-83fa-4a5040674ad6">
<Components />
</Stage>
<Stage CategoryId="9d0e4105-4cce-4536-83fa-4a5040674ad6">
<Components />
</Stage>
<Stage CategoryId="9d0e410d-4cce-4536-83fa-4a5040674ad6">
<Components>
<Component>
<Name>ABC.BizTalk.PipelineComponents.Decoder</Name>
<Properties>
<Property Name="MyUnTypedProperty" />
<Property Name="MyStringProperty">
<Value xsi:type="xsd:string">My String Value</Value>
</Property>
</Properties>
<CachedDisplayName>Decoding Component</CachedDisplayName>
<CachedIsManaged>true</CachedIsManaged>
</Component>
</Components>
</Stage>
<Stage CategoryId="9d0e410e-4cce-4536-83fa-4a5040674ad6">
<Components />
</Stage>
</Stages>
</Document>
In the .btp file
for the pipeline definition, you can set the default data of the
pipeline component property by inserting a value in the property's <Value> element.
The <Value>
that you insert must be an XSD type. For example, the type must be
xsd:string for a string value, or xsd:int for an integer value.