Check out this code:
string newParms = "outdata=WORK.TEST";
Common.SasLanguageService.Async = true;
StoredProcessService sp = Common.SasLanguageService.StoredProcessService;
sp.Repository = storedProcLibrary;
sp.Execute(storedProcedureName, newParms);
Standard stuff when working with the stored process server through VB or C# (or any other means of hitting these dlls).
Funny thing is the SAS log shows that the macro assignment of newParms never takes place. Hence, &outdata is undefined:
SYMBOLGEN: Macro variable OUTDATA resolves to
Commenting out the Async makes this all work:
SYMBOLGEN: Macro variable OUTDATA resolves to WORK.ALAN_20110418_070053
Now, even wiring up the event handlers for SubmitComplete do not fix the issue. Seems like a bug but I'll let the guys in R&D figure it out. If you have to waste a lot of time on it, however, keep in mind the nuances here until SAS R&D dives in.
Well, back out to the far left field where I hang out. Time to work on the business problem.
This blog is designed to show various ways to use Data Virtualization, technologies, and SAS with Microsoft technologies with an eye toward outside of the box thinking.
Monday, April 18, 2011
This one is a real Keeper
So, if you ever get this error while trying to work with OleDb and SAS IOM:
The object ... could not be found; make sure it was previously added to the object keeper
Make sure that you include the following lines (the lack of a Keeper is what causes this error):
ObjectFactory factory = new ObjectFactory();
ServerDef server = new ServerDef();
Workspace ws = (Workspace)factory.CreateObjectByServer("ws", true, server, "", "");
ObjectKeeper keeper = new ObjectKeeper();
keeper.AddObject(1, "SASServer", ws);
That whole ObjectKeeper is missing from a number of examples that I have seen and it is critical for everything to function. It becomes apparent when trying to get the data from an OleDb DataAdaptor.
The object ... could not be found; make sure it was previously added to the object keeper
Make sure that you include the following lines (the lack of a Keeper is what causes this error):
ObjectFactory factory = new ObjectFactory();
ServerDef server = new ServerDef();
Workspace ws = (Workspace)factory.CreateObjectByServer("ws", true, server, "", "");
ObjectKeeper keeper = new ObjectKeeper();
keeper.AddObject(1, "SASServer", ws);
That whole ObjectKeeper is missing from a number of examples that I have seen and it is critical for everything to function. It becomes apparent when trying to get the data from an OleDb DataAdaptor.
Sunday, February 20, 2011
Wufoo and REST API
Wufoo (http://www.wufoo.com/) is a great service for creating user forms and getting input. Build a form interactively, let people fill it out, and Wufoo collects the results. If you haven't checked it out before, I highly recommend this great service.
I was simply parsing the emails when they were sent upon form completion but that is a real hassle due to HTML. However, Wufoo has a really good REST API so I started playing around with it. Here, in C#, is how I used their API to get my data. This can easily be converted into SAS as well:
The HttpGet:
XDocument xd = XDocument.Parse(HttpGet(@"https://xxxxxxx.wufoo.com/api/v3/forms/xxxxx3/entries.xml", "XXXX-XXXX-XXXX-XXXX"));
The https://xxxxx would correspond to your domain on wufoo.
The xxxxx after forms in the uri would be the form id assigned by Wufoo.
The XXX-XXXX-etc. is the API Key assigned by Wufoo.
The above can be found on the Wufoo site. Just look at the Wufoo API information to find out how to obtain it.
I was simply parsing the emails when they were sent upon form completion but that is a real hassle due to HTML. However, Wufoo has a really good REST API so I started playing around with it. Here, in C#, is how I used their API to get my data. This can easily be converted into SAS as well:
The HttpGet:
internal static string HttpGet(string uri, string apiKey)
{
var pairs = new StringBuilder();
var req = WebRequest.Create(uri) as HttpWebRequest;
req.Timeout = 300000;
req.Credentials = new NetworkCredential(apiKey, string.Empty);
req.UserAgent = "AlanC";
req.ContentType = "text/html";
req.Method = "GET";
// Get response
using (var response = req.GetResponse() as HttpWebResponse)
{
if (response != null)
{
WebResponse resp = req.GetResponse();
if (resp != null)
{
var sr = new StreamReader(resp.GetResponseStream());
return sr.ReadToEnd().Trim();
}
return null;
}
}
return null;
}
The call to the method:
XDocument xd = XDocument.Parse(HttpGet(@"https://xxxxxxx.wufoo.com/api/v3/forms/xxxxx3/entries.xml", "XXXX-XXXX-XXXX-XXXX"));
The https://xxxxx would correspond to your domain on wufoo.
The xxxxx after forms in the uri would be the form id assigned by Wufoo.
The XXX-XXXX-etc. is the API Key assigned by Wufoo.
The above can be found on the Wufoo site. Just look at the Wufoo API information to find out how to obtain it.
Thursday, February 17, 2011
SAS Transport Files and .NET
Well, someone contacted me about the Data Management Utilities. they loved them (thank you) but wanted to know about reading SAS Transport Files. Well, after fiddling with the localProvider a bit and getting nowhere, I stumbled onto something cool:
Your dataset will be in variable x
UPDATED: 11/8/2017
[NOTE: I have also created a direct reader for the XPT binary format. That took a long time (a week, maybe). Contact me if you need that]
Complete code:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SAS.UV.Transport;
namespace ReadSasXportFiles
{
class Program
{
static void Main(string[] args)
{
var tf = new TransportFile(@"x:\temp\shoes.xpt");
var x = tf.Datasets;
- Download and install the SAS Universal Viewer from the SAS support site
- Create a new project in Visual Studio
- Add a reference from the SAS Universal Viewer install files to the following 2 dlls
- SAS.UV.Transport
- SAS.UV.Utility
- Use the following C# code (adapt as needed):
TransportFile tf = new TransportFile(@"x:\temp\sample.xpt"); var x = tf.Datasets;
Your dataset will be in variable x
UPDATED: 11/8/2017
[NOTE: I have also created a direct reader for the XPT binary format. That took a long time (a week, maybe). Contact me if you need that]
Complete code:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SAS.UV.Transport;
namespace ReadSasXportFiles
{
class Program
{
static void Main(string[] args)
{
var tf = new TransportFile(@"x:\temp\shoes.xpt");
var x = tf.Datasets;
}
}
}
IMPORTANT NOTE: Make sure your build is set for x64 and not Any CPU. You will see a warning:
Warning There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "SAS.UV.Transport", "AMD64".
Thursday, February 10, 2011
RegexBuddy and Automated Emails
So, I am going to help out with a computer club at my kids middle school. Since a topic was needed to start it all off, I said 'hey! regular expressions are used everywhere, why not start there. Plus, it is very useful.'.
So, I sent JGSoft (the owner of RegexBuddy) an email and explained the situation. How they were kids, we needed a limited version or a free one for a certain time, the kids may purchase it after the class, etc.
What was the response?
"We indeed do not offer a free trial version of RegexBuddy for download on our web site. At RegexBuddy's low price point and with our solid 3-month money-back guarantee, you can buy the full version of RegexBuddy entirely risk-free."
All of the supportive messages for RegexBuddy on SAS-L and other places and the best they can do is some automated response saying all of the kids need to cough up the 40 dollars to use their product. This is a fine way to get a bad reputation IMO.
Now I need to go get a free regex editor to show the kids despite RegexBuddy being the premiere product on the market. I am trying to turn them into kids interested in the product so they can go home and dazzle mom and dad who will then pay the fee.
Ok, off of my soapbox.
So, I sent JGSoft (the owner of RegexBuddy) an email and explained the situation. How they were kids, we needed a limited version or a free one for a certain time, the kids may purchase it after the class, etc.
What was the response?
"We indeed do not offer a free trial version of RegexBuddy for download on our web site. At RegexBuddy's low price point and with our solid 3-month money-back guarantee, you can buy the full version of RegexBuddy entirely risk-free."
All of the supportive messages for RegexBuddy on SAS-L and other places and the best they can do is some automated response saying all of the kids need to cough up the 40 dollars to use their product. This is a fine way to get a bad reputation IMO.
Now I need to go get a free regex editor to show the kids despite RegexBuddy being the premiere product on the market. I am trying to turn them into kids interested in the product so they can go home and dazzle mom and dad who will then pay the fee.
Ok, off of my soapbox.
Sunday, November 28, 2010
SAS-X Blog Aggregator
Tal Galili has started up a SAS blog aggregator. The more folks involved in SAS, the better, as far as I am concerned.
You can find it at:
SAS-X
You can find it at:
SAS-X
Sunday, November 07, 2010
Getting SAS/IntrNet Operational on IIS7
IIS7 is a major change in IIS. Don Henderson contacted me and asked if I could help get it working. It really isn't hard but involves a few steps.
How do you get SAS/IntrNet operational.
1. Enable CGI Role on Server through the Server Manager.
2. Add in your website in IIS. Right-click the scripts or cgi-bin directory where
the broker.exe is located and select Convert to Application.
3. While still having the scripts/cgi-bin folder selected, double-click on the handler mappings icon on the right-hand side. There should already be a listing for *.cgi at the top. Double-click on it --> Request restrictions --> Mapping --> Invoke --> File or Folder, Access --> Execute.
4. Click on the machine name in IIS. Click on ISAPI and CGI restrictions. Click on Add..., specify the full path to the broker.exe.
5. Optional: set up a host header.
Click on the Default website or on the website name. On the far right-hand side of the screen, click on bndings. Specify a host header (demos.savian.net, for example).
See here for more details:
http://www.wrensoft.com/zoom/support/faq_cgi_iis.html
Good luck and contact me if you have issues.
Alan
How do you get SAS/IntrNet operational.
1. Enable CGI Role on Server through the Server Manager.
2. Add in your website in IIS. Right-click the scripts or cgi-bin directory where
the broker.exe is located and select Convert to Application.
3. While still having the scripts/cgi-bin folder selected, double-click on the handler mappings icon on the right-hand side. There should already be a listing for *.cgi at the top. Double-click on it --> Request restrictions --> Mapping --> Invoke --> File or Folder, Access --> Execute.
4. Click on the machine name in IIS. Click on ISAPI and CGI restrictions. Click on Add..., specify the full path to the broker.exe.
5. Optional: set up a host header.
Click on the Default website or on the website name. On the far right-hand side of the screen, click on bndings. Specify a host header (demos.savian.net, for example).
See here for more details:
http://www.wrensoft.com/zoom/support/faq_cgi_iis.html
Good luck and contact me if you have issues.
Alan
Subscribe to:
Posts (Atom)
SAS throwing RPC error
If you are doing code in C# and get this error when creating a LanguageService: The RPC server is unavailable. (Exception from HRESULT:...
-
I am finally ready with my SAS dataset reader/writer for .NET. It is written in 100% managed code using .NET 3.5. The dlls can be found here...
-
Well, around 14 months ago, I started on a journey to understand the SAS dataset so I could read and write one independently. Originally, I ...
-
I was just tasked to read in LDAP records so we could cross-reference userids with login identifiers and general ledger information. Using...