BookmarkSubscribeRSS Feed
Jase
Fluorite | Level 6

 

I have a vb.net program using the SAS.Eg.Scripting library.  When I attempt to multi-thread 2 instances of the Application object, the sub with the first instance runs fine however on the second instance, I get the following error:

SAS.Eg.Scripting.ScriptingException:
Unable to connect to server: server:port
  at SAS.Eg.Scripting.Application.InitializeEngine()
  at SAS.Eg.Scripting.Application.InitializeBroker()
  at SAS.Eg.Scripting.Application..ctor(String_cmdLineProvider)

I'm running SAS EG 5.1 and the code I'm using is along the lines of:

Imports SAS.EG.Scripting
Class Example
  Sub GetData
    Dim taskList = New List(Of Task)
        taskList.Add(Sub() RunCode("C:\filename1.egp"))
        taskList.Add(Sub() RunCode("C:\filename2.egp"))
        Task.WaitAll(taskList.ToArray)
  End Sub
  Sub RunCode(fileName as String)
     Dim egApp = New Application()
     Dim egProj As ISASEGProject
         egApp.RunAutoexecFlow = True
         egProj = egApp.Open(fileName as String, "") 'opens an .egp file that uses AUTOEXEC to run and export code
         egProj.Close
         egApp.Quit()
  End Sub
End Class

 

Can anyone offer any suggestions as to why I'm getting the error on the second object?

 

Thanks,

 

Jason

11 REPLIES 11
ChrisHemedinger
Community Manager

By design, the EG application objects are meant to be just one-per-process.  I can't say exactly what's getting in the way here, except that there are some singleton objects that exist within the process and creating a second instance might interfere with that.  It's not something that the model was designed for.

 

You can use a single Application object with multiple projects...in serial (not in parallel).  You would open a project file, do your work, close the project file...before opening the next project.  Or you can call Application.Quit and null out the Application object before creating a new instance.

 

If you want to get really fancy in a .NET project, you might be able to create different AppDomains (a .NET thing) and have multiple instances.  But that's also not something we've tested...

 

Chris

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
Jase
Fluorite | Level 6

While trying a number of ways to get it working, I ran it with a single threaded task scheduler.  It threw that error but when I clicked ok and let it run, it actually worked.  ie ran two instances in parrell and generated an output from both sessions.  Unfortunately because of the msgbox notifying the error, the project won't work without a user to click the box (which defeats the point of automation).  I think what might have happened is that it could not connect when I instantiated the new object however, it proceeded on to open the project file which was then able to connect to the server.

 

I defaulted back to using a singleton for my Application object.  Would be nice though to get mutli threading running although I'm only really going to be saving 20-30 seconds.  Although I do I have 1 app that mult-threads about 12 SAS EG sessions (via process start) that I would like to convert to to scripting but won't be able to as that will add about 5 minutes to the run-time.

 

I found a couple of examples to create different AppDomains.  I'll give it a try when I get a chance.  I'll let you know how I go.

ChrisHemedinger
Community Manager

Are you automating EG because of its access to SAS infrastructure (metadata, workspace, etc.) or do you have a lot of work in EG projects that you want to "batch up"?

 

If you're looking to simply run a bunch of SAS jobs from a Windows-based app, you might be able to skip a layer with a .NET client that runs SAS code and gets results.  I have an example in this GitHub project.  Of course, if you've got a lot going on in your EG projects, then you really do need that EG layer to line up the work and get it pushed through for you...

 

Chris

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
Jase
Fluorite | Level 6

Hi Chris,

 

I finally got around to trying your SasHarness (and had a few issues however I managed to sort them out) and wow, the SasHarness should be extremely useful for what I'm doing and will also get around the need to export data from SAS EG so as to import it into my .net app.

 

I do have one query though and I suspect the answer will be no, however I'll ask the question anyway... is it possible to use the password stored in the SASEG ConfigurationV6M1.xml file (which is obviously encrypted) or am I stuck with needing the end user to enter their password each time they login to my app?

 

At this stage, it's my preference not to encypt and store the password in my own appdata file.

 

ChrisHemedinger
Community Manager

I'm glad that the project is helpful to you! 

 

No, I can't help you to use the credentials that EG stores locally for its purposes.  But if you want to encrypt your own, you can use the built-in methods in .NET (like the RSACryptoServiceProvider) so that your credentials aren't sitting as clear text, even within your user profile area.

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
Jase
Fluorite | Level 6

Hi Chris,

 

I've been using your SAS Harness for a while now with great success however I was talking to my SAS Admin about what I was doing and was asked to connect via the metadata server rather than the workspace server.  Any chance you can point me in the right direction to do that.  Your example only connects to the workspace server and I get an unable to cast object error when I try to use the metadata server GUID and I get another error when I try to connect using the workspace GUID.

 

Unable to cast COM object of type 'System.__ComObject' to interface type 'SAS.Workspace'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{440196D0-90F0-11D0-9F41-00A024BB830C}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

 

The client has connected to a SAS Metadata Server (v1.0) when it intended to connect to a SAS Workspace Server.

 

