ASP.Net CType unable to convert "£1,234.56" to Decimal - Need detailed list of influences - asp.net

This is a common question - and it has several common answers.
My problem is that none of them have worked.
The code is entirely typical, a CType to a Decimal, which fails due to globalization settings.
Console.write( CType("£1,234.56", Decimal) )
>>> Conversion from string "£1,234.56" to type 'Decimal' is not valid.
My issue is this particular computer isn't converting the value after several different attempts to fix it.
So far, in no particular order of desperation:
Region settings. Made sure they were (United Kingdom) [en-GB], restarted.
IIS, ".NET Globalisation", Culture is set to Invariant Language (Invariant Country).
IIS, ".NET Globalisation", Culture is set to (United Kingdom) [en-GB].
Region settings, Administrative tab, Copy locale settings.
I've yet to try:
Set in web.config ... https://msdn.microsoft.com/en-us/library/bz9tc508.aspx
Is there anything else I can try?

As the_lotus mentioned, Decimal.Parse will work:
Option Infer On
Imports System.Globalization
Module Module1
Sub Main()
Dim s = "£1,234.56"
Dim d = Decimal.Parse(s, NumberStyles.Currency, New CultureInfo("en-GB"))
Console.WriteLine(d) ' outputs 1234.56
s = "$1,234.56"
d = Decimal.Parse(s, NumberStyles.Currency, New CultureInfo("en-US"))
Console.WriteLine(d) ' outputs 1234.56
If Decimal.TryParse(s, NumberStyles.Currency, New CultureInfo("en-GB"), d) Then
Console.WriteLine(d)
Else
Console.WriteLine("Could not parse.")
End If
Console.ReadLine()
End Sub
End Module
An inferior way would be to remove everything which doesn't belong in a number:
Dim s = "£1,234.56"
Dim re As New Regex("[^0-9,.]")
Dim t = re.Replace(s, "")
Console.WriteLine(CType(t, Decimal)) ' outputs 1234.56
It isn't as good because you don't get to check if the currency symbol was the one you expected.

Related

ASP.NET/VB date works on localhost but not remoteserver

