ASP.Net Cart - Duplicate Session IDs - asp.net

Can anyone tell me what is happenning here? I am getting duplicated session ID's across 2 seperate machines, 2 different browsers in a shopping cart website?
I've gone so far as generating a new session id with a 300 character random string, and still they get duplicated
This is the new code... just take out the SyncLock stuff for the old code:
Dim _key As String = String.Empty
SyncLock _locker
_key = Guid.NewGuid().ToString()
Session("Identifier") = Validations.GeneratePassword(150, 300)
Session("SessionID") = _key
Session("SiteID") = "F2630237-E355-4C8A-947E-BBAC97ECA550"
Session("HomePage") = 13
End SyncLock
yes I know Session("SessionID") is not the session ID, however, we used to use Session.SessionID for the "Identifier", and it was getting duplicated

Why would you generate your own SessionID?
ASP.NET and the browser do this out of the box and probably better that you or I.
I recommend you use this instead:
HttpSessionState.SessionID

I am rather doing a different approach
I created a table with identity, every time when needed a session id , an insertion is made and stored in session variable
I think random generators cannot be trusted

I found the solution to this.
if i set the session manager in web.config to be my class, and it worked
<sessionState mode="InProc" cookieless="false" timeout="20" sessionIDManagerType="o7th.Projects.Core.SessionManager"/>

Related

ASP.NET modify connectionstring at runtime

