Properly Defining a Singleton in asp.net - asp.net-2.0

I've the following class which is a singleton implementation:
Imports Microsoft.VisualBasic
Imports System.Xml
Public Class GlobalController
Private Shared instance As GlobalController
Private ControlsXmlDoc As XmlDocument
Private xmldocpath As String
Sub New()
ControlsXmlDoc = New XmlDocument
xmldocpath = HttpContext.Current.Server.MapPath("~/cp/GlobalControl.xml")
ControlsXmlDoc.Load(xmldocpath)
End Sub
Shared Function GetInstance() As GlobalController
If instance Is Nothing Then
Return New GlobalController
Else
Return instance
End If
End Function
Shared Property IsExtracting() As Boolean
Get
Return Boolean.Parse(GetInstance.ControlsXmlDoc.SelectNodes("global/extraction/proceed").Item(0).InnerText)
End Get
Set(ByVal value As Boolean)
HttpContext.Current.Application.Lock()
Dim node As XmlNode = GetInstance.ControlsXmlDoc.SelectNodes("global/extraction/proceed").Item(0)
If Not Boolean.Parse(node.InnerText) = value Then
node.InnerText = value.ToString
node.Normalize()
SaveDocument()
GetInstance.ControlsXmlDoc.Load(GetInstance.xmldocpath)
End If
HttpContext.Current.Application.UnLock()
End Set
End Property
Shared Sub SaveDocument()
GetInstance.ControlsXmlDoc.Save(GetInstance.xmldocpath)
End Sub
End Class
In my page I am doing something like this:
GlobalController.IsExtracting = False
Response.Write(GlobalController.IsExtracting)
I am always getting the output as "true". What is wrong with the code?

According this link Operator precedence and associativity, ! (or vb.net Not) have greater priority than == (= in VB.NET); so, your expression is always evaluated as
Not(True) And False
and never enters that If statement.
Try to use Boolean.Parse(node.InnerText) != value or Not (Boolean.Parse(node.InnerText) = value) in order to get correct result.

All, thanx for ur answers. I apologize for what I am about to say. I found the bug: it was with the way I implemented the singleton. Forgot to assign the newly created object instance to the shared variable.
Shared Function GetInstance() As GlobalController
If instance Is Nothing Then
instance = New GlobalController
End If
Return instance
End Function

Related

Dim variable as datatype stored in db field

I have database table which has a field called "datatype". It will hold a particular datatype, such as string, integer, classname, etc....
How can I dim a variable using whatever is stored in this field? For example, if the field says "string" I want to effectively say "Dim MyVar as string", but fill in the "string" portion with what's stored in the table. Hope that makes sense. Thanks!
You can create instances from the name of the class. Note, you can't ask for "MyClass1" without the namespace before it. There are some options for getting from "MyClass1" to "Namespace.MyClass1" such as a Dictionary or even putting the full type name in your database.
Module Module1
Sub Main()
' compiler knows mc1 is a IMyClasses
Dim mc1 = CType(getInstanceFromTypeName("ConsoleApplication1.MyClass1"), IMyClasses)
' compiler doesn't know, mc2 is an object
Dim mc2 = getInstanceFromTypeName("ConsoleApplication1.MyClass2")
mc1.Foo()
mc2.foo()
End Sub
Private Function getInstanceFromTypeName(typeName As String) As Object
Dim o As Object
Try
o = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(typeName)
Catch ex As Exception
o = Nothing
End Try
Return o
End Function
End Module
Public Class MyClass1
Implements IMyClasses
Public Sub Foo() Implements IMyClasses.Foo
Debug.Print("MyClass1")
End Sub
End Class
Public Class MyClass2
Implements IMyClasses
Public Sub Foo() Implements IMyClasses.Foo
Debug.Print("MyClass2")
End Sub
End Class
Public Interface IMyClasses
Sub Foo()
End Interface
mc1.Foo() works because mc1 is declared as an IMyClasses, and IMyClasses defines this subroutine. The compiler knows that IMyClasses defines Foo.
mc2.foo() doesn't work with Option Strict On because Foo() is not a member of Object. With O.S.On, the compiler must be able to resolve all function calls at compile time. It works with Option Strict Off however, as O.S.Off allows function calls on Object, but can potentially be dangerous because O.S.Off also allows mc2.asdf(), for example.
Other resources:
Using System.Reflection
Using System.Activator

