Problem description:
I have a web service I've created which I'm consuming in another application. The web service has three different web methods which create a new iMacros.App interface and then run
browser.iimInit("",false,null,null,null,120);
and then play some macro.
The three methods execute different scripts: one authenticates to a website, the second is called repeatedly to perform data entry and the third logs out of the website.
So my webservice calls from the other app are something like:
AutomationService.Login();
for each row in dataset
{
AutomationService.Update(row[param1], row[param2], row[param3]);
}
AutomationService.Logout();
When the update method is executed a second time, a new iMacros browser opens, and all subsequent macros fail because they expect the browser to be in a certain state where the last macro left off.
I've tried executing init with the current user, a named user as well as using the imrunner method and all yield the same results.
Why is iimInit("",false) not finding and interfacing with the existing instance of the iMacros browser?
Code:
Code: Select all
public class AutomationService : System.Web.Services.WebService
{
private iMacros.App imBrowser;
public AutomationService()
{
if (this.imBrowser == null)
{
this.imBrowser = new iMacros.App();
}
this.imBrowser.iimInit("-runner", false, null, null, null, 300);
}
[WebMethod]
public string LogIn()
{
iMacros.Status bStatus;
string stat;
stat = (bStatus = imBrowser.iimSet("-var_UserID", System.Configuration.ConfigurationManager.AppSettings["UserID"].ToString())).ToString();
stat += (bStatus = imBrowser.iimSet("-var_Password", System.Configuration.ConfigurationManager.AppSettings["Password"].ToString())).ToString();
stat += (bStatus = imBrowser.iimPlay("C:\\Inetpub\\wwwroot\\Automation\\Login.iim", 300)).ToString();
imBrowser = null;
return stat;
}
[WebMethod]
public string Update(string orgID, string CommentText, string ContactName, int ContactRole, int ReasonCode )
{
iMacros.Status bStatus;
string stat;
stat = (bStatus = imBrowser.iimSet("-var_OrgID", orgID)).ToString();
stat += (bStatus = imBrowser.iimSet("-var_CommentText", CommentText)).ToString();
stat += (bStatus = imBrowser.iimSet("-var_ContactName", ContactName)).ToString();
stat += (bStatus = imBrowser.iimSet("-var_ContactRole", ContactRole.ToString())).ToString();
stat += (bStatus = imBrowser.iimSet("-var_ReasonCode", ReasonCode.ToString())).ToString();
stat += (bStatus = imBrowser.iimPlay("C:\\Inetpub\\wwwroot\\Automation\\AddComment.iim", 300)).ToString();
imBrowser = null;
return stat;
}
[WebMethod]
public string LogOut()
{
iMacros.Status bStatus;
string stat;
stat = (bStatus = imBrowser.iimPlay("C:\\Inetpub\\wwwroot\\Automation\\Logout.iim", 300)).ToString();
imBrowser.iimExit(60);
imBrowser = null;
return stat;
}
}
}
I was able to solve the issue by forcing the web service to start a new STA thread and call a join, blocking the MTA caller until the worker thread with the iMacros COM iMacros.App interface terminated. The COM inter-op in .NET wraps the COM object just fine as an STA thread model object, but the problem is that web services in .NET are MTA model by default.
Some times when I made a call to iimInit, the previously created STA thread was still alive, so it spawned a new thread.
I'm pretty sure this kind of problem is typically with COM interop in .NET...but it took a while to figure it out!