Calling SAS Web Services from C#

Something as trivial as setting a web service client on Visual Studio takes a new meaning when referring to SAS. Don't get me wrong, SAS is a great statistical tool but their implementation of Web Services despite being set on top of JBoss (an excellent app/web container) is disastrous. Add to that the fact that their working examples from using C# were written for Visual Studio 2005. For example this jewel: here and here.

Now having said that, it is actually possible doing a few tricks.

First, out of the box, the standard SAS BI Web Services Authentication well it leaves a lot to be desired, basically sending username and password un-encrypted through http. Which is not even trivial to do on .NET as it is not allowed in one of the standard bindings.

To be able to connect and send a request to your SAS Web service you need to do the following on your Web.config

You need to use custom bindings, usernameovertransport, allowinsecuretransport and here is an additional thing that is not mentioned anywhere, mtomMessageEncoding with messageVersion of SOAP11.

So here is how the binding looks like:

  1. < customBinding>
  2. < binding name="YourSoapBinding" >
  3. < security authenticationMode="UserNameOverTransport" securityHeaderLayout="Strict" includeTimestamp="false" allowInsecureTransport="true"/ >
  4. < mtomMessageEncoding messageVersion="Soap11" />
  5. < httpTransport transferMode="StreamedResponse"/>
  6. < /binding >
  7. < /customBinding >
  8.  
  9. < client >
  10. < endpoint address="http://yourbiservice:8080/SASBIWS/services/YOURWS" binding="customBinding" bindingConfiguration="YourSoapBinding" contract="YourWebService.PortType" name="YourPortType" >
  11. < /client >

Make sure you add credentials to your webservice request when you do it from C# code:

  1. ws.ClientCredentials.UserName.UserName = "john";
  2. ws.ClientCredentials.UserName.Password = "yournetworkpassword";

That is from the C# side.

From the SAS side, it is better if you shut the error messages if SYSCC > 4, so make sure to do that otherwise it messes up the output of the webservice.

Another caveat is that if you do a PROC PRINT to generate the output of your web service, it will actually send it through in MIME format, and in one chunk it will be sent on a HTML page with styles and everything, and hopefully, if you created an output source, on that variable as well, in XML, which brings me to the next issue.

You need to PROC PRINT with ODS DOCBOOK

For example like this:

  1. proc sort data=mydata;
  2. ods docbook body=mydata;
  3. proc print data=mydata;
  4. run;
  5. ods docbook close;

I hope this helps someone, this is mostly a quick reference for the future.