Problems implementing a recursive find extension method

I am attempting to implement a recursive extension method in VB.net that will find all objects with a certain property set so I can call it like so...
Dim camp As New CampaignStructure 'Populated with a full structure of course
Dim lstFoundItems As List(Of CategoryStructure) = camp.Categories.FindRecursive((Function(c) c.Found = False), 3)
My VB.Net classess and modules currently look like this
Imports System.Runtime.CompilerServices
Namespace MyStructure
Public Class CategoryStructure
Public Property CategoryID As Integer = Nothing
Public Property Name As String
Public Property Rank As Integer
Public Property Found As Boolean = False
Public Property Children As New List(Of CategoryStructure)
End Class
Public Class CampaignStructure
Public Property CampaignID As String = Nothing
Public Property Categories As List(Of CategoryStructure)
End Class
Public Module ControlExtensions
<Extension()> _
Public Function FindRecursive(cs As List(Of CategoryStructure), predicate As Func(Of CategoryStructure, Boolean), depthLimit As Integer) As List(Of CategoryStructure)
If cs Is Nothing OrElse cs.Count = 0 Then
Return New List(Of CategoryStructure)()
End If
If depthLimit = 0 Then
Return cs.OfType(Of CategoryStructure)().Where(predicate).ToList()
Else
'**ERROR IS THROWN HERE**
Return cs.OfType(Of CategoryStructure)().Where(predicate).ToList().Union(cs.Cast(Of CategoryStructure).Select(Of List(Of CategoryStructure))(Function(c) c.Children.FindRecursive(predicate, depthLimit - 1)).ToList())
End If
End Function
End Module
End Namespace
However I'm having casting problems when I'm unioning the recursive result with the current list at the point in the code marked. I can see why that's happening, just have no idea how to resolve it. Please do not send me C# examples as there is no 'yield' alternative in VB.net
That's because both sides of UNION have different signatures.
cs.OfType(Of CategoryStructure)().Where(predicate).ToList()
This returns List(Of CategoryStructure).
cs.Cast(Of CategoryStructure).Select(Of List(Of CategoryStructure))(Function(c) c.Children.FindRecursive(predicate, depthLimit - 1)).ToList()
This one returns List(Of List(Of CategoryStructure))
I think what you're looking for is:
Return cs.OfType(Of CategoryStructure)().Where(predicate).Union(cs.Cast(Of CategoryStructure).SelectMany(Function(c) c.Children.FindRecursive(predicate, depthLimit - 1))).ToList()
SelectMany returns flattened collection typed as IEnumerable(Of CategoryStructure).

ASP.net 2010 (VB) Object reference not set to an instance of an object

