when to use shared variables - asp.net

I have built a class which is instantiated many times in a list using vb.net. I want to persist an ID across all instantiations of my class. It's a list of questions which will all have one questionnaire ID. So I can do this whilst assigning the id to each question in the list. Ideally I would like to just assign the ID once and have it available in all the list objects.
So here is my shared member of a class along with property procedure for accessibilty.
Public Class Questions
Private Shared _questionnaireUID As Integer
Public Shared Property QuestionnaireUID() As Integer
Get
Return _questionnaireUid
End Get
Set(ByVal value As Integer)
_questionnaireUid = value
End Set
End Property
End Class
I started to use a vb.net shared class level variable and assigned through a property procedure. This seemed like the right approach, although now I have built it I can see that the shared variable is accessible throughout the entire application.
So like this for instantiation and assignment.
Questions.QuestionnaireUID = CInt(questionnaireUID)
I dont even need to instantiate the class. So I now just have a global variable. to get around this I would use a class level variable instead of. I wondered if there is another way to just make the variable shared across the class and it's instantiated objects without assigning to each object and without making it available across the entire application. Is there a step I am missing.
Thanks for any advice.

I am C# but that is not how I would go about it.
Have a class for the questionnaire
public class Questionnaire
{
public Int ID { get; private set; }
public List<Question> Questions { get; set; }
}

I think a shared (static) is really useful if you want to share something in the whole application.
If I understand you right, you indeed have a class and would like to share one ID, but this ID is not interesting for the whole application but only for a questionnaire (a list of questions). For this, using shared is bad, because you will have to take care of the cleaning of this value once you're finished.
My question is, why do you instantiate the question list every time that you have a new question? Why don't putting the question list as a singleton?

Just because the private field is Shared, that does not mean that the property that accesses it also has to be Shared. For instance, you could do this:
Public Class Questions
Private Shared _questionnaireUID As Integer
Public Property QuestionnaireUID() As Integer ' Note, this is not Shared
Get
Return _questionnaireUid
End Get
Set(ByVal value As Integer)
_questionnaireUid = value
End Set
End Property
End Class
When you do that, all Questions objects will always share the same value for that property, but the value will not be accessible through the class (without instantiating an object).
However, it's worth pointing out that, while that does encapsulate the value a little better as far as scope is concerned, it's still global state. It doesn't really avoid most of the problems which are caused by having global variables. The objects of that class will still behave in potentially unpredictable ways just as with any other kind of global state. It also makes it so that you cannot have Questions objects working on two different ID's at the same time.
As an alternative, you may want to look into injecting the ID in the Questions class' constructor. If passing it in each time you create one is too much of a pain, you could make it easier with a factory, for instance:
Public Class QuestionsFactory
Public Sub New(questionnaireId As Integer)
_questionnaireId = questionnaireId
End Sub
Private _questionnaireId As Integer
Public Function NewQuestions() As Questions
Return New Questions(_questionnaireId)
End Function
End Class

Related

Is it bad to instantiate request and response objects in other functions?