I need to change dataset connectionstrings to point to different DBs at run time.
I've looked at a number of solutions however they all seem to be related to WinForms or web application projects or other technology slightly different than what I'm using, so I haven't figured out how apply them.
The application is like a discussion. It's a web site project based on code originally written under VS2005, and there's no budget (or personal talent!) for major changes at this time. The app is written in vb.net; I can understand answers in c#. I'm working in VS2013.
The app has three typed datasets pointing to one MDF, call it "MainDB.mdf". There are dozens of tableadapters among the three datasets.
I'm going to deploy the app it as an "alpha/demo" version. I would like to use the same code base for all users, and a separate physical version of MainDB for each user, to reduce chances that the users crash each other.
The initial demo access URL will contain query string information that I can use to connect the user with the right physical database file. I should be able to identify the database name and thus the connection string parameters from the query string information (probably using replace on a generic connection string). If necessary I could use appsettings to store fully formed connection strings, however, I would like to avoid that.
I would like to be able to change the connection strings for all the datasets at the time that the entry point pages for the app are accessed.
Changing the tableadapter connection strings at each instantiation of the tableapters would require too much code change (at least a couple of hundred instantiations); I'd just make complete separate sites instead of doing that. That's the fall back position if I can't dynamically change the connectionstrings at runtime (or learn some other way to make this general scheme work).
Any suggestions on how to approach this would be appreciated.
Thanks!
UPDATE: Per comments, here is a sample instantiation of tableadapter
Public Shared Sub ClearOperCntrlIfHasThisStaff( _
varSesnID As Integer, varWrkprID As Integer)
Dim TA As GSD_DataSetTableAdapters.OPER_CNTRLTableAdapter
Dim DR As GSD_DataSet.OPER_CNTRLRow
DR = DB.GetOperCntrlRowBySesnID(varSesnID)
If IsNothing(DR) Then
Exit Sub
End If
If DR.AField = varWrkprID Then
DR.AField = -1
TA.Update(DR)
DR.AcceptChanges()
End If
End Sub
UPDATE: Below is the test code I tried in a test site to modify the connectionString in a single instantiation of a tableadapter. It feeds a simple gridview. I tried calling this from Page_Load, Page_PreLoad, ObjectDataSource_Init, and Gridview_Databind. At the concluding response.writes, the wrkNewConnString looks changed to TestDB2, and the TA.Connection.ConnectionString value looks changed to TestDB2, but the displayed gridview data is still from TestDB1. Maybe it needs to be called from somewhere else?
Sub ChangeTableAdapter()
Dim wrkNewConnStr As String = ""
Dim wrkSel As Integer
wrkSel = 2
wrkNewConnStr = wrkNewConnStr & "Data Source=.\SQLEXPRESS;"
wrkNewConnStr = wrkNewConnStr & "AttachDbFilename=D:\9000_TestSite\App_Data\TESTDB1.MDF;Integrated Security=True;User Instance=True"
Select Case wrkSel
Case 1
wrkNewConnStr = wrkNewConnStr.Replace("TESTDB1", "TESTDB1")
Case 2
wrkNewConnStr = wrkNewConnStr.Replace("TESTDB1", "TESTDB2")
Case 3
wrkNewConnStr = "Data Source=localhost; Initial Catalog=test01;"
wrkNewConnStr = wrkNewConnStr & " User ID=testuser1; Password=testuserpw1"
End Select
Try
Dim TA As New DataSetTableAdapters.NamesTableAdapter
TA.Connection.ConnectionString = wrkNewConnStr
Response.Write("1 - " & wrkNewConnStr)
Response.Write("<br/>")
Response.Write("2 - " & TA.Connection.ConnectionString)
Catch ex As Exception
Dim exmsg As String = ex.Message
Response.Write(exmsg)
End Try
End Sub
The connection string:
<add name="TestDB1ConnectionString"
connectionString="Data Source=.\SQLEXPRESS;
AttachDbFilename=D:\9000_TestSite\App_Data\TESTDB1.MDF;Integrated Security=True;User Instance=True"
providerName="System.Data.SqlClient" />
UPDATE: the following post has lots of solutions, however, they seem to focus on web application projects, that have a project file with settings, which this web site project does not.
link with possible solutions
UPDATE: this next link was brought to my attention, and in working on it I did get it to work, however, it still relies either on having a web application project (with project file) or modifying each table adapter as they are instantiated. So, while I'm not going to implement it, I believe that is the technical answer.
modifying connection strings
sorry if this answer is too late, but I have exactly the same problem and eventually came up with a solution using Reflection.
My solution was to "save" a new default value for the connection string in the settings at run time, which means any further use of the table adapter uses the the new connection string.
It should be noted the term "save" is misleading as the new value is lost when the application closes.
Have tested and worked perfectly.
public void ChangeDefaultSetting(string name, string value)
{
if (name == null)
throw new ArgumentNullException("name");
if (value == null)
throw new ArgumentNullException("value");
Assembly a = typeof({Put the name of a class in the same assembly as your settings class here}).Assembly;
Type t = a.GetType("{Put the full name of your settings class here}");
PropertyInfo propertyInfo = t.GetProperty("Default");
System.Configuration.ApplicationSettingsBase def = propertyInfo.GetValue(null) as System.Configuration.ApplicationSettingsBase;
//change the "defalt" value and save it to memory
def[name] = value;
def.Save();
}

How to use caching?

