Implementing Metadata Resolver Handler
The Adapter Browse Handler and Adapter Search Handler implementations return an array of objects of type MetadataRetrievalNode. This object structure doesn’t contain the actual information about the input and output types of each operation. The input parameters and output result for each operation are depicted using the messaging format of WSDL/XML Schema. So how does the Adapter Consumer get the contract in this format from the Adapter? This is where the Adapter Metadata Resolver Handler comes in. Once the Adapter Consumer is ready to obtain the Service Contract (WSDL) for the final set of operations they have selected, the Adapter uses its WSDL Builder component to return the WSDL and XML Schema from the passed in operations. An entire category containing operations can also be passed into the WSDL Builder, which recursively finds all the leaf operations available within that category and uses them to generate the resulting service description contract.
The Adapter Consumer can get the metadata (WSDL and/or .NET proxy) using
1) Standard WCF request message
2) WS-Transfer Request
3) Svcutil.Exe
4) ASDK VS-Plug In Tools
a. Add Adapter Service Reference VS Plug-In
b. Consume Adapter Service BizTalk Project VS Plug-In
The WSDL Builder uses the in-memory Metadata Cache to get the Adapter SDK Metadata Object Model for each selected operation. If the operation is not present in the cache, it uses the Adapter Metadata Resolver Handler class to resolve the operation and type metadata. Adapter Developers are responsible for executing calls to their target system and converting target system-specific metadata formats into ASDK Metadata Object Model that is used by the Adapter SDK WSDL Builder to generate the standard contract. If the target system’s operation metadata is already expressed in XML Schema (XSD) format, the ASDK Metadata Object Model can be provided that XSD instead of having to convert to this object model from another format (for example – COBOL interface definition for CICS applications).
See the figure below to understand the flow between various components of Adapter SDK that play a part in returning the metadata in the WSDL / XML Schema format to the caller.
Figure 1: Resolve Metadata Flow Diagram
Adapter SDK Metadata Object Model
The Adapter SDK provides an encapsulated object model to capture the target application’s metadata. This model is used by the WSDL Builder to build a WCF Service Contract.
Class Name |
Derives From |
Is Abstract? |
Description |
OperationMetadata |
ICachedMetadata |
Yes |
It is an abstract class that represents the metadata for an adapter operation. The Adapter Developer can extend this class to define adapter specific operation metadata. This class is cached in the Metadata Cache by the Adapter SDK. WSDL Builder component uses this class to generate the Service Description for the client. |
ParameterizedOperationMetadata |
OperationMetadata |
No |
This class derives from OperationMetadata and serves as a default implementation for specifying metadata for a business function. The caller of this class can pass in parameters of type OperationParameter and return the result of type OperationResult. |
TypeMetadata |
ICachedMetadata |
Yes |
It is an abstract class that represents a rich data structure to be used within the adapter’s operation metadata. |
BasicTypeMetadata |
TypeMetadata |
No |
Allows setting W3C schema list, restriction and union element within this class. The behavior is set in the property content of type System.Xml.Schema.XmlSchemaSimpleTypeContent. |
EnumTypeMetadata |
BasicTypeMetadata |
No |
Sets the content by creating a type called System.Xml.Schema.XmlSchemaSimpleTypeRestriction for representing enumerations. |
CharTypeMetadata |
TypeMetadata |
No |
Class to represent a specific character type for serialization. |
DurationTypeMetadata |
TypeMetadata |
No |
Class to represent a specific duration type for serialization. |
GuidTypeMetadata |
TypeMetadata |
No |
Class to represent a specific guid type for serialization. |
StructuredTypeMetadata |
TypeMetadata |
No |
Class to define a data structure containing various members of type TypeMember. For example, for an object Employee with fields Name, Salary and HireDate. The Employee will be represented using class StructuredTypeMetadata. For each of Employee fields, the class TypeMember will be created and added to the collection property Members. |
QualifiedType |
System.Object |
Yes |
It is an abstract helper class that contains static methods to create instances of SimpleQualifiedType. |
SimpleQualifiedType |
QualifiedType |
No |
This class encapsulates the W3C Xml Schema Definition simple type using enumeration System.Xml.Schema.XmlTypeCode. For example – W3C Xml Schema xs:double, xs:string, xs:date, etc. W3C facets can also be defined for a simple type within this class. |
ComplexQualifiedType |
QualifiedType |
No |
This class defines the adapter specific complex type equivalent of W3C Xml Schema Definition complex type. It is constructed for each TypeMetadata using TypeMetadata unique ID as an input. |
QualifiedTypeContainer |
System.Object |
No |
It is a wrapper class for a SimpleQualifiedType or ComplexQualifiedType. |
OperationParameter |
QualifiedTypeContainer |
No |
OperationParameter class is used to describe a parameter signature for an operation. For example, if the parameter is of a simple type such as a string, double or int, it will contain a SImpleType. If the parameter is a rich data structure, it uses a ComplexQualifiedType class. |
OperationResult |
QualifiedTypeContainer |
No |
This class is used to describe the result for an operation. The result can be of a simple or complex qualified type. |
TypeMember |
QualifiedTypeContainer |
No |
This class is used within a StructuredTypeMetadata to provide details about various members of a rich data structure. The type member can be of a simple or complex qualified type. |
OperationParameterDirection |
System.Object |
No |
It defines the direction of an operation parameter. The valid values are: · In · Out · InOut |
TypeMetadataCollection |
System.Object |
No |
It is a custom collection containing objects of type TypeMetadata. |
Let’s continue with the DLL adapter example introduced in the previous post to extend our sample to now implement metadata resolver handler.
Step 1: Implement ResolveOperationMetadata and IsOperationMetadataValid methods in Adapter implementation of IMetadataResolverHandler interface
Here is a sample code snippet for a simple operation with signature string SayHelloWorld( int count ) before we continue with implementing it for the DLL adapter example.
public OperationMetadata ResolveOperationMetadata(string operationId, TimeSpan timeout, out TypeMetadataCollection extraTypeMetadataResolved)
{
bool useCustomSchema = false;
extraTypeMetadataResolved = null;
if ("Hello/SayHelloWorld".Equals(operationId))
{
// USE CUSTOM SCHEMA
if (useCustomSchema)
{
SayHelloWorldOperationMetadata om = new SayHelloWorldOperationMetadata("Hello/SayHelloWorld", "SayHelloWorld");
return om;
}
// USE LOB ADAPTER SDK METADATA OBJECT MODEL
else
{
ParameterizedOperationMetadata om = new ParameterizedOperationMetadata("Hello/SayHelloWorld", "SayHelloWorld");
om.OperationNamespace = HelloWorldAdapter.SERVICENAMESPACE;
// TODO - the node ID is not set
// syntax: String SayHelloWorld( String aName );
OperationParameter parm1 = new OperationParameter("aName", OperationParameterDirection.In, new SimpleQualifiedType(XmlTypeCode.String), false);
parm1.Description = "Hello World is said by this name.";
// Expected result: aName says Hello World
OperationResult result = new OperationResult(new SimpleQualifiedType(XmlTypeCode.String), false);
om.Parameters = new List<OperationParameter>();
om.Parameters.Add(parm1);
om.OperationResult = result;
return om;
}
}
return null;
}
Step 2: Implement ResolveTypeMetadata and IsTypeMetadataValid methods in Adapter implementation of IMetadataResolverHandler interface
Here is a sample code snippet –
public TypeMetadata ResolveTypeMetadata(string typeId, TimeSpan timeout, out TypeMetadataCollection extraTypeMetadataResolved)
{
extraTypeMetadataResolved = null;
// set the loaded assembly
Assembly myLoadedAssembly = this.Connection.LoadedAssembly;
// load the classes from assembly
Type myType = myLoadedAssembly.GetType(typeId);
if (myType != null)
{
StructuredTypeMetadata customType = new StructuredTypeMetadata(typeId, myType.Name);
customType.TypeNamespace = MyExistingLibraryAdapter.SERVICENAMESPACE;
FieldInfo[] fields = myType.GetFields();
foreach ( FieldInfo fieldInfo in fields)
{
TypeMember typeMember = new TypeMember(fieldInfo.Name, MyExistingLibraryOperationMetadata.ResolveType(fieldInfo.FieldType), false);
customType.Members.Add(typeMember);
}
customType.NeverExpires = true;
return customType;
}
return null;
}
Step 5: Test the Adapter Resolver Functionality
1) Using WCF Channel Programming
This method shows how Adapter’s Resolver functionality can be called using WCF channel programming. We will first get all the nodes using metadata browse and then we will pass these nodes to the metadata service, so that it can resolve the input and output types for each operation.
class Program
{
static void Main(string[] args)
{
// Create the instance of the binding
MyExistingLibraryAdapterBinding binding = new MyExistingLibraryAdapterBinding();
// Create endpoint address
EndpointAddress address = new EndpointAddress("reflect://@c:/temp/MyExistingLibrary.dll");
// Create channel factory
ChannelFactory<IMetadataRetrievalContract> channelFactory = new ChannelFactory<IMetadataRetrievalContract>(binding);
// Open the channel factory
channelFactory.Open();
// Create a new channel to invoke metadata service in the adapter
IMetadataRetrievalContract proxy = channelFactory.CreateChannel(address);
// Invoke Browse method starting from the root node
MetadataRetrievalNode[] rootNodes = proxy.Browse("/", 0, Int32.MaxValue);
// Invoke GetMetadata method
System.Web.Services.Description.ServiceDescription sd = proxy.GetMetadata(rootNodes);
// Write the WSDL in the file system
sd.Write("c:\\temp\\CodeLibrary.wsdl");
Console.WriteLine("WSDL generated!");
// Close channel factory
channelFactory.Close();
}
}
Here is the expected output, when this console program is run. Open the generated WSDL file from this program. This WSDL file should contain all the operations (as we selected the root node) as the GetWsdl method of the WSDL Builder recursively obtains all the available operations from a given category node. Check the input parameters and output result of each operation
WSDL generated!
2) Using MetadataExchangeClient
This will use the WS-Transfer protocol to connect to the adapter and get metadata for the passed in operations.
The following snippet shows you how to accomplish this –
class Program
{
static void Main(string[] args)
{
// Declare an EndpointAddress and initialize it with the URI for MEX address
EndpointAddress mexAddress = new EndpointAddress("reflect://@c:/temp/MyExistingLibrary.dll?wsdl&op=MyExistingLibrary.CalculatorService/Subtract");
// Create a metadata exchange client that will retrieve metadata according to the WS-MEX standard
MetadataExchangeClient mexClient = new MetadataExchangeClient("reflect");
// Obtain the metadata
MetadataSet metadataSet = mexClient.GetMetadata(mexAddress);
// For each metadata section, do something - in this case just print the section dialect
int i = 0;
string wsdlFileName;
foreach (MetadataSection section in metadataSet.MetadataSections)
{
// Retrieve the first service description found
System.Web.Services.Description.ServiceDescription wsdl =
(System.Web.Services.Description.ServiceDescription) section.Metadata;
Console.WriteLine("Writing WSDL for: " + section.Identifier);
// Write the WSDL in the file system
wsdlFileName = "c:\\temp\\reflect" + i++ + ".wsdl";
wsdl.Write(wsdlFileName);
Console.WriteLine("WSDL " + wsdlFileName + " generated!");
}
}
}
Here is the expected output. The resulting WSDL file should only contain the metadata definition for one selected operation “MyExistingLibrary.CalculatorService/Subtract” as provided in the endpoint address.
Writing WSDL for: reflect://My.Existing.Library.Adapter
WSDL c:\temp\reflect0.wsdl generated!
3) Using Add Adapter Service Reference VS Plug-In
Right-click on a non-BizTalk VS Project and select “Add Adapter Service Reference…”. This will bring up the Add Adapter Service Reference UI. Once the adapter binding is registered with the WCF configuration system, the adapter binding will show up in the Select a binding drop down box. Select your adapter binding, enter Connection Uri and click on Connect. If the connection is successful, you should be able to see the browse results in left-hand tree pane labeled as Select a category. Choose operations and/or categories from Available Categories and Operations and click on OK. This will generate a client proxy file in the selected project. It uses the binding name in the name of the generated file. For example, unless overridden, the client for HelloWorldAdapterBinding will generate a proxy file called HelloWorldAdapterBindingClient.{ext}, where {ext} is "cs" or "vb" depending on the type of selected VS project.
4) Using Consume Adapter Service BizTalk Project VS Plug-In
Create a BizTalk Project in Visual Studio for experiencing Consume Adapter Service BizTalk Project VS Plug-In. Right-click on this project, select “Add Generated Items > Consume Adapter Service …”. This will bring up the Consume Adapter Service UI. This UI has same browse behavior as the Add Adapter Service Reference UI with the exception that clicking on OK after selecting operations generates XML Schemas instead of a .NET proxy.
5) Using Svcutil.Exe
You can also use WCF Service Metadata Utility Tool Svcutil.Exe to obtain the metadata.
· Generating the contract with all the operations in the adapter
o For generating proxy file: Svcutil reflect://localhost/c:/temp/MyExistingLibrary.dll
o For generating WSDL file: Svcutil /t:metadata reflect://localhost/c:/temp/MyExistingLibrary.dll
· Generating the contract with selected operations from the adapter
o For generating proxy file: svcutil reflect://localhost/c:/temp/MyExistingLibrary.dll?op=MyExistingLibrary.CalculatorService/Subtract
o For generating WSDL file: svcutil /t:metadata reflect://localhost/c:/temp/MyExistingLibrary.dll?op=MyExistingLibrary.CalculatorService/Subtract
Next Post: Message Exchange Patterns
implementing Metadata Resolver Handler.docx
Comments
Anonymous
April 08, 2007
After WCF LOB Adapter SDK is installed on the system, the Adapter Developer can use the WCF LOB AdapterAnonymous
June 19, 2007
WCF LOB Adapter SDK extends the WCF channel architecture with Metadata Object Model and provides an infrastructureAnonymous
October 07, 2007
Background: After we downloaded WCF LOB Adapter SDK and read my previous post. You will find all the...