Morning All,
I am using VS2010 with VB and im trying to get a ping test working in my web application. In order to do this and test that it works i have simply created a button that when clicks should ping a specified IP address.
I believe that the code for the button should work fine. The only issue i have is the following error message on my web page...
System.NullReferenceException: Object reference not set to an instance of an object.
It bugs on the cole line...
Console.WriteLine("Address: {0}", vPingReply.Address)
I thought that this was due to 'Properties' needing to be set up for the .Address and .Status objects. Im not too sure if i have added these correctly as i have added some properties but i still have the same issue when i run the page?
Can someone please take a look and advise?
Here is my full code...
Imports Microsoft.VisualBasic
Imports System.Text
Imports System.Net.NetworkInformation
Imports System.Net.NetworkInformation.PingReply
Partial Class Ping
Inherits System.Web.UI.Page
Private mSend As PingReply
Private Property Send(p1 As String) As PingReply
Get
Return mSend
End Get
Set(value As PingReply)
mSend = value
End Set
End Property
Private mAddress As PingReply
Private Property Address(p2 As String) As PingReply
Get
Return mAddress
End Get
Set(value As PingReply)
mAddress = value
End Set
End Property
Private mStatus As PingReply
Private Property Status(p3 As String) As PingReply
Get
Return mStatus
End Get
Set(value As PingReply)
mStatus = value
End Set
End Property
Protected Sub btnPing_Click(sender As Object, e As System.EventArgs) Handles btnPing.Click
Dim vPing As New Ping
Dim vPingReply As PingReply = vPing.Send("xxx.xx.xxx.xx")
Console.WriteLine("Address: {0}", vPingReply.Address)
Console.WriteLine("Status: {0}", vPingReply.Status)
End Sub
End Class
Any help is much appriechiated.
Betty.
You cannot access the content of Address property if the Status is not Success
Dim vPing As New Ping
Dim vPingReply As PingReply = vPing.Send("xxx.xx.xxx.xx")
if vPingReply.Status = IPStatus.Success Then
Console.WriteLine("Address: {0}", vPingReply.Address)
End If
Console.WriteLine("Status: {0}", vPingReply.Status)
The docs says
If the value of Status is not Success, you should not use the values
returned by the RoundtripTime, Options or Buffer properties. The
RoundtripTime property will return zero, the Buffer property will
return an empty array, and the Options property will return null.
but I found that the Address property is null (Nothing in VB) also if the Send is for a non-existant ip address or DNS name
However, looking better at your code, it is clear that all the calls made inside the btnPing_Click method are handled by your class Ping not to the framework class Ping. And your class uses variables not correctly initialized. I suggest to remove those methods from your class or just rename the class with something different.
Another option (not recommended) is this
Private Property Send(p1 As String) As PingReply
Get
' Specify the full namespace to remove ambiguity between this class and framework class
Dim p = new System.Net.NetworkInformation.Ping()
mSend = p.Send(p1)
Return mSend
End Get
Set(value As PingReply)
mSend = value
End Set
End Property
Private Property Address() As String
Get
if mSend IsNot Nothing Then
Return mSend.Address
else
Return string.Empty
End If
End Get
' Meaningless ???
'Set(value As PingReply)
' mAddress = value
'End Set
End Property
Private mStatus As PingReply
Private Property Status() As String
Get
if mSend IsNot Nothing Then
Return mSend.Status.ToString()
else
Return string.Empty
End If
End Get
' Meaningless ???
'Set(value As PingReply)
' mStatus = value
'End Set
End Property

Do I Need a Class if I only need 1 Property (at the moment)?

