Math operators as dynamic variables - asp.net

I have no idea how I'm going to accomplish this BUT someway, somehow I have to perform calculations dynamically in ASP/VB.NET (Possibly SQL Server). Something like this:
Dim var1, var2 as Integer
Dim Optr as string
var1 = 15
var2 = 25
Optr = +
MyResult(var1, var2, Optr)
...and MyResult should equal 40. How can I do this? Anyone have any ideas? Thanks!

The only way I can think of is a switch case which deals with all possible operators.
If you want to implement something more complicated(with operator presedence) you can use the Shunting Yard Algorithm

I don't have the code specifics, but you if have your vars and operations concatenated as a single string you could parse the string and compile it, given you the proper result.
Check this SO questions and answers here, they discuss a very similar problem (if not the exact same)

I like Paul Sasik's example for a purely .net solution, but another alternative would be to make use of the VBScript engine that's part of windows.
For example (you'll need to add a reference to the COM MSScript control)
Static sc As MSScriptControl.ScriptControl
'---- init the script control once
If sc Is Nothing Then
sc = New MSScriptControl.ScriptControl
sc.Language = "VBScript"
sc.AllowUI = False
End If
Try
Return sc.Eval(Expr)
Catch ex As Exception
'Deal with any error conditions here
End Try
Where Expr is any expression you might want to evaluate.
Granted, this leverages VBScript support, which you might want to avoid, but, depending on your audience, they might be more comfortable with that than .net coding

To allow for arbitrarily complex calculations you could take advantage of .NET's on-fly-compilation features. Here's an article for starters.
For your particular implementation you would construct a calculation string from your input like this:
Dim toCalc as string = var1 & " " & Optr & " " & var2
...and use a process where the calculation would get injected into a dynamically created class that would look something like this: (working console sample based on the CP article)
Imports System.CodeDom.Compiler
Imports System.Reflection
Module Module1
Sub Main()
Dim var1 As Integer = 50
Dim var2 As Integer = 65
Dim Optr As String = "+"
Dim equation As String = var1 & " " & Optr & " " & var2
Dim nl As String = System.Environment.NewLine
Dim dynClass As String = ""
dynClass &= "public class DynamicClass" & nl
dynClass &= " public shared function Calc() as double" & nl
dynClass &= " return " & equation & nl
dynClass &= " end function" & nl
dynClass &= "end class" & nl
Try
Dim params As New CompilerParameters
params.ReferencedAssemblies.AddRange(New String() {"Microsoft.VisualBasic.dll"})
Dim mAssembly As Assembly = New VBCodeProvider().CreateCompiler. _
CompileAssemblyFromSource(params, dynClass).CompiledAssembly
Console.WriteLine("Calculating: " & equation)
Console.WriteLine("SUCCESS! Result: " & mAssembly. _
GetType("DynamicClass"). _
InvokeMember("Calc", _
BindingFlags.InvokeMethod Or _
BindingFlags.Public Or _
BindingFlags.Static, _
Nothing, Nothing, Nothing).ToString())
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Sub
End Module

Related

Dictionary(Of String, String) Cannot Evaluate Expression

When calling a Sub to populate a System.Collections.Generic.Dictionary with keys and values from a DictionaryEntry(), upon examining the Dictionary in Debug mode every property has a red circle with an X and contains the text "Unable to evaluate expression." It appears to be working, it will even complain if I try to add two entries with the same Key/Value pair. No keys or values are present either, even though my test string (valuesString) is populated.
I am calling the Sub from the ItemInserted event of a FormView (.Net Framework 4, Visual Studio 2013 Webforms Application)
Protected Sub PopulateDictionary(myValues As DictionaryEntry())
Dim de As DictionaryEntry
Dim valuesString As String = String.Empty
Dim myDictionary As New Dictionary(Of String, String)
For Each de In myValues
'This works - the string is populated with key/value pairs
valuesString &= "Key=" & de.Key.ToString() & ", " & _
"Value=" & de.Value.ToString() & "<br/>"
'This doesn't - just get the red circle with an X
myDictionary.Add(de.Key.ToString(), de.Value.ToString())
Next
End Sub
What is going on here? I have restarted Visual Studio with no luck.
odd that this works with the "<br/>". it looks like it's missing the closing quote. (and maybe ToString() is not needed?)
valuesString &= "Key=" & de.Key.ToString() & ", " & _
"Value=" & de.Value.ToString() & "<br/>"
it looks like this:
myDictionary.Add(de.Key.ToString(), de.Value.ToString())
just needs to be:
myDictionary.Add(valuesString)
or (not sure...):
myDictionary.Add(DictionaryEntry())

ASP Classic to VB.NET - Recursive Function including RecordSets

I'm hoping someone can help me think this one out because I'm stuck.
We are slowly migrating a ASP Classic web site to a .NET web application. I stumbled upon the following function. The function will return an array of strings that consists of hml a-tags.
Private Function getFullPathLinks(lNodeId, sPath, sDocTemplate)
Dim sql, recordSet, rsTmp
Dim arrPath, sResult
Dim lDocId
lDocId = getDocumentId(lNodeId)
sql = "SELECT parent_id, label FROM wt_node WHERE (node_id = " & lNodeId & ")"
Set recordSet = execSqlCache(oConn,sql,Array(),Array("wt_node"))
If Not (recordSet.Bof And recordSet.Eof) Then
If sDocTemplate <> "" Then
sPath = sPath & "|" & "<a href='" & sDocTemplate & "?nodeid=" & lNodeId & "&documentid=" & lDocId & "'>" & recordSet("label") & "</a>"
Else
sPath = sPath & "|" & recordSet("label")
End If
getFullPathLinks recordSet("parent_id"), sPath
End If
recordSet.Close
Set recordSet = Nothing
arrPath = arrReverse(Split(sPath,"|"))
sResult = Join(arrPath,sPathDelimiter)
If Right(sResult,Len(sPathDelimiter)) = sPathDelimiter Then sResult = Left(sResult,Len(sResult)-Len(sPathDelimiter))
getFullPathLinks = sResult
End Function
The function calls itself at the end and this will not work well in my .NET implementation where we are using DataReaders to talk to the SQL database.
Could I follow the same structure as above and instead use something else than a DataReader to achieve this?
I am not sure what SQL Server version you are using, but have you taken a look at recursive queries in SQL? It is designed to retrieve hierarchical data in a single db call. Take a look:
http://msdn.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

Backslashes in path in VB.Net

It seems I'm not lucky with backslashes in ASP.Net VB.Net.
I'm trying to output some infos about files with ffprobe and my paths are cut randomly at some backslash in every string containing backslash.
I debugged this function to return the path generated by fileToProcess:
Function ffprobe_show_format(ByVal arg As String) As String
Dim myProcess As New System.Diagnostics.Process()
Dim fileToProcess As String = MapPath(".") & "\temps\" & arg
myProcess.StartInfo.FileName = MapPath(".") & "\ffprobe.exe"
myProcess.StartInfo.Arguments = "-show_format " & fileToProcess & " >C:\inetpub\vhosts\mysite.com\httpdocs\absolutefs\ffmpegtemp.txt"
myProcess.StartInfo.UseShellExecute = False
myProcess.StartInfo.RedirectStandardInput = True
myProcess.StartInfo.RedirectStandardOutput = True
myProcess.Start()
Dim myStreamWriter As StreamWriter = myProcess.StandardInput
Dim mystreamreader As StreamReader = myProcess.StandardOutput
Dim str As String = mystreamreader.ReadToEnd
Return str & ";" & "FileToProcess=" & fileToProcess & "MapPath(.) AND ffprobe.exe" & MapPath(".") & "\\ffprobe.exe"
End Function
And it returns ;FileToProcess=C:
It means that
My file is not processed because of some errors
My Path is cut at backslashes
The rest of the string is then broken
Does I need to tell asp.net to represent backslashes in another way?
[EDIT]
I can't choose an answer but will upvote since I made two mistakes:
- To debug, I was reading my value once it was put in SQL variables with limites size then
- ... fetched with Newtonsoft.Json parser that probably was refusing some chars.
I'm new on ASP.Net so I have difficulties finding a good way to debug. So I finally made as usual when I'm not able to debug on a platform: I've written my debug vars in a text file, and everything was there using this way:
Function ffprobe_show_format(ByVal file As String, ByVal app As String) As String
Dim myProcess As New System.Diagnostics.Process()
myProcess.StartInfo.FileName = app
Dim argz As String = FormatCommandLine("-show_format", file)
myProcess.StartInfo.Arguments = argz
myProcess.StartInfo.UseShellExecute = False
myProcess.StartInfo.RedirectStandardOutput = True
myProcess.Start()
Dim mystreamreader As StreamReader = myProcess.StandardOutput str As String = mystreamreader.ReadToEnd
MapPath(".") & "/ffprobe.exe"
Dim objWriter As New System.IO.StreamWriter(MapPath(".") & "\debug.txt")
objWriter.Write(str)
objWriter.Close()
Return str
End Function
I'll add an ffmpeg tag since it's also another example on how to call it and process a file.
You don't need to worry about the backslashes. The backslash is not a special character in VB like it is in C#. In fact if you do double them up you might hit errors.
It's hard to tell where the problem is occurring. Some ideas to try to narrow it down:
Try not redirecting StandardInput since you aren't passing it anything.
Read from StandardError to make sure it is empty. It may contain an error message.
I would make use of Debug.WriteLine to trace the function and try to spot where things begin to go wrong.
This may not matter, but I would place myProcess.WaitForExit after mystreamreader.ReadToEnd.
Larry's suggestion to use System.IO.Path is a good one.
Some hastily modified code based on all this:
Function ffprobe_show_format(ByVal arg As String) As String
Debug.WriteLine("arg: " & arg)
Dim fileToProcess As String = IO.Path.Combine(MapPath("."), "temps\" & arg)
Debug.WriteLine("fileToProcess = " & fileToProcess)
Debug.WriteLine("MapPath AND ffprobe.exe: " & IO.Path.Combine(MapPath(".") & "\\ffprobe.exe"))
Dim myProcess As New System.Diagnostics.Process()
myProcess.StartInfo.FileName = IO.Path.Combine(MapPath("."), "\ffprobe.exe")
myProcess.StartInfo.Arguments = "-show_format " & fileToProcess & " >C:\inetpub\vhosts\mysite.com\httpdocs\absolutefs\ffmpegtemp.txt"
myProcess.StartInfo.UseShellExecute = False
'myProcess.StartInfo.RedirectStandardOutput = True
myProcess.StartInfo.RedirectStandardError = True
myProcess.Start()
'Dim str As String = myProcess.StandardOutput.ReadToEnd
Dim errStr as string = myProcess.StandardError.ReadToEnd
myProcess.WaitForExit()
Debug.WriteLine("myProcess exit code = " & myProcess.ExitCode.ToString())
'Debug.WriteLine("stdOutput: " & str)
Debug.WriteLine("stdError: " & errStr)
Return str & ";" & "FileToProcess=" & fileToProcess
End Function
There are a few things to consider here.
First, the back-slash character is the escape character (i.e. \t \n \r ...) and should be double-escaped \\ IF you MUST embed it into strings.
However, the .NET framework contains a very good class: System.IO.Path that has several Combine method overloads that can help you to construct paths without embedding back-slash characters into strings. This also makes your code more portable in the (somewhat unlikely) event that you would ever run it on a non-Windows platform.
http://msdn.microsoft.com/en-us/library/system.io.path
Try closing the StreamReader before accessing its contents:
Dim myStreamReader As StreamReader = myProcess.StandardOutput
Dim str As String = myStreamReader.ReadToEnd
myStreamReader.Close()
Return str & ";" & "FileToProcess=" & fileToProcess & "MapPath(.) AND ffprobe.exe" & MapPath(".") & "\\ffprobe.exe"
When I run your function in my local devbox:
Function ffprobe_show_format(ByVal arg As String) As String
Dim myProcess As New System.Diagnostics.Process()
Dim fileToProcess As String = HttpContext.Current.Server.MapPath(".") & "\temps\" & arg
myProcess.StartInfo.FileName = HttpContext.Current.Server.MapPath(".") & "\ffprobe.exe"
myProcess.StartInfo.Arguments = "-show_format " & fileToProcess & " >C:\inetpub\vhosts\mysite.com\httpdocs\absolutefs\ffmpegtemp.txt"
'myProcess.StartInfo.UseShellExecute = False
'myProcess.StartInfo.RedirectStandardInput = True
'myProcess.StartInfo.RedirectStandardOutput = True
'myProcess.Start()
'Dim myStreamWriter As StreamWriter = myProcess.StandardInput
'Dim myStreamReader As StreamReader = myProcess.StandardOutput
Dim str As String = String.Empty 'myStreamReader.ReadToEnd
Return str & ";" & "FileToProcess=" & fileToProcess & "MapPath(.) AND ffprobe.exe" & HttpContext.Current.Server.MapPath(".") & "\\ffprobe.exe"
End Function
I get what I consider to be a somewhat normal string returned for ffprobe_show_format:
";FileToProcess=C:\Documents and Settings\Me\My Documents\Proj1\SubApp1\temps\testMapPath(.) AND ffprobe.exeC:\Documents and Settings\Me\My Documents\Proj1\SubApp1\\"
I commented out the System.Diagnostics.Process() as I don't have an executable called ffprobe.exe.
Given that the rest of it works, Try closing the StreamReader before accessing its contents.
You should just need to escape each backslash with another backslash.
Or, you might be able to prefix your string with the # symbol (works in C#, not sure about VB.NET).
I.E.
instead of "C:\this\that.exe"
use "C:\this\that.exe"
or #"C:\this\that.exe"

ASP.NET Replacing Line Break with HTML br not working

Hi
I am trying to submit some information into a database using an ASP.NET multiline textbox.
I have the following code:
Dim noteContent As String = Replace(txtNoteContent.InnerText.ToString(), vbCrLf, "<br />")
Shop.Job.Notes.addNote(Request.QueryString("JobID"), ddlNoteFrom.SelectedValue, ddlNoteTo.SelectedValue, noteContent)
The addNote's function code is:
Public Shared Sub addNote(ByVal JobID As Integer, ByVal NoteFrom As Integer, ByVal NoteTo As Object, ByVal NoteContent As String)
Dim newNote As New Job_Note
newNote.Date = DateTime.Now()
newNote.JobID = JobID
newNote.NoteByStaffID = NoteFrom
If Not NoteTo = Nothing Then
newNote.NoteToStaffID = CInt(NoteTo)
End If
newNote.NoteContent = NoteContent
Try
db.Job_Notes.InsertOnSubmit(newNote)
db.SubmitChanges()
Catch ex As Exception
End Try
End Sub
When it submit's the compiler does not seem to detect that line breaks have been entered into the textbox. I have debugged and stepped through the code, and sure enough, it just ignores the line breaks. If I try and replace another character instead of a line break, it works fine.
It doesn't seem to be anything to do with my function, the LINQ insert or anything like that, it simply just doesn't detect the line breaks. I have tried VbCr, and also chr(13) but they do not work either.
Can someone help me? I have been trying ad searching for over an hour trying to sort this.
Thanks
When you do your replace, you should check for VbCrLf (Windows Line Break), VbLf (Unix Line Break) and VbCr (Mac Line Break). If memory serves correct, the standard newline in a HTML textarea element is "\n" (aka VbLf), so you might just get away with replacing VbCrLf with VbLf in your code, but personally I always check for them all just to be safe.
Example
Dim htmlBreakElement As String = "<br />"
Dim noteContent As String = txtNoteContent.Text _
.Replace(vbCrLf, htmlBreakElement) _
.Replace(vbLf, htmlBreakElement) _
.Replace(vbCr, htmlBreakElement)
Shop.Job.Notes.addNote(Request.QueryString("JobID"), ddlNoteFrom.SelectedValue, ddlNoteTo.SelectedValue, noteContent)

creating my own Word wrapper for string

How do I make my own word wrap function for strings? I want each line to be no longer than 50 characters and respect existing CRLFs.
Something like this, it will get you started (just a quick samle i mashed together):
Private Sub Doit()
Dim Source As String = ""
Source &= "How to make my own word wrap function for string, I want each line to be no longer than 50chars and take respect existing CRLFs" & vbCrLf & vbCrLf
Source &= "So this will be a new row."
Dim wrappedtext As String = wrap(Source, 20, vbNewLine)
MsgBox(wrappedtext)
End Sub
Function wrap(ByVal text As String, ByVal maxlength As Integer, ByVal newline As String) As String
Dim tmp() As String = Split(text.Replace(vbCrLf, " | "), " ")
Dim ret As String = ""
Dim wrk As String = ""
For Each word As String In tmp
If word = "|" Then
ret &= newline
wrk = ""
ElseIf word = "" Then
Else
If Len(wrk & word) <= maxlength Then
wrk &= " " & word
Else
ret &= wrk & newline
wrk = word & " "
End If
End If
Next
If wrk <> "" Then ret &= wrk
Return ret
End Function
From which point of view? SW architecture?
Take a look at the decorator pattern. If you like to work with streams, in the book "Heads First: Design Patterns" a string modifier is proposed. It's in Java, but the general programming concept is described in a good way. Some pages are missing but you can find many infos here.
The algorithm itself is trivial, isn't it?

Resources