Qxtend Query Service, .NET, and Dexter

Work, a new house, young daughter, and watching Dexter from the beginning doesn’t leave a lot of time for writing a software blog. Fortunately, tonight I finished the last episode (terrible ending) and it’s time to get back to writing!

To catch you up to the current season in my storyline; I’ve been working in the enterprise world, the land of three letter acronyms (TLA). I recently asked a few of my co-workers to help me come up with a short list to capture the type of work we’ve been doing, here’s what we came up with:

  • ERP – Enterprise Resource Planning
  • MES – Manufacturing Execution System
  • MRP – Material Requirements Planning
  • CRM – Customer Relationship Management
  • EAM – Enterprise Asset Management
  • PLM – Product Lifecycle Management
  • DHR – Device History Record
  • DHF – Device History File
  • MDR – Master Device Record
  • NCR – Non-Conformance Record
  • ECO – Electronic Change Order
  • BOM – Bill of Materials
  • BPR – Business Process Reengineering
  • ATP – Available To Promise
  • ISO – International Standardization Organization
  • CNC – Computer Numerical Control
  • RMA – Return Merchandise Authorization
  • ROI – Return On Investment
  • CSR – Customer Service Representative
  • DNS – Domain Name Service
  • EFT – Electronic Funds Transfer
  • FTP – File Transfer Protocol
  • JIT – Just In Time
  • POS – Point of Sale
  • CAD – Computer Aided Design
  • CAE – Computer Aided Engineering
  • RFP – Request For Proposal
  • WIP – Work In Process

In addition to all of the TLA’s, we’ve been working with a ton of new (and old) technology which is something that I thought I would post about. What’s interesting about working with many of these ERP-related systems is that if they are not SAP or Oracle, they don’t seem to get a lot of exposure. This makes working on these systems so much harder because information is no longer a Google (or Bing) search away. Not only is the technology older, but the way to access information about the technology is a throw-back to the days of (gasp) reading manuals and asking real people.

The particular ERP system we use is called QAD, which uses a web service based interface called Qxtend to communicate to other systems. Trust me, more than once I tried searching for interfacing with QAD via Qxtend and .NET, but to no avail. Working with Qxtend as a .NET developer is extremely different than consuming typical web services, at least for us at this stage in our understanding. Instead of adding a service reference or using WCF or similar framework, we had to do this an older more manual way which I will outline below. It does seem to work quite reliably, but there were several gotcha’s both in setting up the Query Service on the part of Qxtend and consuming it from .NET. All code on the .NET side can be used to connect to other SOAP based web services, so if you aren’t using QAD, don’t worry – you can still get a bit out of this code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Xml;

namespace QxtendSoapCall
{
    class Program
    {
        static void Main(string[] args)
        {
            //Prep information related to Qxtend 
            //(these values are made up for demo purposes)
            string url = "http://qad-qxtend/services/QDocWebService";
            string receiver = "qad_rcv";
            string domain = "abc";
            string version = "v1_1";
            string sourceApp = "abc";
            string profile = "GetCustomerReps";
            int maxRows = 0;  //unlimited

            //Set filter for query service (optional)
            //(these values are made up for demo purposes)
            string part = "ABC-123";
            string filter = string.Format("pt_part = {0}", part);

            //Load generic xml request template from external file
            //(create an empty QueryService QDOC request to begin and add placeholders)
            string templatePath = @"C:\XmlData\QueryService.xml";
            string requestXML = string.Empty;
            using (StreamReader streamReader = new StreamReader(templatePath))
            {
                requestXML = streamReader.ReadToEnd();
            }

            //Replace template values with values for this query service
            requestXML = requestXML.Replace("{receiver}", receiver);
            requestXML = requestXML.Replace("{domain}", domain);
            requestXML = requestXML.Replace("{version}", version);
            requestXML = requestXML.Replace("{sourceApplication}", sourceApp);
            requestXML = requestXML.Replace("{profile}", profile);
            requestXML = requestXML.Replace("{filter}", filter);
            requestXML = requestXML.Replace("{maxRows}", maxRows.ToString());

            //Clean up template
            requestXML = requestXML.Replace("\n", "").Replace("\r", "");

            //Prep service call variables for qxtend
            WebRequest request = null;
            WebResponse response = null;
            string xmlResponse = string.Empty;

            try
            {
                //Prepare web request
                request = WebRequest.Create(url) as HttpWebRequest;
                request.Method = "POST";  //post method
                request.ContentType = "text/xml";  //xml
                request.Headers.Add("soapaction", url);  //soapaction header
                request.Headers.Add("Synchronous", "Yes");  //synchronous
                request.Timeout = 30000;  //30 seconds timeout expiry

                //Encode xml string into byte array
                byte[] byteData = Encoding.UTF8.GetBytes(requestXML);
                request.ContentLength = byteData.Length;

                //Post byte array
                using (Stream postStream = request.GetRequestStream())
                {
                    postStream.Write(byteData, 0, byteData.Length);
                    postStream.Close();
                }

                //Get web response
                response = request.GetResponse() as HttpWebResponse;

                //Pull response into stream
                Stream stream = response.GetResponseStream();

                //Read stream
                StreamReader reader = new StreamReader(stream);
                xmlResponse = reader.ReadToEnd();
            }
            catch (WebException webEx)
            {
                //TODO: Handle your web exceptions here
            }
            catch (Exception ex)
            {
                //TODO: Handle your general exceptions here
            }

            //Convert string to XmlDocument (or XDocument)
            XmlDocument xdoc = new XmlDocument();
            if (!string.IsNullOrEmpty(xmlResponse))
            {
                xdoc.LoadXml(xmlResponse);
            }

            //TODO: Do something with XML now that you have data from QAD
        }
    }
}

That’s it, now you’ve got a way to generically call QAD Qxtend Query Service from .NET without needing an XSD or creating service references to .NET. This is fairly new for me, so if you see any bugs or better approaches, please leave a comment!

5 thoughts on “Qxtend Query Service, .NET, and Dexter

  1. Hi,

    We are working on a Qxtend integration with the Service and Support (SSM) Module of QAD software. We have experienced some inconsistency with sending the correct transaction ID back when we generate a new transaction. Have you seen anything like this?

  2. Hi Nicholas,

    In your Java code you are using the template C:\XmlData\QueryService.xml. Can you please share that template with me.

    Regards,
    Dilip

  3. Hi Nicholas,
    We are working on a Qxtend project and find your sample is very useful.
    Can you please share the template C:\XmlData\QueryService.xml with me.
    Thanks
    Regards
    Chris

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s