Does ASP Classic use reflection? - reflection

I saw a piece of ASP code that looks as follows:
<% rs("Server.HTMLEncode(x)") %>
Since I doubt that the recordset has a field named "Server.HTMLEncode(x)" I was wondering if they meant to write:
<% Server.HTMLEncode(rs(x)) %>
Or if classic ASP does reflection and somehow interprets that string literal as a method call.

I used classic ASP for ten years, and I never encountered any kind of reflection. Based on my past experience, I would agree with you that they probably meant to write:
<% Server.HTMLEncode(rs(x)) %>
But, it still does not look correct. Did they mean to write out the value using Response.Write? I can't tell without seeing more of the code.
Looks like bad coding to me.

Classic ASP can be written with VBScript which does allow kind of reflection by using Eval() and Execute() methods. For example:
Class Foo
Public Bar
End Class
Dim oFoo, propName, myValue
Set oFoo = New Foo
oFoo.Bar = "hello world"
propName = "Bar"
myValue = Eval("oFoo." & propName)
Response.Write("Value of " & propName & ":" & myValue)
However, that's not the case with your sample code. This is just a string literal passed to the Recordset object which looks for exact match. If the given parameter is a number it will return value of field having such index otherwise it expects a string which is exact field name.
Assuming x is user input that should be a field name or index, they probably meant:
<%=rs(Server.HTMLEncode(x)) %>

Related

Using Scripting Dictionary to store Objects in MS Access to avoid circular references and allow forms to know their owner objects