Update: I didn't make it clear but I meant this to be a question about where/how I would use a function to return a list of strings when I'm trying to just work with classes.
I have a class called Account.
I have data access class called AccountDAO.
I have various functions that return lists of objects like GetAllAccounts, GetAccountByID etc.
I want to populate a drop down list with just the account names and nothing else. It's proving rather slow when using lists of objects and databinding them to the dropdownlist.
I feel like I should be using a simple "Select Account_Name From blah" type statement and returning a list of strings but I don't know how to work this into my class and data access class.
How should I handle this predicament?
You can use a list of string,s and bind the list of strings to a dropdownlist no problem... the DDL can support that, just leave out DataTextField and DataValueField props, and it will display the account name as is, which that name would be accessible through the ListItem's Text and Value property.
I like to use objects to be consistent with the rest of the app (which other areas might need a class), and if for some reason you want to add AccountKey later, if you use an object, all you need to do is add a property. Otherwise, if using strings, you'd have to switch up the binding later to point to the object.
HTH.
There is nothing wrong by making a function that only returns a list of strings. YOu could however wonder if it's not better to restrict the number of records you want to put in the list and use some kind of paging.
Assuming that you're using a List<>, you can try something like this:
IEnumerable<string> nameList = accountList.Select(t => t.AccountName);
Or if you need a List:
List<string> nameList = accountList.Select(t => t.AccountName).ToList();
Go with your feelings. Use a datareader to select the list and then load them into an arraylist which can then be bound to the dropdown. Alternately, use something like this method I use to provide both a DisplayMember and a ValueMember which uses a class (with both values) as members of the arraylist. This should give you the general idea. (Note: I normally include this code in a data access class (MyBase) where StartReader, _datRdr, ReadNext and_ReaderValid are a members. But the general idea is intact.)
Public Sub LoadDataSource(ByRef PlantDataSource As PlantSource, Optional ByVal Filter As String = "", Optional ByVal IncludeBlankItem As Boolean = False)
PlantDataSource = New PlantSource
If IncludeBlankItem Then
PlantDataSource.Add(0, "")
End If
If Filter = String.Empty Then
Call StartReader(" Order by PlantName")
Else
Call StartReader(String.Concat(" Where ", Filter, " Order by PlantName"))
End If
If _DatRdr.HasRows Then
While MyBase._ReaderValid
PlantDataSource.Add(PlantId, PlantName)
ReadNext()
End While
End If
Call CloseReader()
End Sub
Private Class PlantListing
Private _PlantList As New ArrayList
Public Sub Add(ByVal PlantId As Integer, ByVal PlantName As String)
_PlantList.Add(New PlantDataItem(PlantId, PlantName))
End Sub
Public ReadOnly Property List() As ArrayList
Get
Return _PlantList
End Get
End Property
End Class
Private Class PlantDataItem
Private _PlantId As Integer
Private _PlantName As String
Public Sub New(ByVal pPlantId As Integer, ByVal pPlantName As String)
Me._PlantId = pPlantId
Me._PlantName = pPlantName
End Sub
Public ReadOnly Property PlantName() As String
Get
Return _PlantName
End Get
End Property
Public ReadOnly Property PlantId() As Integer
Get
Return _PlantId
End Get
End Property
Public ReadOnly Property DisplayValue() As String
Get
Return CStr(Me._PlantId).Trim & " - " & _PlantName.Trim
End Get
End Property
Public Overrides Function ToString() As String
Return CStr(Me._PlantId).Trim & " - " & _PlantName.Trim
End Function
End Class

Connect reusable ASP.NET WebControl to a method for loading data

