Maxime Labelle
Maxime Labelle

Reputation: 3639

How to consume a LOB Adapter SDK-based design-time interfaces

I'm trying to build a web-based GUI to consume custom LOB Adapter SDK-based connectors. In particular, I would like to browse the metadata using the IMetadataResolverHandler interface.

I'm having two problems:

The first problem happens when trying to instantiate the custom adapter. My plan is to obtain an instance of the IConnectionFactory interface, through which I could get a new IConnection and connect to the target LOB system.

Since the most interesting methods in the Adapter base class are protected, I can only seem to succeed using reflection (please, see the sample code below).

The second problem happens when trying to browse the metadata from the target system. The method Browse on the IMetadataResolverHandler interface expects an instance of a MetadataLookup object that I have no idea how to obtain.

Please, see the sample code below:

    static void Main(string[] args)
    {
        var extension = new SqlAdapterBindingElementExtensionElement();
        var adapter = (Adapter) Activator.CreateInstance(extension.BindingElementType);

        var isHandlerSupportedMethodInfo = adapter.GetType().GetMethod("IsHandlerSupported", BindingFlags.NonPublic | BindingFlags.Instance);
        var buildConnectionUri = adapter.GetType().GetMethod("BuildConnectionUri", BindingFlags.NonPublic | BindingFlags.Instance);
        var buildConnectionFactory = adapter.GetType().GetMethod("BuildConnectionFactory", BindingFlags.NonPublic | BindingFlags.Instance);

        if (isHandlerSupportedMethodInfo == null || buildConnectionUri == null || buildConnectionFactory == null)
        {
            Console.WriteLine("Not a LOB adapter.");
            Environment.Exit(1);
        }

        var isHandlerSupportedTHandler = isHandlerSupportedMethodInfo.MakeGenericMethod(typeof(IMetadataResolverHandler));
        var isMetadataBrowseSupported = (bool)isHandlerSupportedTHandler.Invoke(adapter, new object[] { });

        if (!isMetadataBrowseSupported)
        {
            Console.WriteLine("Metadata retrieval not supported.");
            Environment.Exit(1);
        }

        var bindingElement = (SqlAdapterBindingElement)adapter;
        bindingElement.AcceptCredentialsInUri = false;
        bindingElement.InboundOperationType = InboundOperation.TypedPolling;
        bindingElement.PolledDataAvailableStatement = "EXEC [dbo].[usp_IsDataAvailable]";
        bindingElement.PollingStatement = "EXEC [dbo].[usp_SelectAvailableData]";
        bindingElement.PollingIntervalInSeconds = 10;

        var binding = new CustomBinding();
        binding.Elements.Add(adapter);

        var parameters = new BindingParameterCollection();

        var context = new BindingContext(binding, parameters);

        var credentials = new ClientCredentials();
        credentials.UserName.UserName = "username";
        credentials.UserName.Password = "password";

        var address = (ConnectionUri) buildConnectionUri.Invoke(adapter, new []{ new Uri("mssql://azure.database.windows.net//SampleDb?InboundId=uniqueId")});

        var connectionFactory = (IConnectionFactory)buildConnectionFactory.Invoke(adapter, new object[] { address, credentials, context });
        var connection = connectionFactory.CreateConnection();

        connection.Open(TimeSpan.MaxValue);

        MetadataLookup lookup = null; // ??
        var browser = connection.BuildHandler<IMetadataBrowseHandler>(lookup);

        connection.Close(TimeSpan.MaxValue);
    }

Upvotes: 0

Views: 47

Answers (1)

Maxime Labelle
Maxime Labelle

Reputation: 3639

Answering my own question, I figured it out by inspecting the code of the "Consume Adapter Service" wizard. The key is to use the IMetadataRetrievalContract interface which, internally, is implemented using up to three LOB-SDK interfaces, and in particular IMetadataResolverHandler.

Here is code that works without reflection:

var extension = new SqlAdapterBindingElementExtensionElement();
var adapter = (Adapter) Activator.CreateInstance(extension.BindingElementType);

var bindingElement = (SqlAdapterBindingElement)adapter;
bindingElement.AcceptCredentialsInUri = false;
bindingElement.InboundOperationType = InboundOperation.TypedPolling;
bindingElement.PolledDataAvailableStatement = "EXEC [dbo].[usp_IsDataAvailable]";
bindingElement.PollingStatement = "EXEC [dbo].[usp_SelectAvailableData]";
bindingElement.PollingIntervalInSeconds = 10;

var binding = new CustomBinding();
binding.Elements.Add(adapter);

const string endpoint = "mssql://azure.database.windows.net//SampleDb?InboundId=unique";
var factory = new ChannelFactory<IMetadataRetrievalContract>(binding, new EndpointAddress(new Uri(endpoint)));
factory.Credentials.UserName.UserName = "username";
factory.Credentials.UserName.Password = "password";

factory.Open();
var channel = factory.CreateChannel();
((IChannel)channel).Open();

var metadata = channel.Browse(MetadataRetrievalNode.Root.DisplayName, 0, Int32.MaxValue);

((IChannel) channel).Close();
factory.Close();

Upvotes: 1

Related Questions