Basically, I retrieved a dataset and I want to cache it in the server memory for one month. So I don't need to call the query again and again when running the page within this month.
I did some research and think http://msdn.microsoft.com/en-us/library/system.web.caching.cacheitemremovedcallback%28v=vs.110%29.aspx is the way to do the cache, basically i modified the sub codes to fit into my application
Public Sub RemovedCallback(k As String, v As Object, r As CacheItemRemovedReason)
itemRemoved = True
reason = r
End Sub
Function AddItemToCache(cacheKey as String, ds as Dataset)
itemRemoved = False
onRemove = New CacheItemRemovedCallback(AddressOf Me.RemovedCallback)
If (IsNothing(Cache(cacheKey))) Then
Cache.Add(cacheKey, ds, Nothing, DateTime.Now.AddMonths(1), TimeSpan.Zero, CacheItemPriority.High, onRemove)
End If
End Function
There are quite a few errors in this piece of code. One of the error is for Cache(cacheKey) says that " Cache is a type and cannot be used for expression"? where did i do wrong?
Sounds like you're using IIS cache. First of all, if this is your route - if you have an assemblies that may use cache (when available), you need to create Caching assembly in which you check for HTTPcontext. If it is null - you are running outside of IIS and caching will not be available.
A good alternative is to download Enterprise Library Caching blocks if you working with framework up to 3.5. If you use FW4.0+ you use system.runtime.caching. This way cache will be available always. There is also AppFaric and some third party cache implementations but this is probably outside the scope for you.
For your error, it sounds like your identifier Cache [your code is not showing how you assign it] is actually a type. That is if you did this
If Integer Is Nothing....
What you need is to use is syntax
System.Web.Caching.Cache.Add...
Now, this is instance. So, what you can do is
Dim c as Cache = System.Web.Caching.Cache
c.Add(....

asp.net vb2010 How to log Windows Authentication events - i.e. save user name and login time

Just now getting into the asp.net environment with VB 2010. I have designed an intranet page that we will be using to auction off old equipment to employees. I've had some very good luck getting the whole thing working, but I have hit a snag on one minor issue: I would like to keep a database table of user logins and times.
Several methods have presented themselves, but so far none of them have been adequate. The main problem seems to be that regardless of the event I use to record the login, they fire multiple times resulting in as many as 4 or 5 entries in the login database for the same login event, not to mention additional times when something on the page changes for whatever reason.
The system uses Windows Authentication, so the user must login with his/her company credentials.
I can't remember what all I have tried, but the first thing I tried was the Page_Load event because it seemed obvious. I've learned that because the page updates the display every ten seconds, Page_Load event fires numerous times throughout the session.
Fighting my way through other ideas, all of which failed, I came to the WindowsAuthentication_OnAuthenticate event in the Global_asax class, shown below:
Imports System.Web.SessionState
Imports System.Data.SqlClient
Imports System.Web
Imports System.Web.UI.WebControls
--------------------------------------------
Public Sub WindowsAuthentication_OnAuthenticate(ByVal sender As Object, ByVal args As WindowsAuthenticationEventArgs)
Dim strLoginName = args.Identity.Name
Dim sqlCommandString As String = "INSERT into tblLogin (UserLogin,DateTime) VALUES ('" & _
strLoginName & "','" & _
Format(Now, "MMM dd, yyyy hh:mm:ss") & "');"
Dim sqlConn As New SqlConnection(strConnectionString)
Dim sqlCommand As SqlCommand = New SqlCommand(sqlCommandString, sqlConn)
sqlCommand.Connection.Open()
sqlCommand.ExecuteNonQuery()
sqlCommand.Connection.Close()
End Sub
which also seems to fire multiple times. I then tried to work a way where setting a Boolean value to TRUE upon authentication so that the data would be written to the database only once:
Public Sub WindowsAuthentication_OnAuthenticate(ByVal sender As Object, ByVal args As WindowsAuthenticationEventArgs)
If Not boolUserIsLoggedIn Then
boolUserIsLoggedIn = True
Dim strLoginName = args.Identity.Name
Dim sqlCommandString As String = "INSERT into tblLogin (UserLogin,DateTime) VALUES ('" & _
strLoginName & "','" & _
Format(Now, "MMM dd, yyyy hh:mm:ss") & "');"
Dim sqlConn As New SqlConnection(strConnectionString)
Dim sqlCommand As SqlCommand = New SqlCommand(sqlCommandString, sqlConn)
sqlCommand.Connection.Open()
sqlCommand.ExecuteNonQuery()
sqlCommand.Connection.Close()
End If
End Sub
and subsequent authentication iterations would skip the database write code; but then I needed to find a way to clear the Boolean value when the user logged off or closed the session. I couldn't figure out how to trap a "Logged Off" event, and the Session_End and Application_End events didn't work as I had hoped.
I feel like this is getting too convoluted to make sense. To put it simply, I just need a way to record a user's login name and date only once per session. Can anyone help?
[Edit: Although this is not really an essential element of the page, it has become a crusade for me to get it to work if not for any other reason than to understand the process.]
Researching more about JDB's suggestion using the session ID property, I discovered another property that seems to be doing exactly what I need: The IsNewSession property.
With that in mind, I have this code in my default.aspx's Page_Load event:
If Context.Session.IsNewSession Then
Login()
End If
Which calls the Login sub that writes the login information to the database:
Protected Sub Login()
Dim strConnectionString As String = "Data Source = toponet\sqlexpress; initial catalog = TopoAuction; Integrated security = True"
Dim strLoginName = System.Web.HttpContext.Current.User.Identity.Name
Dim sqlCommandString As String = "INSERT into tblLogin (UserLogin,DateTime) VALUES ('" & _
strLoginName & "','" & _
Format(Now, "MMM dd, yyyy hh:mm:ss") & "');"
Dim sqlConn As New SqlConnection(strConnectionString)
Dim sqlCommand As SqlCommand = New SqlCommand(sqlCommandString, sqlConn)
sqlCommand.Connection.Open()
sqlCommand.ExecuteNonQuery()
sqlCommand.Connection.Close()
End Sub
So far, testing has shown that it fires only once per session. Even if the browser moves to another site and comes back, it will not count that as a new session. This seems to be the perfect solution.
I'm open to hear any comments or concerns about this, anybody?
I think, perhaps, you are getting hung up on the request/response cycle of a web page. If you have only ever used WebForms and come from a desktop development background, the statelessness of the HTTP protocol can be very confusing.
Essentially, the client (the browser) requests information from the server (where your .NET code is running). Each request is completely independent from every other request - the server maintains no memory of prior requests.
Now, WebForms was an attempt to bridge the gap by shoe-horning on a sort of pseduo-statefullness on top of HTTP. This is where ViewState and other similar concepts come in. Basically, WebForms includes additional information about the state of the web application in each Response, which is then included again in following Requests, maintaining the application's state and giving the appearance of statefulness. There are other tricks too, like server variables, which can be used to maintain some "memory" of past transactions.
However, this statefulness is easily broken. For example, if you include a basic anchor tag (not an ASP.NET server control), and you redirect to another page (or even the same page) without including the view state, then you will lose some of your application state. Even if you are using server controls and maintaining your view state, you must pay careful attention to the WebForms Page lifecycle. If you are handling the wrong event (such as Page_Load) or attempting to access a property at the wrong time (before the web page has had a chance to reload it's state), you may not get the results you are expecting.
In this scenario, I recommend you check the user's Session ID. It changes very infrequently. If you have a user ID coming in with a session ID you've not seen before (or that's not been associated with that user in some amount of time - say 30 minutes), then you probably have a unique logon event. If you have seen that user ID/Session ID combo, then that user has probably already "logged in" and you don't need to record it again.
Alternatively, just store the user's login state in a session variable. You can check that variable on each Page_Load and branch (using an If statement) based on your needs.

Dynamic connString (now stored in session, bad)

I working on a project where the connString is stored in a session variable. The problem is that the session runs out when the user is not around for a while (makes sense), thereby making the user having to log in again to create a new connection.
The user selects his database from a list of ODBC connection configured on the web server, therefore the different connStrings the user can chose from cannot be stored in the web.config as the user can add new ones as they wish.
I was wondering how to fix this problem. Should I just tell the user not to leave his computer for 20mins+ or can I perhaps store the connString someplace else? Ive seen websites making a pop-up saying "your session will expire in 5 mins, press ok to continue using the site", or something like that.
Furthermore it is not a possbility to make a static varible as the website is shared between many users, so if user1 choses "connString1" and user2 choses "connString2" afterwards, then user1 will unfortunatly be running on "connString2" aswell.
Hope you can help :)
**
Can this be a solution?:
I create a "BasePage" which my pages inherit from. In this basepage i create a hiddenfield and add the connString to the value property on load. Furthermore I will encrypt the connString so the user cannot see the value in the source code.
Then, if the session has a timeout, i will restore the session by using the value in the hiddenfield and the site will not crash.
Can you store the user's connection string preference in their Profile and then persist their profile? http://odetocode.com/articles/440.aspx
You should also be able to do this for anonymous users.
As an aside, I don't know how secure the Profile APIs are, they should be fine, but just in case, you might want to store an Enum value and then map that to a Connection string in your code.
You could use the app.config to get and set config files. Take a look at this to see implementation of storing files. Its just as easy to get settings.
ConfigurationManager doesn't save settings
//Edit: If you don't want the user to be able to see your connectionstring name then you can provice an another in hidden_html or cookie or session cookie. In this example I use a cookie. THis should solve your problem.
To set cookie:
HttpCookie myCookie = new HttpCookie("UserSettings");
myCookie["ConnectionString"] = "MyCOnnectionValue";
myCookie.Expires = DateTime.Now.AddDays(1d);//For one day.
Response.Cookies.Add(myCookie);//Will store the cookie within the users browser so your code can read from it at every request.
then:
if (Request.Cookies["UserSettings"] != null)
{
string userSettings;
if (Request.Cookies["UserSettings"]["ConString"] != null)
{ userSettings = Request.Cookies["UserSettings"]["ConString"]; }
}
string connectionStringNameToUse;
if(userSettings =="Connection1"){
connectionStringNameToUse = "here you can have your name of connectionsstring";
}etc with ypur other connectionsstrings here.
//Then use your connectionsstring here:
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings[connectionStringNameToUse ].ToString()))
{
cn.Open();
using (SqlCommand command = new SqlCommand
("delete TBL from RatingListObjects TBL where ( TBL.TradeObject1Id = #MY_ID ) or ( TBL.TradeObject2Id = #My_ID ) ", cn))
{
command.Parameters.Add(new SqlParameter("#MY_ID", customerToRemove.TradeObjectId));
command.ExecuteNonQuery();
}
}
On the other hand. I would go for saving the users database of choice in with the other user data in the db. But this is doable if you only want the user to have a chosen connectionsstring a certain time, set by the program. It wont allow them to see the connections string name. Hopes this helps, good luck!