I could not find a similar question, and this could be a dumb question, not sure, I couldn't figure out what keywords to search for.
For example, we have some sort of request/response pair for accessing information from the database (forgive me, using VB .NET at work, not my choice, so I'm just staying consistent)
Public Class ItemAddRequest
Public param1 As String = ""
Public param2 As String = ""
End Class
Public Class ItemAddResponse
Public returnParameter As MyItemObject = ""
Public Function Invoke(req As ItemAddRequst)
' SQL Queries go here
' Build my returnParameter
End Function
End Class
So these are used for the front end to get information to display on the front end, but is it bad to use these somewhere else in your code for the sole purpose of getting that info or adding that info? Generally you would want to modularize (invented word) that and use methods of my MyItemObject to do this, but we already have a large collection of things that would need to be changed so we are not doing that, at least for now. So for example we are doing something like this
Public Class ParentItemAddRequest
Public param1 As String = ""
Public param2 As String = ""
End Class
Public Class ParentItemAddResponse
Public returnParameter As MyParentItemObject = ""
Public Function Invoke(req As ParentItemAddRequest)
' SQL Query goes here to add parent
' Now also need to add a regular MyItemObject
Dim itemReq as new ItemAddRequest()
Dim itemResp as new ItemAddResponse()
itemReq.param1 = 'whatever
itemReq.param2 = 'whatever
itemResp.Invoke(itemReq)
me.returnParameter = itemResp.returnParameter
End Function
End Class
Doing this seems to work fine, but what kind of problems could we anticpate to cause? Or is this a completely normal thing? Seems odd to us. Thanks for the help.
If this code works than not much is wrong. If it aint broke then dont fix it. That being said, the only thing wrong with this code, i think, is that it uses wrong patterns. It just looks wrong. The only problem it would create is that it would confuse the hell out of new hires. Another serious implication of working this way is that the Class is now responsible for two things (1) declaring the data contract (2) defining the algo to fill it. This mixup is frowned upon according to SOLID principles. The mixup of responsibilities make it difficult to do unit testing and impact analysis.
When I find a Request class and Response class, the immediate assumption is that you guys are using the DTO pattern. The classes are assumed to be data contracts because of their naming convention. Now, the dtos are supposed to be simple POCOs devoid of any business logic. This is so that you can put all such classes in a seperate dll and different clients can use the shared data structures. So I wont be expecting the Invoke method there. I would expect that the dto is filled at the DAL layer either by handcrafted sqls in a DAO class or via some orm like entity framework.
With handcrafted sqls, I would expect a set of classes like Class ParentItemDAO with methods like Function Add(req As AddParentItemRequest) As AddParentItemResponse. Similarly I would expect a method Function GetParentItemById returning either a business object or a dto.

Method types within a Class in VB.NET 4.0

A friend asked me this and not sure how to understand. Prolly a simple answer.
He has the following
Public Class TestClass
Public Sub Setup()
MsgBox ("Hello")
End Sub
End Class
Based on that example, what type of member is Setup, in relation to the TestClass class?
I think it it might be an instance member. Because a class is just a collection of instances (methods, properties, etc) within the class.
Correct?
This would be an instance method as opposed to a class method (static methods).
When a field, method, property, event, indexer, constructor, or destructor declaration does not include a static modifier, it declares an instance member.
More information here.
Initially my answer said that a member is the same as a field. According to the MSDN link above this was not entirely correct so I adjusted it. You'll also notice that they use the term static member instead of instance member.
Terminology is a very tricky subject and you'll notice people use many different descriptions for the same subject. This is further amplified when you take other languages in consideration and the terminology there.
It is an instance method, but not because a class is a collection of instances.
It is an instance method because TestClass is not shared (static), and must be instantiated. That is, there must be a instance of TestClass available to use its method Setup(). Conversely, with a Shared class, you do not need an instance of TestClass to use Setup(), it would be a Shared method and not an instance method.
That is academic, however, since VB does not support static classes (Shared Classes), but does support shared methods, the effective difference is that declaring Setup() as Public makes it an instance method, or declaring it as Shared would make it a static method.

How to get a public variable (in a Module) to NOT share value between users

I'm working in an ASP.NET (VB) Web Application with Windows/Active Directory Authentication
I am using a module so that I can call public subroutines and functions, and reference variables, without having to instantiate a new object to access them on each page.
Within that module, I have some Public variables that I am using in multiple pages throughout the web application. I've recently realized that the values for these public variables in the module get shared between all users.
THE GOAL:
I want the value for these global variables to be specific to a single user and not shared between all sessions, and I do not want to have to instantiate a new object/class on every page that uses the variable.
THE CATCH:
I don't want to store the value in a client-side variable such as a cookie or session. I want the value to be stored on the SERVER but specific to each client/user.
The only thing I can think to do is setup a global collection/dictionary and store the variables with the authenticated user names, but then I need to have specific functions to get and set the values. While this will work, it requires all the references to these variables on all pages in the application to be updated.
EXAMPLE OF THE PROBLEM:
The below code shows how I am creating the public variable within the module and how the value is being set from one page and used on another. I'd like to continue to use this variable in the same way and share it's value between pages, but the value of the variable needs to NOT be shared between users.
-- MODULE.VB --
Public Module MyMod
Public myVariable as String = ""
End Module
-- MAINPAGE.VB --
Partial Class _Default
Sub Page_Load() Handles MyBase.Load()
myVariable = "HELLO WORLD"
End Sub
End Class
-- NEXTPAGE.VB --
Partial Class _Default
Sub Page_Load() Handles MyBase.Load()
Response.Write(myVariable)
End Sub
End Class
There are a LOT of pages in this application that will need to be manually updated if I have to use my userID-indexed collection solution, so I'm hoping there is a way to simply scope these variables differently or a way to disable the sharing between sessions.
Thanks in advance!
You didn't indicate whether or not the variables need to be persisted across page round trips or whether they are just used within each page's lifecycle.
If they are not persisted across pages, then perhaps the easiest solution is to have all of your pages inherit from a based page class and then move the values from the module into the base page. This way you won't have to change any variable references, only page inheritance.
If you do want to persist the values, completing the above changes makes it much easier to implement. You can then turn the member variables on the base page into properties and embed your user specific caching and fetching in the getter and setter.
For example, instead of:
Public MyVariable As String = ""
You would have something like:
Public Property MyVariable As String
Get
Return GlobalMyVariableCache(UserNameKey)
End Get
Set (Value As String)
GlobalMyVariableCache(UserNameKey) = Value
End Set
End Property
The problem you are coming across is a very common one in web programming. A Module's members are static - meaning there is one instance of them across the entire AppDomain of your application. Every user that accesses these will get the same object - you have already learned this.
Your options are exactly what you described. You could possibly replace the public variable in your module with a property whose getter you write to access a user-specific field in a dictionary (please remember thread safety when writing this getter code).
The much easier solution would be to use the Session. Session values are stored server-side and are user specific. The only thing that get's sent client side is the session key, and if you are using .Net authentication, this is likely already getting sent.
Good luck,

Populating Object with Data VB.net

I'm looking to populate an object then display the data to labels.
I've created a Student Class:
Public Class student
Public Dim sNum As Integer
Public sName As String
Public Sub New(ByVal sNum As Integer)
MyBase.New()
Me.sNum = sNum
End Sub
I've got a database class that I want to use to populate this.
Public Function populateStudent() As Object
Dim ObjStudent As New student(1)
ObjStudent.sName = "Bitz"
Return ObjStudent
End Function
Obviously this is just a step, eventually I'll be querying the database to populate the data, but I want to get this working first so I know I'm creating this correctly.
In my main class attached to my .aspx I want to be able to do
lblStudentName.Text = ObjStudent.sName
Am I going about this correctly, or is there a better way?
You need not have
MyBase.New()
because you don't have a explicit base class.
The return type of populateStudent() of Object does not make much sense; it should be either a list of Student if you are planning to return a collection of student after querying the db. if you are planning on populating the view from this method itself, then it should be a Sub returning nothing and not a Function.
Otherwise everything else looks okay.
EDIT:
Sounds like you need something like this.
Public Function populateStudent(Id as String) As student
Dim ObjStudent As New student(1)
ObjStudent.sName = "Bitz"
Return ObjStudent
End Function
Close. You'll want to set the .Text property on the Label control:
lblStudentName.Text = ObjStudent.sName
(which you have since edited your question to contain... it often bothers me that SO doesn't show that something was edited if the edit is very soon after the initial post)
As for a "better way" just remember that there are many, many ways to do just about anything. "Better" is very relative and depends on other factors not present in the code you have so far. As of now, you have a method which returns an instance of an object (similar to the Factory pattern, feel free to research more on that and other patterns) and you use properties on that object to populate data fields in the UI. Pretty straightforward, nothing wrong with it.
As the system grows and the problem domain becomes more complex, there will be more definition of "good design" vs. "bad design." But in just getting started, this is perfectly fine.

Override An Existing Property as a Child form of its return type

I apologize if that title is confusing. This question may be a result of lack of coffee and/or sleep, but my mind is not working correctly right now.
Anyways, I have an inheritance tree like so (I know the architecture isn't ideal):
BaseClass
GeneralForm : Inherits BaseClass
SpecificForm : Inherits GeneralForm
And an object like so:
MyItem
MySpecificItem : Inherits MyItem
I have Items As List (Of MyItem) as a property in BaseClass. I would like for SpecificForm to somehow override Items to return type List (Of MySpecificItem). I feel like this is easy to do, but again, my head is spinning and I can't think straight at the moment.
Thanks so much in advance.
EDIT
If the above isn't possible, is it possible to take a List (Of MyItem) and turn it into a List (Of MySpecificItem)? MySpecificItem has just one additional property that is specific to SpecificForm, but I NEED it.
Anyone? :\
You should be able in SpecificForm to just do the following...
Private pMySpecificItems As List(Of MySpecificItem)
Public Shadows ReadOnly Property Items() As List(Of MySpecificItem)
Get
Return pMySpecificItems
End Get
End Property
The 'Shadows' keyword will tell the compiler that this property in SpecificForm hides the Items property from the base-class form.
You can't actually delegate to the base class' property and "cast" it to List(Of MySpecificItem) because while a sub-class may be viewed as an instance of its base class, a base class object cannot be cast to an instance of a sub-class (as the sub-class may have added required properties/state that the base class does not support or implement).

Resources