I’m building an Access database with classes e.g clsOrder, clsCustomer etc which manage the interface with tables. These classes create instances of forms when displaying their data. I found that once the execution of code was within one of these forms I couldn’t refer to the parent object that created it (so is there a better way of doing this? would be part of my question).
To deal with this I’m using a scripting dictionary to store instances of classes with a key using the ID of the class and a unique identifier for the class (e.g Order-3265). I then store a reference to the owner object in the form itself.
So when an object is created and its ID is known it puts a pointer to itself in the dictionary and gives that pointer to its form (hope that’s clear enough).
This then allows the form to interact with its owner class.
I’m using another class clsManager to do the adding of items to the Dictionary or retrieval or removal (with destruction).
Examples of classes - seriously cut down..
clsManager:
Public WorkingObjects As New Scripting.Dictionary
Public Function AddWorkingObject(key As String, ObjectType As Object) As Boolean
If Me.WorkingObjects.Exists(key) Then
Me.WorkingObjects.Remove key
Me.WorkingObjects.Add key, ObjectType
Else
Me.WorkingObjects.Add key, ObjectType
End If
End Function
Public Function GetWorkingObject(key As String) As Object
If Me.WorkingObjects.Exists(key) Then
Set GetWorkingObject = Me.WorkingObjects(key)
Else
Set GetWorkingObject = Nothing
End If
End Function
Public Function DestroyObject(obj As Object) As Boolean
Dim key As String
If Not obj Is Nothing Then
key = obj.DictionaryKey
If Me.WorkingObjects.Exists(key) Then
Me.WorkingObjects.Remove (key)
Set obj = Nothing
If obj Is Nothing Then
Debug.Print key & " destroyed"
Else
Debug.Print obj.DictionaryKey & " NOT destroyed"
End If
End If
Set obj = Nothing
End If
End Function
clsQuote:
Option Compare Database
Option Explicit
'use a form using an instance of this class to control manipulation of Quote records
'Loading and saving set default values if a null value is detected
Private Const scTABLE As String = "tblQuote"
Private intID As Long 'unique identifier
Private intCustomerID As Long
Private intSiteID As Long
Private rsQuoteTotalValues As DAO.Recordset
Private oCustomer As clsCustomer
Const ObjectType = "Quote-"
Private oEditForm As Form_frmQuote
Property Get EditForm() As Form_frmQuote
Set EditForm = oEditForm
End Property
Property Get ID() As Long
ID = intID
End Property
Property Let ID(QuoteID As Long)
intID = QuoteID
Me.EditForm.ID = QuoteID
End Property
Property Get Customer() As clsCustomer
Set Customer = oCustomer
End Property
Property Let CustomerID(ID As Long)
intCustomerID = ID
oCustomer.Load (ID)
EditForm.SiteID.RowSource = oCustomer.AddressSQL
EditForm.SiteID.Requery
EditForm.ContactID.RowSource = oCustomer.ContactsSQL
EditForm.ContactID.Requery
EditForm.CustomerID = ID
End Property
Property Get DictionaryKey() As String
DictionaryKey = ObjectType & CStr(Me.ID)
End Property
'END PROPERTIES//////////////////////////////////
Public Sub DisplayForm(Visibility As Boolean)
With Me.EditForm
.Visible = False
.subFrmQuoteSectionsSummary.SourceObject = ""
If Visibility = True Then
...some stuff...
.Visible = True
End If
End With
End Sub
Public Function Load(ID As Long) As Boolean
'On Error GoTo HandleError
Dim RS As DAO.Recordset
Dim sQry As String
Load = False
If Nz(ID, 0) <> 0 Then
sQry = "SELECT * FROM " & scTABLE & " WHERE ([ID]=" & ID & ");"
Set RS = Manager.DB().OpenRecordset(sQry, dbOpenForwardOnly)
With RS
If .RecordCount = 0 Then
MsgBox "Cannot find Quote with ID = " & ID, vbCritical
GoTo Done
End If
Me.ID = Nz(!ID, 0)
Me.CustomerID = Nz(!CustomerID, 0)
Manager.AddWorkingObject Me.DictionaryKey, Me
Me.EditForm.SetOwnerObject (Me.DictionaryKey)
.Close
End With
Set RS = Nothing
Load = True
End If
Done:
Exit Function
HandleError:
MsgBox "Error in Customer Load: " & vbCrLf & Err.Description, vbCritical
Resume Done
End Function
Private Sub Class_Initialize()
Debug.Print "Quote class initialized"
Set oCustomer = New clsCustomer
Set oEditForm = New Form_frmQuote
Me.ID = 0
Set oQuoteTidier = New clsClassTidier
Me.DisplayForm (False)
End Sub
Private Sub Class_Terminate()
Set oCustomer = Nothing
Set oEditForm = Nothing
Debug.Print "Quote class terminated"
End Sub
From the EditForm:
Option Compare Database
Option Explicit
'necessary for the object to have a reference to its owner in this manner to prevent circular reference
Private OwnerObject As clsQuote
Public Function SetOwnerObject(OwnerKey As String) As Boolean
SetOwnerObject = False
Set OwnerObject = Manager.GetWorkingObject(OwnerKey)
SetOwnerObject = True
End Function
Private Sub cmdClose_Click()
OwnerObject.EditForm.Visible = False
Manager.DestroyObject OwnerObject
DoCmd.Close acForm, Me.Name
End Sub
Each business object class (like ClsOrder) has an editForm instance which is loaded and hidden until required and a up to 3 DAO Recordsets that it keeps open.
I think all references to the business objects that are interrelated are pointers to the objects in the dictionary.
My problem is error 3035 exceeding system resources. I’ve checked objects are destroyed when not in use but repeatedly opening and closing objects gets me to error 3035.
So the question is- am I just asking Access to do stuff it can’t or would better programming fix it?
I see ZERO reasons to write all that code. Why not let a form handle all of this? Remember, each form is in fact a "class" instance. You can even launch multiple copies of a single form, each with their own code, own data and each instance of the SAME form can operate 100% independent of other working copies of that same form.
If you attempting to look at this problem and wanting to have a class object for a form, then just use the form object - that's what it does for you!
I see zero benefits from writing all that code. While .net has the dataset manager and system (and now the very similar entity framework, this is MUCH done since .net does not have data bound forms.
In Access, each form is in fact a class object. And that includes any public sub or function for that form (so functions become methods of that form, and public vars become properties of that form). In addition to the bound form having a truckload events, these events work as actions against any data editing. So, unlike most systems, you have "on change" event, before update event, after update event. So, by simply adoptiing a bound form, then you get:
A class object is automatic created for you.
You can have multiple instances of that class, and hence multiple instances of that same form open at the same time.
You get all of those data events that can be used for verifiction of data input (or have the user not save the record until such time your critera is met.
You have full use of all data columns, even if controls are NOT placed on the form bound to those columns. So, you even get intel-sense for all of the data columns - that is you map.
I am not aware that there is some big huge circular reference problem here. This is like stubbing your toe, but then going to the doctor for some huge open heart by-pass operation. So to go on some huge massive coding spree, and chew up huge amounts of developer dollars for some "rare" issue of some kind of rare and un-seen circular reference issue is essentially a huge wild goose chase that will only have you chewing up huge amounts of developer code and time when NONE is required at all.
I mean, if you have say 3 instances of the SAME form open? Then how does the code know and refernce what insance of that form? Well, the EXACT same approac used in typical OO programming can and should be used here. That approach means you don't HARD CODE the forms! name or referances in code EVER. You never want to do this.
So, if you are in a sub form, and need to referacne say data or controls in the parent form?
You could do this:
strLastName = forms!frmCustomer!LastName
In above, we have hard coded the forms name. You don't want to do that.
In that subform, the correct way to write this code is:
strLastName = me.Parent.form!LastName
Now, note how the above referances the parent form. So, that code will work EVEN if we have 3 copies of the frmCustomer active at the same time. You can full refernce ANYTHING in a form by its object "instance". So, in JavaScrip, or c#, you often see "this.SomProperty" as a refeance to that object.
In access, you can do the same thing, and use "me". Or me.Parent.From to reference the parent form. So, as a general approach here, you should NEVER have to hard code forms reference. If you take this approach, then all issues of circular referencing will not only be eliminated, but then you are using a classic and traditional approach to object programming, and object referencing. While Access is not full OO, it certainly follows a lot of OO design concepts, and how forms work in Access are most certainly instances of a object.
Attempting to write truckloads of code when the forms object model already exists as a "single" class object instance of that form makes no sense, and is not required, and the road you going down will likely hamper and reduce your abilities to deal with the fantastic instance of that form you already have.
As noted, the form already has the dictionaly and columns attached, and Access EVEN generates the members for your automatic. The result is you can reference any column of the table that the form is bound to with
me.LastName
me!LastName
While the above two formats are allowed, the first (me + dot + column name) is in fact a member of the forms class. You will find that if you use code to set the forms data source, then often these members are NOT generated for you, and thus you have to use the ! (bang) to reference columns from the table for that form.
So, I don't grasp while you attempting all that extra code when the form has all of the abilities you are asking for in a class object.

asp.net VB best way to return result code

For asp.net framework 4.5 vb
I know that I can use a session variable.. but wondering if there is a more efficient way to return a variable (we call it a condition code) that we set almost in every function /sub being called.
Example
Function xyz(bla as String, blab as String) as dataset
.. do the deed
**Cond.code = -1**
Return ds
We use this Cond.code everywhere. Obviously it can not be a Public Shared variable... but want the most efficient way to always set a "condtion code" within any sub or function... It is valid, only from the time it is set, to the time it is checked by the calling function... so the lifetime is very short.
It's unclear what, exactly the condition code is used for. It's possible that a proper use of custom exception types would replace the need for it. However, if you really need it, it would be better to have it be returned by the method, rather than essentially setting a global, which is pretty rotten. What happens if two methods ever got called simultaneously? It's just brittle and unnecessarily confining.
For instance, you could make a container to hold the return value plus the condition code, like this:
Public Class ReturnValue(Of T)
Public Sub New(value As T, conditionCode As Integer)
Me.Value = value
Me.ConditionCode = conditionCode
End Sub
Public ReadOnly Property Value As T
Public ReadOnly ConditionCode As Integer
End Class
By requiring the code in the constructor, like that, it forces every method to always specify a condition code in its return value. That way it could never be forgotten:
Function xyz(bla As String, blab As String) As ReturnValue(Of DataSet)
' do the deed
Return New ReturnValue(ds, -1)
End Function
However, even then, I would still strongly recommend making the condition code use an enumeration or, at the very least, a set of constants. -1 isn't very self documenting.

Clean way to output values in ASP.NET MVC Views when value is not null

Is there a better way to write the code below? I have quite a few blocks that are similar, and this is making the code in the Viewpage very messy to work with.
The data value with the associated label only needs to be output when certain conditions are met, which is almost always if the value is not null.
The options I can think is to use a response.write to atleast minimize the usage of the ASP script tags, or to format the webpage is such a way that the label displays with an appropriate n/a type value.
<% if (myData.Balance != null)
{ %>
Balance: <%= String.Format("{0:C}", (myData.Balance))%>
<% } %>
If you make use of the DisplayFormatAttribute class in System.ComponentModel.DataAnnotations you can explicitly control the output of null values in your view without dealing with inline script tags. By itself that won't help you remove the labels tied to the value, but you can at least have it automatically substitute an output if the value is null.
[DisplayFormat(NullDisplayText = "N/A", DataFormatString = "{0:c}")]
public double? Price { get; set; }
<%=Html.DisplayFor(m => m.Price)%>
With the above code it will automatically display "N/A" if the value is null, otherwise it will display the value using the default currency format.
As an alternative, if you want to remove the label too and don't want to deal with script tags in your view you could make your own HtmlHelper which takes an expression in the same format of Html.DisplayFor(expression) and then returns the combined output of an Html.LabelFor(expression) and Html.DisplayFor(expression) if and only if the value mapped to that expression is not null.
If you stick the "Balance" inside the format string, and use Response.Write, it ends up looking a lot cleaner, I think:
<% if (myData.Balance != null)
Response.Write(String.Format("Balance: {0:C}", myData.Balance)) %>

Taking a NULL value from the database and assigning to a Date variable

A stored procedure returns data about a user record including a nullable datetime column for their last login date. Which one is the better choice in dealing with the possibility for NULL values when trying to assign a .Net date variable?
Try
_LastLogin = CDate(DT.Rows(0)("LastLogin"))
Catch ex As InvalidCastException
_LastLogin = Nothing
End Try
or
If DT.Rows(0)("LastLogin") Is DBNull.Value Then
_LastLogin = Nothing
Else
_LastLogin = CDate(DT.Rows(0)("LastLogin"))
End If
Edit: I also forgot about the possibility of using a TryParse
If Not Date.TryParse(DT.Rows(0)("LastLogin").ToString, _LastLogin) Then
_LastLogin = Nothing
End If
Which is the preferred method of handling possible NULL values from the database? Is there a better way than the three listed?
Edit #2: I have noticed that the TryParse method does not play nice when trying to assign to a Nullable type.
The second code snippet is better. Exceptions are for exceptional cases, not cases you expect to happen. Plus, the intent is much better. It's clear that you are expecting DBNull to be a possible value and you want to handle it accordingly.
Also, you may have unintended consequences if the value is not null but not parseable (although this is likely to never happen).
The second method is preferable because of the cost involved in throwing exceptions (especially if you expect the LastLogin field to be NULL on a regular basis).
Here is a good blog post with more details about exceptions (see the part about Exceptions and Performance).
I use the FixDBNull class:
Public Class FixDBNull(Of ItemType)
Public Shared Function Convert(ByVal data As Object) As ItemType
If data IsNot System.DBNull.Value Then
Dim obj As ItemType = Nothing
Try
obj = CType(data, ItemType)
Catch ex As Exception
'do something with the conversion error
End Try
Return obj
Else
Return Nothing
End If
End Function
End Class
then I can call it like this:
_LastLogin = FixDBNull(Of date).Convert( DT.Rows(0)("LastLogin"))
which will return either nothing or a date.
in VB.net, it has to be Nullable(of Date)
here’s one way:
dim theDate as nullable(of Date)
If theDate.HasValue Then
'you can proceed
Else
'you must assign with DBNull.value
End If
The database will also likely factor into what you can do.
MS Access will squalk about dates no matter what. I eventually got the above to work, but I usually prefer to save dates as strings in Access. It just makes for less hassle down the road.
I would use TryCast, which'll look something like this:
_LastLogin = TryCast(DT.Rows(0)("LastLogin"), Date?)

ASP.NET embedded code expressions

The below code works but I am not sure how?
OnClientClick='<%# CreateConfirmation(Eval("EventName"),DataBinder.Eval(Container.DataItem, "EventDate", "{0:ddd, d MMM}")) %>'
Public Function CreateConfirmation(ByVal EventName As String, ByVal EventDate As String) As String
Return String.Format("return confirm('Are you sure you wish to register for {0} on {1} ?');", EventName, EventDate)
End Function
I have read that <%# %> is a databinding expression, but overhere we are not directly data-bidning (infact returining value from the function CreateConfirmation) and I also thought that it should work with <%= %> but it gives JavaScript error message i.e. Illigal XML character
pointing to =
Please could you clarify as to why is this?
Many Thanks.
This question is very precisely answered in an exisiting post:
Why will <%= %> expressions as property values on a server-controls lead to a compile errors?
You can call any code inside the <%#. The Eval bit is the piece that makes it relate to the row/object in the datasource.
You are still binding the returned string to the property. You can only use <%=%> with inline HTML. You have to use <%#%> when binding to a contols property.

Resources