custom authorization and page protection in asp.net

need to solve a custom authorization issue.
I already have four tables in my database named:
1. Usermaster
2.Roles
3.RoleMenu
4.Menu
I have implemented this and its working perfectly.
My only issue now is that an authenticated user can view an unauthorized page by simply entering the page url in the browser.
Any useful ideas apart from forms authentication and folder level access?
I had a project similar to this and i can't seem to find the code anywhere as it was quite awhile ago. I remember the premise though. What i did was i set up a key in the webconfig that had usernames allowed access in a pipedelimited string. Behind the code i would pull in that key as well as the user trying to access the page. I would then search the string and try and match the user. If a match was found the page would load, if a match wasn't found it would redirect them to a page telling them they didn't have access and who to contact to request access. I'll look for the code and edit if i find it.
EDIT
WebConfig
<appSettings>
<add key="Users" value="user1|user2|user3|..." />
</appSettings>
This piece goes above the
For the .aspx.vb page
Dim DomainUserName() As String = Request.ServerVariables("LOGON_USER").Split("\")
Dim UserName As String = DomainUserName(1)
Dim Users() As String = ConfigurationManager.AppSettings("Users").ToString.Split("|")
Dim isAllowedAccess As Boolean = False
For i As Integer = 0 To Users.Count - 1
If UserName = Users(i) Then
isAllowedAccess = True
Exit For
End If
Next
If isAllowedAccess = False Then
Response.Redirect("Default.aspx")
End If
Essentially our logins are domain\username so what i'm doing is extracting just the name using a split. I'm then populating the accepted users into an array splitting on the pipe and looping through them searching for a match. when the match is found it allows them access, if a match isn't found they are redirected back to the home page.

Resources