I finally got SAS BI Web Services for .Net installed after I received my 6th installation plan file from SAS and that odyssey is blogged here:
Creating The SAS Web Service
I am now ready to create a simple web service on SAS and to call that web service from a .Net application. SAS web services are wrappers which are created around a SAS stored process (SP). I found some basic SAS code on the Internet and created a simple SP which took in zero parameters, did some calculations, and returned 2 strings. I then used the SAS Management console to deploy that SP as a web service named CPI1.asmx.
SAS web services are located in an IIS virtual directory named SASBIWS. This directory contains the WebServiceMaker.asmx web service which SAS used to create my CPI1 web service and the directory contained my CPI1.asmx file. On my SAS server, this filesystem directory is located here:
Setting Up SAS Web Service Logging
I was now ready to create the .Net app to call the web service, but before I did I wanted to ensure I had as much logging turned on at the SAS server as I could get. This desire for massive quantities of log information was a direct result of the injuries I had experienced while trying to get SAS installed in the first place. Nothing in SAS is simple so I wanted to turn on logging. Thankfully I had figured out that SAS uses log4net as their logging module during my SAS installation odyssey by sifting through their .Net assemblies with reflector. If you ever need to know where this log4net config file is located, it is located here on my SAS server:
c:\Documents and Settings\All Users\Application Data\SAS\WindowsClientLogging\log4netConfig.xml
Creating A .Net App To Call The WebService
I created a console app compliled as .Net 2.0 because I have to use WSE. I don’t know if I could have used .Net 3.5 and WCF to call it but why make this more complex right now? I simply want to call the WS and get my results back.
I called the web service and immediately got back this exception:
System.Web.Services.Protocols.SoapHeaderException: Microsoft.Web.Services3.Secuity.SecurityFault: Security requirements are not satisfied because the security header is not present in the incoming message.
That made sense because I wasn’t passing any credentials and surely SAS would expect them. I looked at the wse3policyCache.config located in the SASBIWS directory and found that it is expecting the security header in the SOAP package and by poking around on the web, I found I could pass that header with this code (my generated web service client proxy is named CPI1WS.CPI1):
CPI1WS.CPI1 ws = new CPI1WS.CPI1();
UsernameToken token = new UsernameToken(“sasadm@saspw“, “Password123”, PasswordOption.SendPlainText);
But there was a problem because the CPI1 class derived from SoapHttpClientProtocol which did not contain a SetClientCredential() or a SetPolicy() method. I fixed this by ignoring line 6 of the auto-generated CPI1 file which states Changes to this file may cause incorrect behavior… and modifying it to derive the CPI1 class from WebServicesClientProcotol.
I executed again and this time, the call was successful and I got my results back.
WAHOO!!!! I did it!!!! I called a SAS web service from a .Net application!!!! WAHOO!!!
I’m so happy. It took me forever to get to this point. There are many more details to fill in such as using Windows integrated security to make the call rather than passing plain text credentials, but this is a major milestone and I am happy.