I have an Asp.Net Core application. I have used session to keep track of objects a user may access.
On one of the pages on the website, I have two lists that are loaded by JavaScript AJAX. When the IDs of the records for these lists are found, these IDs are then stored in a session variable as a serialized string (case from a list of ints).
These are 2 unique lists, with 2 unique session variables, lets call them List1 and List2.
So it ends up with something like:
List1 = [1,2,3,4,5]
List2 = [100,101,102,103]
The problem is, as these two are called at the same time or in very quick succession via JS, it seems like the Session server side is being overridden by whichever is stored last.
I am using HttpContext.Session.SetString to set these.
I have tried using a setTimeout of a second, before calling the second list and that makes everything work, but that's not the most elegant or reliable.
It seems as though the whole Session object is updated when the SetString is called and I end up losing the Session variable for one or another list.
Is there any way around this, or something I'm missing?
Thanks!
David
Related
I have a VB function which calls a stored procedure to get 2 kinds of reports (actives users/inactive users). The stored procedure returns the data (columns) based on the report we choose. If we choose to get active users report, the sproc doesn't return an Inactive_Date for the users, but it will return the same field, Inactive_Date field for Inactive users report. I'm getting an error when I choose to get active users report, because the sproc doesn't return Inactive_Date field, but my VB.NET code is same for both active/inactive users reports. Here are some of the ways I tried to resolve, but no luck.
If IsDBNull(dr("Inactive_Date")) Then
Result.Inactive_Date = Nothing
Else
Result.Inactive_Date = SafeStr(dr("Inactive_Date"))
End If
and
If IsDBNull(dr("Inactive_Date")) Then
Result.Inactive_Date = DateTime.Now
Else
Result.Inactive_Date = SafeStr(dr("Inactive_Date"))
End If
You're getting the exception because you're basically trying to access a dictionary entry that doesn't exist. You have a few options.
Have your stored procedure for Active Users return Inactive_Date as null. This would allow you to use code you have posted in VB with no changes.
Create a function that checks if the datareader has that column before you attempt to access it, as in this answer: Check for column name in a SqlDataReader object - this would be akin to checking if the dictionary has the key first
Write two separate functions in your VB code - one for the active report and one for the inactive report. Or, add a parameter to your function to check if this is a request for an active user, and only try to access the "Inactive_Date" field if that parameter is set to true.
If it were up to me, I'd update the stored procedure (option 1). That would probably be the least amount of work, shouldn't hurt anything semantically (unless you have queries that SELECT * from the results of that procedure), and requires no other changes to your codebase. The only other problem I can see is confusion that might arise from having a function in your VB code that's used for both active and inactive users.
The second option will involve iterating through all the fields, and that just feels wrong to me (seems like it's asking for performance issues if used incorrectly). It's the least invasive though if you can't change the stored proc.
The third option probably creates more problems elsewhere in your code base. That said, you probably shouldn't have one function do two very different things - I'd avoid the parameterized version if you end up going down this route, and go for two separate functions.
From your code and the fact that your variable is named dr, I am going to assume that you are using a DataReader.
The DataReader class exposes the column names as indexed values.
Dim columnNames = Enumerable.Range(0, dr.FieldCount).Select(dr.GetName).ToList()
Will call the method dr.GetName(index) for all columns, returning a list of column names you can check using columnNames.Contains("yourColumnName")
There is also dr.GetOrdinal, but that will throw an exception if the column doesn't exist.
Using EF6 Framework4.5 – Creating my first n-tier app and first EF experience. I have CRUD working but one issue that I have a work-a-around but don’t like it. There must be a better way.
When data object is returned from my UI layer to the DAL layer, it has been detached, so I flag EntityState as “Modified.” But then it updates all columns in the db. Values that were not loaded in the form view (and not submitted) obviously are null and updated to such in the db.
1) My first solution does work:
Store the object in session in the UI layer and loop through the object updating edited values when the form is submitted. Thus, original values are passed back unchanged and updated to original values. I don’t think this would be best practice though.
2) The solution I think I want:
I am looking for a helper function in the DAL layer to loop through all values in the returned object and flag only non-null values as “IsModified” before calling SaveChanges.
I have found examples in C# on how to check for changed value but not null. (I am still a vb guy anyway. Don't hate.)
A) Is solution #2 a good way to do this?
B) Has anyone a piece of good to help me?
Thank you.
BTW, this is my best stab at it so far: (Errors on “CurrentValues”)
Public Overridable Function MarkEntriesModified(entity As Object)
Dim dbEntityEntry = DbContext.Entry(entity)
'Ensure only non-null values are inserted
For Each [property] In dbEntityEntry.CurrentValues.PropertyNames
If Not IsDBNull(dbEntityEntry.CurrentValues.GetValue(Of Object)([property])) Then
dbEntityEntry.[Property]([property]).IsModified = True
End If
Next
Return entity
Try this architecture. So if you are using EF then I suppose you have edmx updated and correctly representing your database objects.
eg: Say you wan to update Customer data in customer table
Create a Customer class.
when you extract a particular customer, get an instance of the
customer created.
pass this instance to the UI
and pass the instance back to Business layer to save
this way you don't loose anything in between.
some sample code
Mine is an asp.net vb application. I need a dictionary of around 100 keys and values. That dictionary I'd like to initialize when page loads. But I've to use those values and keys in that dictionary in various button events on that page. So how can I achieve that with a 1 time initialization of that values to the dictionary when page loads, since that values in that dictionary clears out normally in every server requests .
Keep the dictionary in session/viewstate after it initialized with keys and values. Typecast the session/viewstate object to dictionary on every server requests.
I'm upgrading my application to use stored procedures rather than dynamic SQL as it is now. What I'd like to do is call some procedure, for example setUser(id), and then for that ID to be carried forward for the duration of the current connection. I have a UserVariables table which stores important data related to the current user (I'm not using the session to store this data as the session only lasts for so long; this way the users data is persisted across logins). I want to select data, such as the ID of the client they're currently viewing, without having to pass the user ID into each stored procedure. Call it laziness, if you like!
I've searched for this quite a bit, and looked at various articles, but they're all about either global variables (which we can't change) or something unrelated.
Basically what I want to do is set the user ID at the beginning of the page load (may even move this into the session_start method at some point) and then access this variable during all subsequent stored procedure calls or queries.
Edit: What I'm after is like when you set a variable at the beginning of an asp page (my application is written in good ol' classic asp) and you then use it throughout the page and any includes. Think of the asp page representing the connection and the includes representing the stored procedures, if you like.
I have found a suitable alternative to setting connection-specific variables. I have a function which takes the sproc name, an array of parameter names, an array of parameter values and a variable to return (i.e. a byref variable). I have modified this function so that, when the parameters are refreshed, it checks for a userid parameter and sets it automatically if it exists. It then returns the 'retval' parameter if it exists, otherwise sets the return variable to myCmd.execute.
From the Transactions doc, second paragraph:
The intention here is for the client to increment the total number of
chat messages sent (ignore for a moment that there are better ways of
implementing this).
What are some standard "better ways" of implementing this?
Specifically, I'm looking at trying to do things like retrieve the most recent 50 records. This requires that I start from the end of the list, so I need a way to determine what the last record is.
The options as I see them:
use a transaction to update a counter each time a record is added, use the counter value with setPriority() for ordering
forEach() the parent and read all records, do my own sorting/filtering at client
write server code to analyze Firebase tables and create indexed lists like "mostRecent Messages" and "totalNumberOfMessages"
Am I missing obvious choices?
To view the last 50 records in a list, simply call "limit()" as shown:
var data = new Firebase(...);
data.limit(50).on(...);
Firebase elements are ordering first by priority, and if priorities match (or none is set), lexigraphically by name. The push() command automatically creates elements that are ordered chronologically, so if you're using push(), then no additional work is needed to use limit().
To count the elements in a list, I would suggest adding a "value" callback and then iterating through the snapshot (or doing the transaction approach we mention). The note in the documentation actually refers to some upcoming features we haven't released yet which will allow you to count elements without loading them first.