I'm trying to create a control that can extend other webcontrols and set some properties like visible and enabled, based on user permissions.
Here's an example where your user role would need to include the "CanSave" permission:
<asp:Button ID="btn1" runat="server" Text="Save"/>
<myControls:PermissionsExtender runat="server" ControlToSet="btn1" Permission="CanSave"/>
I'm trying to keep this reusable, that's why the PermissionExtender is in a separate project that can not have any dependencies to other projects. To make a decision, the control of course needs to get this info from somewhere else (database or something). I made another control and, using events, the above extender will be set by a master control, so only that needs to know where to look up the information.
The master control now needs to be configured to know where the information about roles and permissions will be coming from. My idea was to have an interface inside the reusable project, and implement that somewhere else, then configure my control to go and find the class that implements the method I need and load it through reflection. But I'm unclear how this could work. I would probably place the master control in the masterpage and supply it a class name like PermissionClass="SecurityLibrary.PermissionsClass". Kinda like ObjectDatasource does it, but other suggestions are welcome.
The method signature would be like:
bool HasPermission(string permission)
It would know the current users role and using that combination, looks up if the role includes the permission.
How can I wire up a call from the control to a method inside my main project that can supply the necessary information without making them dependent.
I think I've got something that will work for you (tested fine for me but I may have misunderstood part of what you were looking for). With this implementation the asp.net designer code will look like this:
<web:PermissionMasterControl runat="server" ID="masterController" PermissionClass="SecurityLibrary.RandomPermissionClass" />
<asp:Button ID="btnSave" runat="server" Text="save" />
<web:PermissionExtender runat="server" ControlToSet="btnSave" Permission="CanSave" MasterControllerID="masterController" />
Now for the SecurityLibrary. Pretty straight forward, I included a simple "RandomPermissionClass" that randomly returns true/false.
Namespace SecurityLibrary
Public MustInherit Class PermissionClass
Public MustOverride Function HasPermission(ByVal permission As String) As Boolean
End Class
Public Class RandomPermissionClass
Inherits PermissionClass
Private rand As New Random()
Public Overrides Function HasPermission(permission As String) As Boolean
Return If(rand.Next(2) = 0, False, True)
End Function
End Class
End Namespace
Now we have the "myControls" library, which contains no references to SecurityLibrary. I created two controls and a delegate. The controls are "PermissionMasterControl" and "PermissionExtender". The delegate is what is used to actually perform the check against the reflected object.
Namespace myControls
Public Delegate Function HasPermissionDelegate(ByVal permission As String) As Boolean
Public Class PermissionMasterControl
Inherits System.Web.UI.Control
Public Property PermissionClass As String
Get
Return If(ViewState("PermissionClass") Is Nothing, "", ViewState("PermissionClass").ToString())
End Get
Set(value As String)
ViewState("PermissionClass") = value
End Set
End Property
Private ReadOnly Property PermissionDelegate As HasPermissionDelegate
Get
If _permissionDel Is Nothing Then
If Not String.IsNullOrEmpty(PermissionClass) Then
Dim t = Type.GetType(PermissionClass, False)
If t IsNot Nothing Then
_permissionObj = Activator.CreateInstance(t)
Dim mi As MethodInfo = _
t.GetMethod("HasPermission", BindingFlags.Public Or BindingFlags.Instance)
_permissionDel = [Delegate].CreateDelegate(GetType(HasPermissionDelegate), _permissionObj, mi)
End If
End If
End If
Return _permissionDel
End Get
End Property
Private _permissionObj As Object = Nothing
Private _permissionDel As HasPermissionDelegate = Nothing
Public Function HasPermission(ByVal permission As String) As Boolean
If PermissionDelegate Is Nothing Then
Throw New NullReferenceException("The specified permission class (" + PermissionClass + ") could not be loaded/found.")
End If
Return PermissionDelegate(permission)
End Function
End Class
Public Class PermissionExtender
Inherits System.Web.UI.Control
Public Property ControlToSet As String
Get
Return If(ViewState("ControlToSet") Is Nothing, "", ViewState("ControlToSet").ToString())
End Get
Set(value As String)
ViewState("ControlToSet") = value
End Set
End Property
Public Property Permission As String
Get
Return If(ViewState("Permission") Is Nothing, "", ViewState("Permission").ToString())
End Get
Set(value As String)
ViewState("Permission") = value
End Set
End Property
Public Property MasterControllerID As String
Get
Return If(ViewState("MasterControllerID") Is Nothing, "", ViewState("MasterControllerID").ToString())
End Get
Set(value As String)
ViewState("MasterControllerID") = value
End Set
End Property
Protected ReadOnly Property MasterController As PermissionMasterControl
Get
If _mastercontroller Is Nothing Then
_mastercontroller = Me.Page.FindControl(MasterControllerID)
End If
Return _mastercontroller
End Get
End Property
Protected ReadOnly Property ManagedControl As Control
Get
If _controlToSet Is Nothing Then
_controlToSet = Me.NamingContainer.FindControl(ControlToSet)
End If
Return _controlToSet
End Get
End Property
Private _controlToSet As Control = Nothing
Private _mastercontroller As PermissionMasterControl = Nothing
Protected Overrides Sub OnLoad(e As System.EventArgs)
MyBase.OnLoad(e)
Dim bResult As Boolean = MasterController.HasPermission(Permission)
ManagedControl.Visible = bResult
End Sub
End Class
End Namespace

Resources