Use Microsoft Scripting Control to evaluate 'If' expressions (via c#) - c#

I have some c# code that uses the Microsoft Scripting Control to evaluate some expressions:
using MSScriptControl; // references msscript.ocx
ScriptControlClass sc = new ScriptControlClass();
sc.Language = "VBScript";
sc.AllowUI = true;
try
{
Console.WriteLine(sc.Eval(txtEx.Text).ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
(txtEx is a simple text field)
Numerical expressions: "6+4", "cos(34)", "abs(-99)", "round(1.234, 2)" etc. are fine
Boolean expressions: "true or false", "1=2" are fine
But how can I evaluate a simple 'if'? I have tried "if(true, 2, 3)", "iif(true, 2, 3)", "if (true) then 2 else 3" and "if (true) then 2 else 3 endif"
Can anybody please help me to evaluate simple conditional expressions? Any help much appreciated!
RH

Try wrapping your IF-expression in a function
Function test
if (true) then
return true
else
return false
end if
End function
Add the function to the control and then use Run
Result = ScriptControl.Run("Test")
(the code above is not tested, but something along that way should work)
Check out this link for some more info
http://support.microsoft.com/kb/184740

using MSScriptControl; // references msscript.ocx
ScriptControlClass sc = new ScriptControlClass();
sc.Language = "VBScript";
sc.AllowUI = true;
// VBScript engine doesn’t have IIf function
// Adding wraper IIF function to script control.
// This IIF function will work just as VB6 IIf function.
sc.AddCode(#"Function IIF(Expression,TruePart,FalsePart)
If Expression Then
IIF=TruePart
Else
IIF=FalsePart
End IF
End Function");
try
{
//define x,y variable with value
sc.AddCode(#"x=5
y=6");
//test our IIF
Console.WriteLine(sc.Eval("IIF(x>y,x,y)").ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

You should consider using the expression evaluation engine that is part of Windows Workflow Foundation. Both the evaluator and the designer for it can be used separately from WF.

if (true) then return 2 else return 3

Thanks for the tips! After a bit more experimenting, based on Brummo's help, this seems to work:
txtEx contains this text:
function test
if (1=1) then
test = true
else
test = false
end if
end function
then
sc.AddCode(txtEx.Text);
and
object[] myParams = { };
Console.WriteLine(sc.Run("Test", ref myParams).ToString());
This isn't ideal, since I really wanted to evaluate an expression, without building, loading and evaluating a function. (I am surprised IIF doesn't work for simple one line if evaluation).

Related

Contract function with transaction

I have a question about programming VB.NET & Nethereum.
The contract address works flawlessly. For testing purposes I have built in a maintrace - pause function that can be set via function.
In the Remix tool + Metamask, the pause and resume function works perfectly.
I've been desperately looking for a solution for VB.NET (or else C #) for days:
The contract function (i have for test remove OnlyOwner variable in this Contract):
function SetPause() external returns (string memory) {
if (paused) {
paused = false;
emit Unpause();
Unpause;
return "Pause Set inactive";
} else {
paused = true;
Pause;
emit Pause();
return "Pause Set active";
}
}
When I address the function via VB.NET I get the return messages as normal, but my wallet does not carry out a transaction. Thus the status does not change. Other functions like transfer. Query of token names and balance work fine.
The VB.NET code:
Dim changeFunction As Task(Of String) = Contract.GetFunction("SetPause").SendTransactionAsync(senderAddress, gas)
changeFunction.Wait()
Textbox1.Text = changeFunction.Result
As I said, I get all the correct feedback, but no transactions are carried out (changes), only read queries. I also tried other VB.NET codes. Unsuccessful ...

Why does CodeRush warn me of an Unused Declaration in code?

I have this code, which I use all over my applications to save data back to the database.
public bool SaveDemo()
{
bool success = false;
try
{
using (DataTable dt = DataAccess.ExecuteDataTable("[dbo].[udp_Customers_ups]",
DataAccess.Parameter(CustomerIdColumn, CustomerId),
DataAccess.Parameter(CodeColumn, Code),
DataAccess.Parameter(CompanyColumn, Company),
DataAccess.Parameter(IsDeletedColumn, IsDeleted),
DataAccess.Parameter(LastUpdatedColumn, LastUpdated),
DataAccess.Parameter(UpdatedByColumn, UpdatedBy)))
success = true;
}
catch
{
success = false;
}
return success;
}
The code works as is, which by that I mean it saves the data back to the database. However CodeRush complains about the dt being an Unused Declaration. And since the Using is (I think) using the dt I would think that the warning is a false positive. So I am left wondering if CodeRush is wrong or if I am missing something?
What CR is trying to say is that in:
using (DataTable dt = DataAccess.ExecuteDataTable ...
you are not using the declaration of dt; the variable remains untouched after.
The refactor button will transform this to
using ( DataAccess.ExecuteDataTable ...
i.e. it will still be a using statement but you won't have a variable to refer to it.
While you're doing that, you can do some Inline Result transformations, yielding:
try
{
using (DataAccess.ExecuteDataTable("[dbo].[udp_Customers_ups]",
DataAccess.Parameter(CustomerIdColumn, CustomerId),
DataAccess.Parameter(CodeColumn, Code),
DataAccess.Parameter(CompanyColumn, Company),
DataAccess.Parameter(IsDeletedColumn, IsDeleted),
DataAccess.Parameter(LastUpdatedColumn, LastUpdated),
DataAccess.Parameter(UpdatedByColumn, UpdatedBy)))
return true;
}
catch
{
return false;
}
I'll let others question whether wrapping calls like this in a catch block is a good idea...

Waiting for a frame to load using Selenium

I have seen many posts on handling switching between frames in Selenium but they all seem to reference the Java 'ExpectedConditions' library for the below method.
ExpectedConditions.frameToBeAvailableAndSwitchToIt
I was wondering if there is any C# implementation anywhere or if anyone has any such work around?
Cheers
There isn't a direct equivalent in the C# bindings but it's very easy to do this yourself.
Remember that Selenium is open source so let's dig out the source code. Here is the Java ExpectedConditions and here is the C# set.
So what's the Java version doing? Well, not a lot I tell you.
try {
return driver.switchTo().frame(frameLocator);
} catch (NoSuchFrameException e) {
return null;
}
All it's doing is attempting to switch to the frame you tell it to, and providing it was successful (as in, there was no exception in attempting to do that), then it's assumed it can carry on.
So, all you'll need to do is do the same thing in C#, so something like (not compiled):
public static Func<IWebDriver, bool> WaitUntilFrameLoadedAndSwitchToIt(By byToFindFrame)
{
return (driver) =>
{
try
{
return driver.SwitchTo().Frame(driver.FindElement(byToFindFrame));
}
catch (Exception)
{
return null;
}
return true;
};
}
As in, keep the same concept: try to find the frame and switch to it, any exceptions then we return null and force the caller (usually a WebDriverWait instance) to iterate through again. Returning true will tell the caller that we are happy we can move on.
All the waiting & expected conditions classes live in the OpenQA.Selenium.Support.UI namespace which lives in the WebDriver.Support.dll assembly.
These answers are old and I had the same issue. I was able to use SeleniumExtras.WaitHelpers.ExpectedConditions from nuget to achieve this easily.
//wait for 10 seconds max for the frame
WebDriverWaitwait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.FrameToBeAvailableAndSwitchToIt(By.Id("FRAMEID")));
I have just committed such a ugly code. Dropping here for the future!
protected void SwitchToFrame(int iframe = 1)
{
var driver = GetWebDriver();
driver.SwitchTo().DefaultContent();
bool done = false, timeout = false;
int counter = 0;
do
{
counter++;
try
{
driver.SwitchTo().Frame(iframe);
done = true;
}
catch (OpenQA.Selenium.NoSuchFrameException)
{
if (counter <= Constants.GLOBAL_MAX_WAIT_SEC)
{
Wait(1);
continue;
}
else timeout = true;
}
} while (!done && !timeout);
if (timeout) throw new OpenQA.Selenium.NoSuchFrameException(iframe.ToString());
}

Calling Javascript (Raphael.js library) from C# codebehind in ASP.NET

I'm trying to call some function from my code behind in C#. I was searching how to do this and was able to call an alert to display when I wanted it to. However, I don't know how to call other things!
This is what I need to call from the code behind:
var paper = Raphael("paper1", 800, 800);
var Plan = paper.path("M100, 100 a 50, 50 0 0,1 50, 50 l -50 0 l 0, -50");
Plan.attr({ fill: "#FF6600" });
I've tried these on a plain HTML file but I'm not able to use it. I'm also using a master page and most of the examples I've found have been without master pages so I'm pretty lost on this.
Anyone can help?
Create a Javascript function in the .aspx page and then call the function from code behind like so:
Function in html Code
function dostuff()
{
// code here
}
C# code in code behind
protected void callmethod()
{
StringBuilder oSB = new StringBuilder();
Type cstype = this.GetType();
try
{
oSB.Append("<script language=javaScript>");
oSB.Append("dostuff();");
oSB.Append("</script>");
Page.ClientScript.RegisterClientScriptBlock(cstype, Guid.NewGuid().ToString(), oSB.ToString(), false);
}
catch (Exception ex)
{
throw ex;
}
finally
{
oSB = null;
}
}
Javascript can only be called on the client side. If you absolutely need to call it from your serverside, you can use a asp:HiddenField's value as a flag for when you need the javascript code executed upon returning, and then run the needed javascript if the requirements are met.
But its not a nice solution, you should probably try to separate the server and the client.
Hope this helps, in any case!

is there a better way to handle RPC_E_CALL_REJECTED exceptions when doing visual studio automation?

this is what I'm currently doing:
protected void setupProject()
{
bool lbDone = false;
int liCount = 0;
while (!lbDone && liCount < pMaxRetries)
{
try
{
pProject.ProjectItems.Item("Class1.cs").Delete();
lbDone = true;
}
catch (System.Runtime.InteropServices.COMException loE)
{
liCount++;
if ((uint)loE.ErrorCode == 0x80010001)
{
// RPC_E_CALL_REJECTED - sleep half sec then try again
System.Threading.Thread.Sleep(pDelayBetweenRetry);
}
}
}
}
now I have that try catch block around most calls to the EnvDTE stuff, and it works well enough. The problem I have is when I to loop through a collection and do something to each item once.
foreach(ProjectItem pi in pProject.ProjectItems)
{
// do something to pi
}
Sometimes I get the exception in the foreach(ProjectItem pi in pProject.ProjectItems) line.
Since I don't want to start the foreach loop over if I get the RPC_E_CALL_REJECTED exception I'm not sure what I can do.
Edit to answer comment:
Yes I'm automating VS from another program and yes I usually am using VS for something else at the same time. We have an application that reads an xml file then generates around 50 VS solutions based on the xml file. This usually takes a couple of hours so I try to do other work while this is happening.
There is a solution on this MSDN page: How to: Fix 'Application is Busy' and 'Call was Rejected By Callee' Errors. It shows how to implement a COM IOleMessageFilter interface so that it will automatically retry the call.
First, Hans doesn't want to say so but the best answer to "how to do this" is "don't do this". Just use separate instances of visual studio for your automation and your other work, if at all possible.
You need to take your problem statement out somewhere you can handle the error. You can do this by using in integer index instead of foreach.
// You might also need try/catch for this!
int cProjectItems = pProject.ProjectItems.Length;
for(iProjectItem = 0; iProjectItem < cProjectItems; iProjectItem++)
{
bool bSucceeded = false;
while(!bSucceeded)
{
try{
ProjectItem pi = pProject.ProjectItems[iProjectItem];
// do something with pi
bSucceeded = true;
}catch (System.Runtime.InteropServices.COMException loE)
{
liCount++;
if ((uint)loE.ErrorCode == 0x80010001) {
// RPC_E_CALL_REJECTED - sleep half sec then try again
System.Threading.Thread.Sleep(pDelayBetweenRetry);
}
}
}
}
I didn't have much luck with the recommended way from MSDN, and it seemed rather complicated. What I have done is to wrap up the re-try logic, rather like in the original post, into a generic utility function. You call it like this:
Projects projects = Utils.call( () => (m_dteSolution.Projects) );
The 'call' function calls the function (passed in as a lambda expression) and will retry if necessary. Because it is a generic function, you can use it to call any EnvDTE properties or methods, and it will return the correct type.
Here's the code for the function:
public static T call<T>(Func<T> fn)
{
// We will try to call the function up to 100 times...
for (int i=0; i<100; ++i)
{
try
{
// We call the function passed in and return the result...
return fn();
}
catch (COMException)
{
// We've caught a COM exception, which is most likely
// a Server is Busy exception. So we sleep for a short
// while, and then try again...
Thread.Sleep(1);
}
}
throw new Exception("'call' failed to call function after 100 tries.");
}
As the original post says, foreach over EnvDTE collections can be a problem as there are implicit calls during the looping. So I use my 'call' function to get the Count proprty and then iterate using an index. It's uglier than foreach, but the 'call' function makes it not so bad, as there aren't so many try...catches around. For example:
int numProjects = Utils.call(() => (projects.Count));
for (int i = 1; i <= numProjects; ++i)
{
Project project = Utils.call(() => (projects.Item(i)));
parseProject(project);
}
I was getting the same error using C# to read/write to Excel. Oddly, it worked in debug mode but not on a deployed machine. I simply changed the Excel app to be Visible, and it works properly, albeit about twice as slow. It is annoying to have an Excel app open and close dynamically on your screen, but this seems to be the simplest work-around for Excel.
Microsoft.Office.Interop.Excel.Application oApp = new ApplicationClass();
oApp.Visible = true;
oApp.DisplayAlerts = false;

Categories