I'm having alot of trouble trying to get the date from a DateTime picker to save to my database. It works fine when run from Localhost, but when running it on the public server it doesn't.
Originally i used the cDate function, plus also tried Convert.ToDateTime. But on the server it now gives me an error "String was not recognized as a valid DateTime."
I researched and found that its best to used the DateTime.TryParse function. After finding an example i changed it for my project and now im getting the error "Must declare the scalar variable "#articledate"."
When i debug the project, the value added into the "result1" DateTime is correct. But it still throws the error at ExecuteNonQuery?
If it makes a difference, the main server is hosted with GoDaddy, Localhost is my PC.
Any help or advice would be greatly appreciated.
cnSQL1 = New SqlConnection(MSSQL.cRemoteConnectionString)
cnSQL1.Open()
sSQL = "SELECT NewsID FROM News WHERE Season = #season AND Heading = #heading AND ArticleDate = #articledate AND Author = #author AND Club = #club AND State = #state AND AddedDate = #addeddate AND AddedBy = #addedby AND Release = #release"
Dim com1 As New SqlCommand(sSQL)
com1.Connection = cnSQL1
com1.Parameters.AddWithValue("#season", General.sSeason)
com1.Parameters.AddWithValue("#heading", General.UppercaseFirstLetter(txtHeading.Text))
Dim result1 As DateTime
com.Parameters.AddWithValue("#articledate", DateTime.TryParseExact(txtArticleDate.Text, "dd-MM-yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, result1))
'com1.Parameters.AddWithValue("#articledate", Convert.ToDateTime(txtArticleDate.Text))
com1.Parameters.AddWithValue("#author", txtAuthor.Text)
com1.Parameters.AddWithValue("#club", ddlClub.SelectedItem.Value)
com1.Parameters.AddWithValue("#state", dsState.Tables(0).Rows(0).Item(0))
com1.Parameters.AddWithValue("#addeddate", Date.Today)
com1.Parameters.AddWithValue("#addedby", Session("UserID"))
com1.Parameters.AddWithValue("#updatedate", Date.Today)
com1.Parameters.AddWithValue("#updateby", Session("UserID"))
com1.Parameters.AddWithValue("#release", s)
com1.ExecuteNonQuery()
The error "Must declare the scalar variable "#articledate" is caused by a typo. When you add the parameter you should use the SqlCommand variable named com1 not the variable com.
But after this you have a more critical error. All the TryParse methods return booleans. The converted date is written in the last parameter passed to TryParse.
In this way you are passing a boolean to AddWithValue and this method takes whatever you put in the value parameter. It has no way to know that you want a date, so it happily complies with your request.
You should do (Notice that the SqlCommand to use is com1 not com)
Dim result1 As DateTime
if DateTime.TryParseExact(txtArticleDate.Text, "dd-MM-yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, result1) Then
com1.Parameters.AddWithValue("#articledate", resul1)
Else
.....
In general it is better to avoid AddWithValue exactly because it takes whatever you pass to it. The preferred way is with
if DateTime.TryParseExact(txtArticleDate.Text, "dd-MM-yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, result1) Then
com1.Parameters.Add("#articledate", SqlDbType.Datetime).Value = result1
com1.Parameters.AddWithValue("#season", General.sSeason)
com1.Parameters.AddWithValue("#heading", General.UppercaseFirstLetter(txtHeading.Text))
com1.Parameters.AddWithValue("#author", txtAuthor.Text)
com1.Parameters.AddWithValue("#club", ddlClub.SelectedItem.Value)
com1.Parameters.AddWithValue("#state", dsState.Tables(0).Rows(0).Item(0))
com1.Parameters.AddWithValue("#addeddate", Date.Today)
com1.Parameters.AddWithValue("#addedby", Session("UserID"))
' This is not used by the query, commented out
' com1.Parameters.AddWithValue("#updatedate", Date.Today)
' This is not used by the query, commented out
' com1.Parameters.AddWithValue("#updateby", Session("UserID"))
com1.Parameters.AddWithValue("#release", s)
com1.ExecuteNonQuery()
Else
MessageBox.Show("Date is not valid")
End If
I have also removed two parameters that are not used in the query above (though they should not cause the error message above)

Having classic ASP read in a key from appsettings in a web.config file

OK so here's the situation. I've got a classic ASP website running inside an MVC 4 application. I need the classic ASP website to be able to get a key from the appsettings section of the web.config file.
Here is the function I've got:
' Imports a site string from an xml file (usually web.config)
Function ImportMySite(webConfig, attrName, reformatMSN)
Dim oXML, oNode, oChild, oAttr, dsn
Set oXML=Server.CreateObject("Microsoft.XMLDOM")
oXML.Async = "false"
oXML.Load(Server.MapPath(webConfig))
Set oNode = oXML.GetElementsByTagName("appSettings").Item(0)
Set oChild = oNode.GetElementsByTagName("add")
' Get the first match
For Each oAttr in oChild
If oAttr.getAttribute("key") = attrName then
dsn = oAttr.getAttribute("mysite")
ImportMySite = dsn
Exit Function
End If
Next
End Function
Here is the function call code:
msn = ImportMySite("web.config", "mysite", false)
So when I call this function the value I get back is always blank or null. I'm not sure where I'm going wrong, I'm a total novice with XML so maybe I'm missing something completely obvious. I have searched the questions but couldn't find anything related to this using classic ASP.
Any help would be much appreciated.
I appreciate Connor's work. It got me well along the way to making this happen. I made some changes that I think might be helpful to others.
I did not want to have to repeat the file name for each call and I have a couple of sections in my config. This seemed more general. Also, I consolidated his changes into a for-sure working example. You can paste this into your app, change the CONFIG_FILE_PATH and get on with your life.
'******************************GetConfigValue*******************************
' Purpose: Utility function to get value from a configuration file.
' Conditions: CONFIG_FILE_PATH must be refer to a valid XML file
' Input: sectionName - a section in the file, eg, appSettings
' attrName - refers to the "key" attribute of an entry
' Output: A string containing the value of the appropriate entry
'***************************************************************************
CONFIG_FILE_PATH="Web.config" 'if no qualifier, refers to this directory. can point elsewhere.
Function GetConfigValue(sectionName, attrName)
Dim oXML, oNode, oChild, oAttr, dsn
Set oXML=Server.CreateObject("Microsoft.XMLDOM")
oXML.Async = "false"
oXML.Load(Server.MapPath(CONFIG_FILE_PATH))
Set oNode = oXML.GetElementsByTagName(sectionName).Item(0)
Set oChild = oNode.GetElementsByTagName("add")
' Get the first match
For Each oAttr in oChild
If oAttr.getAttribute("key") = attrName then
dsn = oAttr.getAttribute("value")
GetConfigValue = dsn
Exit Function
End If
Next
End Function
settingValue = GetConfigValue("appSettings", "someKeyName")
Response.Write(settingValue)
OK I found my answer.
I changed:
For Each oAttr in oChild
If oAttr.getAttribute("key") = attrName then
dsn = oAttr.getAttribute("mysite")
ImportMySite = dsn
Exit Function
End If
Next
To:
For Each oAttr in oChild
If oAttr.getAttribute("key") = attrName then
dsn = oAttr.getAttribute("value")
ImportMySite = dsn
Exit Function
End If
Next

Date field changing from UK to US culture upon SaveChanges (EF6.1)

I am using a custom overloaded SaveChanges to implement some auditing functionality. The functionality works perfectly with the exception of some unexpected behaviour in relation to dates. In this example I'm changing a date field value from 1st May 2014 to 2nd May 2014:
A change is made to the database here:
Public Function UpdateTask(request As DataSourceRequest, ThisTask As JobTasksVM) As JsonResult
Dim cu As ApplicationUser = GetCurrentUser()
Dim CurrentTask = db.events.Find(ThisTask.id)
CurrentTask.start_date = ThisTask.start '<--- 2/5/2014 (ie 2nd May 2014), was previously 1/5/2014
CurrentTask.date = ThisTask.end
CurrentTask.task_name = ThisTask.Title
db.SaveChanges(cu.Employee_id)
End Function
This is intercepted by my custom SaveChanges:
Public Overloads Function SaveChanges(userID As Integer) As Integer
For Each entry As dbentityentry In Me.ChangeTracker.Entries().Where(Function(e) e.State <> EntityState.Unchanged)
Dim startOriginal As DateTime = entry.OriginalValues.Item("start_date")
Dim StartCurrent As DateTime = entry.CurrentValues.Item("start_date")
etc....
The bizarre thing is that whilst CurrentTask.start_date that is committed clearly shows the correct (UK) date of 2/5/2014 (2nd May 2014) the values within the overloaded SaveChanges are:
startOriginal: 5/1/2014 (ie 5th Jan 2014) <-- seems to have changed to US culture
startCurrent: 2/5/2014 (ie 2nd May 2014) <---as expected
I need to use the Original values in my audit functionality so this is causing a problem. I have also tried:
entry.CurrentValues.SetValues(entry.GetDatabaseValues)
But this also loads in the erroneous (ie US format 5/1/2014) into the start_date field.
I've checked all the culture settings on the system and they are all correctly English-UK. This behaviour seems fundamentally inconsistent - am I missing something?!
Thanks
DateTime types do not have a format, they are simply a value (number of ticks since 1/1/0001).
You did not say where you are seeing the "wrong" format, whether ToString() output or in intellisense. If you use ToString to the Output window, you should see the UK format since ToString will use/respect the local culture setting of the computer.
Intellisense is culture agnostic and tries to use an unambiguous format: MM/dd/yyyy. This is the same "format" or order you have to use when creating a DateTime var from a literal:
Dim dt As DateTime = #1/5/2014# ' e.g. MM/dd/yyyy
' same as:
Dim dt As New DateTime(1, 5, 2014) ' mm, dd, yyyy
This is InvariantCulture (not US). When you hold the mouse over the var, the VB IDE will use the same order. It tries to make clear it is using the required literal/InvariantCulture format by displaying it with the hashes: #1/5/2014#.
Dim dt As DateTime = #2/11/2011#
Console.WriteLine(dt.ToString)
In the US, 2/11/2011 will display based on the culture
In the UK, it will be 11/2/2011
Intellisense will be #2/11/2011#

Where do DAC objects live (in Classic ASP)?

I have taken over a departing programmer's Classic ASP object, and I'm trying to debug some DAC code. The trouble is I don't really understand what DAC is or how it works -- and I can't find were the DAC code "lives".
Here's the individual line of code:
set runObj = server.CreateObject("DAC.clsDb_container")
We use SQL Server, and I looked in Enterprise Manager under Stored Procedures and User-Defined functions, but I don't see anything named clsDB_container.
Any suggestions where I can find the code for this DAC object?
The full code in context:
FUNCTION getNewGUID
Dim runCON, runObj, runCMD
DebugWrite( "<BEGIN> iRoutines.asp|getNewGUID (a) GUID=" & GUID & " dealernum=" & dealernum )
set runObj = server.CreateObject("DAC.clsDb_container")
if not runObj.run_query("EXEC sproc_createGUID") then
traperror(runObj.DB_ErrStr)
else
GUID = replace(runObj.get_by_ordinal(0),"-","")
dealernum_len = trim(cstr(len(dealernum)))
set runObj = nothing
end if
getNewGUID = dealernum_len & dealernum & GUID
DebugWrite( "<END> iRoutines.asp|getNewGUID (b) getNewGUID=" & getNewGUID & " dealernum=" & dealernum )
END FUNCTION
This looks like a custom COM object that was written as a data access layer for the site.
The name of the object would be DAC.clsDb_container and lives in a DLL somewhere on the web server.
It is not standard - you will need to look for (I am guessing here) the VB6 or Delphi code that created it if you want to be enlightened further.
if all you need is a GUID then you could do this
<%
Function createGuid()
Set TypeLib = Server.CreateObject("Scriptlet.TypeLib")
dim tg : tg = TypeLib.Guid
createGuid = left(tg, len(tg)-2)
Set TypeLib = Nothing
End Function
%>

How to declare ASP classic constants to a data type?

In asp classic and vbscript, you can declare a Const with a hexidecial value, and a date type value:
Const C_LIGHTCYAN = &hCCFFEE
Const C_STARTDATE = #1 JAN 2000#
But how can I declare currency, single or doubles data types?
Const C_LONG = 1024 '# I want this to be a LONG, not an INT!
I'm sure I've seen something like Const C_LNG = L12345 or some other prefix/suffix combination for longs or doubles but can't find the source now
You can't declare variables with data types in ASP just set the value in decleration, that should work fingers crossed.
I don't think there is currency type anyway. For double you can 1.00 etc.
Here is the CLng function for VBScript. But since you can't declare use a function for a constant declaration, and you can't re-assign to a constant, do you really have to use constants here?
While you can't declare data types in Windows Scripting (VBScript, ASP), you can assign a variable to become a type, then verify that variable's type. VBScript provides no type protections, so you're allowed to reassign a declared variable to a different type. This loose typing strategy is one root of problems.
Dim textVariable : textVariable = "Hello World!"
WScript.Echo TypeName(textVariable)
' Returns Text
Dim integerVariable : integerVariable = 6
WScript.Echo TypeName(integerVariable)
' Returns Integer
Dim objectVariable : set objectVariable = CreateObject("Scripting.Dictionary")
WScript.Echo TypeName(objectVariable)
' Returns Object
Some types require some brute force and trickery. The binary datatype is one example.
Dim generateData(1) : generateData(0) = &HFF
Dim mem : Set mem = CreateObject("System.IO.MemoryStream")
mem.SetLength(0)
mem.WriteByte (generateData(0))
Dim byteArray : byteArray = mem.ToArray()
'Returns a VB Style, "Byte()" [Byte Array]

Resources