Both errors make sense to me and I have had a look around and see that I probably need to use SASOMIInterop.dll but I can't see anything in there to get a workspace object from the metadata server or some other object that would allow me to submit SAS code and download tables like I already do via the workspace server. I suspect that it can only be done via the workspace object however when using SAS Enterprise Guide, we log in via the meatadata server so I'm not sure if EG is using the metadata server to submit code or if it's creating a workspace object and just using the metadata server to get the relevent details so as to be able to create a workspace object.  Clearly I'm a but confused and am hoping you can point me in the right direction.  (I'm also unable to use SAS custom formats via the workspace server so I'm guessing they reside on the metadata server which only adds another layer of confusion about how I should be connecting.)

 

Thanks in advance,

 

Jason

ChrisHemedinger
Community Manager

I don't have a .NET example of that, but I do have a PowerShell example that you might be able to adapt.

 

The reason for connecting to a Metadata Server might be for auditing purposes, to ensure your process is coming in through the "front door" and gaining access to a SAS Workspace in a legit way, the way that EG does it.  You would have to then query the metadata connection for a list of SAS Workspaces (or the specific workspace you want), then use those details to get your workspace.  You're making a second connection to a Workspace, not casting or requesting a connection from the metadata interface.

 

SAS custom formats -- I think you mean "user defined formats" should be available in the Workspace as long as you have an OPTIONS FMTSEARCH= set to include the library where your formats reside.  That's not related to the metadata server directly.

 

Chris

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
Jase
Fluorite | Level 6

It is for auditing purposes which is why I'm pretty keen to make it work.

I saw the powershell sample but $objFactory.CreateObjectByServer only returns an object and I'm looking to use early binding rather than late binding so I need to cast it to something.  Just not sure which interface/class I can cast the CreateObjectByServer result to when connecting to the metadata server.  Perhaps it's soemthing in SASOMIInterop rather than SASInterop? (Also that example doesn't show how to connect to a workspace via the metadata server.)

 

So I can use a method in SASOMIInterop to find the correct workspace in the metadata server connection then cast that workspace to the workspace Interface in SASInterop and then use the languageservices to submit the code as per the SASHarness?  Or is it that I'm getting workspace details from the metadata server and then using those details to create another connection? In which case, which method do I use for that?

 

 

User defined formats - thats it (they're described both ways across the net and I'm not at work to check); I'll have a try with OPTIONS FMTSEARCH= .  Any hints on how I find the library name.  EG takes appears to take care of it automatically so I'm not sure where to look.(I tend to use SAS code written by others so I may be wrong about that.)

ChrisHemedinger
Community Manager

@Jase - here's the sequence of steps.

 

  • Create a connection to the SAS Metadata Server (iOMI) -- using the host/port for the metadata server
  • Use the iOMI handle to submit a metadata query (XML-based query and response) to get a list of SAS Workspace servers (or the specific server you want)
  • Use the details from that result to create another connection to a SAS Workspace Server -- basically you're learning the host/port info for the Workspace from this iOMI call, and then picking it up the rest with your existing SASHarness code.

One tricky part is credentials -- if your metadata identity and workspace identity are the same, you can just reuse your user/pw and not reprompt.

 

Another source of .NET code you can look at for some hints: Cmdlets4Sas.  These were built by outside contributors (including @AndreasMenrath) who obviously know something about how to negotiate metadata and workspace sessions.

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
AndreasMenrath
Pyrite | Level 9

Well, here are some more insights from me:

I hope this helps you. Good luck!

 

Jase
Fluorite | Level 6

Thanks @ChrisHemedingerand @AndreasMenrath.

I ended up getting it working a few days ago after I had a look at what was going on in the Cmdlerts4Sas and combined that with the process as explained by Chris.  That helped me understand where to get the server defs from (didn't realise they came from the objectFactory as well) and to use the server defs rather than the xml.

The code I went with essentially looks like this:

C#

dynamic omi = objectFactory.CreateObjectByServer(serverName, true, metaDataServerDef, loginName, password);
objectFactory.SetRepository(omi);
IEnumerable<SASObjectManager.ServerDef> serverDefs = objectFactory.ServerDefs.Cast<SASObjectManager.ServerDef>();

IServerDef workSpaceServerDef = default(IServerDef);
foreach (SASObjectManager.ServerDef serverDef in serverDefs) 
{ if (serverDef.Name == "SASApp - Workspace Server")
{ workSpaceServerDef = serverDef; break; } } _workspace = (SAS.Workspace)objectFactory.CreateObjectByServer(serverName, true, workSpaceServerDef, loginName, password); ObjectKeeper.AddObject(1, Name, _workspace);


VB.NET

Dim omi = objectFactory.CreateObjectByServer(serverName, True, metaDataServerDef, loginName, password)
          objectFactory.SetRepository(omi)
Dim serverDefs As IEnumerable(Of SASObjectManager.ServerDef) = objectFactory.ServerDefs.Cast(Of SASObjectManager.ServerDef)()

Dim workSpaceServerDef as IServerDef
For Each serverDef As SASObjectManager.ServerDef In serverDefs
    If serverDef.Name = "SASApp - Workspace Server" Then
        workSpaceServerDef = serverDef
        Exit For
    End If
Next

_workspace = DirectCast(objectFactory.CreateObjectByServer(serverName, True, workSpaceServerDef, loginName, password), SAS.Workspace)
ObjectKeeper.AddObject(1, Name, _workspace)

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

SAS Enterprise Guide vs. SAS Studio

What’s the difference between SAS Enterprise Guide and SAS Studio? How are they similar? Just ask SAS’ Danny Modlin.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 11 replies
  • 3110 views
  • 6 likes
  • 3 in conversation