Soap Service Authentication

I am testing connecting to the SOAP Web Service via a .NET application and all attempted requests get a 405 Method Not Found response. I think this may be because i am using basic authentication which is no longer an option for the SOAP service?

The guide suggests setting up OAUTH authentication however this is not an option for me since the sage x3 instance is not public facing.

Can anyone confirm if it is the case basic authentication will not work and if there is a way to use OAUTH without making the sage instance public facing?

  • What version of X3 are you on, and what version of .net are you using?  X3 uses basic authentication for the SOAP web services since version 8.  I believe the way to call X3 web services from SOAP is difference from .net Core, but if you are using a standard Console/WinForms/Web application, it should work with basic authentication.

  • in reply to Denise Hartman

    The X3 version is 12 (IDDN.FR.001.120009.xxx.2016). It is just a demo VM rather than a production server.

    I am trying to connect from a basic .NET Framework WinForms application, is there an official example for connecting to a web service?

  • in reply to Denise Hartman

    I can successfully get a list of customer using the test tool within x3 however using the same values in an equivalent call from a .net application always returns 405.

    static string _x3WSUr1 = "https://x3erpv12sqlvm.local:8443/soap-wsdl/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC?wsdl";
    static string _publicName = "AOWSEXPORT";
    static CAdxWebServiceXmlCCService _x3WebService = new CAdxWebServiceXmlCCServiceBasicAuth();
    static CAdxCallContext _callContext = new CAdxCallContext();
    static CAdxResultXml _resultXML = new CAdxResultXml();
    
    static void Main(string[] args)
    {
    	_callContext.codeLang = "ENG";
    	_callContext.poolAlias = "ADC";
    	_callContext.requestConfig = "adxwss.trace.on=off&adxwss.trace.size=16384&adonix.trace.on=off&adonix.trace.level=3&adonix.trace.size=nadxwss.optreturn=1SON&adxwss.beautify=true";
    	_x3WebService.Url = _x3WSUr1;
    	_x3WebService.Credentials = new NetworkCredential("...", "...");
    	_x3WebService.PreAuthenticate = true;
    	_x3WebService.Timeout = 6000000;
    	
    	ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; // fix for trust relationship error
    
    	CAdxParamKeyValue[] objectKeys = new CAdxParamKeyValue[1];
    
    	_resultXML = _x3WebService.query(
    		callContext: _callContext,
    		publicName: "BPC",
    		objectKeys: objectKeys,
    		listSize: 100);
    }

  • in reply to Graeme Faulkner

    You need to add the basic authentication to the request header.  Below is a blog post with details on how to add the authentication header to the web request in .net

    www.rklesolutions.com/.../5-days-sage-x3-web-services-v12-day-4

  • in reply to Denise Hartman

    Yes I followed that guide to produce the code sample above, it looks like that will be very useful once I can successfully connect.

    The example above is using the recommended custom version of CAdxWebServiceXmlCCService ( CAdxWebServiceXmlCCServiceBasicAuth )

    static CAdxWebServiceXmlCCService _x3WebService = new CAdxWebServiceXmlCCServiceBasicAuth();

    The custom class is correct as far as i can see. 

    using ConsoleApp.X3WebService;
    using System;
    using System.Net;
    using System.Text;
    
    namespace ConsoleApp.App_Code
    {
        public class CAdxWebServiceXmlCCServiceBasicAuth : CAdxWebServiceXmlCCService
        {
            protected override WebRequest GetWebRequest(Uri uri)
            {
                HttpWebRequest webRequest = (HttpWebRequest)base.GetWebRequest(uri);
                NetworkCredential credentials = Credentials as NetworkCredential;
    
                if (credentials != null)
                {
                    string authInfo = "";
                    if (credentials.Domain != null && credentials.Domain.Length > 0)
                    {
                        authInfo = string.Format(@"{0}\{1}:{2}", credentials.Domain, credentials.UserName, credentials.Password);
                    }
                    else
                    {
                        authInfo = string.Format(@"{0}:{1}", credentials.UserName, credentials.Password);
                    }
                    authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
                    webRequest.Headers["Authorization"] = "Basic " + authInfo;
                }
    
                return webRequest;
            }
        }
    }

  • I don't know if you tried posting your issue to the developer site, maybe someone would be better equipped to help out with .net stuff there.

    https://developer-community.sage.com/

    There is also a developer site as well  https://developer.sage.com/x3/ 

  • in reply to Graeme Faulkner

    Hi ,
    405 means method not allowed. You're trying to use a query method on a web service AOWSEXPORT which doesn't support it...

    The query method is the equivalent to the X3 left list to get a list of records from X3 objects, and as such only works with an object based web service, not a subprogram one.
    AOWSEXPORT is a web service based on a X3 subprogram that will export data using an X3 export template.

    I recommend you to follow X3 Web Services training, it will save you some time and headaches.
    Generally, when you want to test your SOAP web services, you use the getDescription method (check the WSDL) as this one will work for all SOAP Services in X3 whether they are object or subprogram based.

  • in reply to Denise Hartman

    Hi Denise,

    do you know wich is the way to call X3 web service SOAP from .net core?

    Thanks for all!

  • in reply to Carles Homs Ferrer

    Hi ,

    I have an old example (10 years old) in C# based on sales order example (SOH object):

    // XML Header to be included in all xml input strings
            private static string XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
    
            // Public name of the web service
            private static string WEB_SERVICE_NAME = "SOH";
    
            public Orders()
            {
                InitializeComponent();
    
                // Initialise connection values
                callContext = new CAdxCallContext();
                webService = new CAdxWebServiceXmlCCService();
                paramKey = new CAdxParamKeyValue[1];
                resultXML = new CAdxResultXml();
    
                callContext.codeLang = "BRI";          // Connection language
                callContext.codeUser = "admin";        // X3 user
                callContext.password = "";             // X3 password
                callContext.poolAlias = "WS_DEMOBRI";  // Connection pool name
            }
    
            /// <summary>
            /// This is called when the Read button is clicked.
            /// The program uses the field values to construct input XML
            /// and calls the read() method.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void Read_Click(object sender, EventArgs e)
            {
                // Complete call context depending on flags
                if (DisplayTraceFile.Checked)
                    callContext.requestConfig = "adxwss.trace.on=on&adxwss.trace.size=16384&adonix.trace.on=on&adonix.trace.level=3&adonix.trace.size=8";
                else
                    callContext.requestConfig = "adxwss.trace.on=off&adxwss.trace.size=16384&adonix.trace.on=off&adonix.trace.level=3&adonix.trace.size=8";
    
                // Prepare paramKeyValue
                paramKey[0] = new CAdxParamKeyValue();
                paramKey[0].key = "1";  // Other method: paramKey[0].key = "SOHNUM";
                paramKey[0].value = SOHNUM.Text;
                // When more than one field in the object key, complete as follows:
                // paramKey[1] = new CAdxParamKeyValue();
                // paramKey[1].Key = "2";
                // paramKey[1].value = ...
    
                // Call web service
                resultXML = webService.read(callContext, WEB_SERVICE_NAME, paramKey);
    
                displayMessages(resultXML);
    
                if (resultXML.status == 0)
                {
                    Status.Text = "Status: NOT OK";
                }
                else
                {
                    Status.Text = "Status: OK";
                    displayData(resultXML);
                }
    
            }

  • in reply to Bruno Gonzalez

    Hello  ,

    thanks for the answer. In .Net core the class CAdxWebServiceXmlCCService are no accessible:

    The way to reference WSDL is different and I suspect this affects the way I use it.

  • in reply to Carles Homs Ferrer

    I don't know how .Net core works, but I bet it has to do with how the WSDL was declared and the code generated.
    medium.com/.../integrating-with-soap-web-services-in-net-core-adebfad173fb