Reputation: 153
I wrote simple function that generates a session variable on login and stores it in the Session table in a sql database. It works perfectly 99% of the time, however occasionally, it seems that the session table fills up or something, because the login page will redirect to the home page as if properly logged in, however no session will have been created and no user data will be present on any page in the web app.
Accessing the Session table directly through Sql Server Mgmt Studio and manually deleting all existing sessions under that username seems to correct the issue in the short-term, however I would like to know what causes the issue, and how I can alter my code to prevent it in the future.
any constructive pointers on how to improve my approach are also welcome
Thanks!
Here is my c#:
protected void CreateSession(object sender, EventArgs e)
{
//generate SessionId
var AvailableCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyx1234567890";
var random = new Random();
var SessionId = new string(Enumerable.Repeat(AvailableCharacters, 20).Select(s => s[random.Next(s.Length)]).ToArray());
String UserIdOut = null;
Session["New"] = SessionId.ToString();
string connstring = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connstring))
{
//retreive user id
try
{
SqlCommand cmd = new SqlCommand("spInsertSessionId", conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("@username", SqlDbType.VarChar).Value = tb_username.Text;
cmd.Parameters.Add("@createdate", SqlDbType.VarChar).Value = DateTime.Now.ToString();
cmd.Parameters.Add("@SessionId", SqlDbType.VarChar).Value = SessionId.ToString();
conn.Open();
cmd.ExecuteNonQuery();
}
catch(Exception ex)
{
message = "error inserting session: " + ex.Message;
ClientScript.RegisterStartupScript(this.GetType(), "Popup", "ShowPopup('" + message + ex.Message + "');", true);
}
}
}
Here is the stored procedure that inserts the session ID:
CREATE PROCEDURE [dbo].[spInsertSessionId]
@username VARCHAR(200) = NULL ,
@UserId VARCHAR(200) = NULL ,
@createdate VARCHAR(200) = NULL ,
@SessionId VARCHAR(200) = NULL
AS
BEGIN
SELECT
@UserId = user_id
FROM dbo.users
WHERE
username = @username
INSERT INTO dbo.session
(
UserId ,
CreateDate ,
SessionId
)
VALUES
(
@userid ,
@createdate ,
@SessionId
)
DELETE FROM dbo.session
WHERE UserId = @UserId
AND SessionId NOT IN
(
SELECT TOP(5) SessionId FROM dbo.session
WHERE UserId = @UserId
ORDER BY CreateDate DESC
)
END
Upvotes: 1
Views: 118
Reputation: 168
try configuring your application to use <sessionState mode=SQLServer>
and use aspnet_regsql.exe to configure your database tables, then use Session["key"] collection to store you data. Then the application will manage sessions itself. And if you aren't ok with that, you can always write your custom session provider.
Upvotes: 1
Reputation: 101533
Given provided info, my wild guess is that problem is in spInsertSessionId procedure. After inserting session, you delete "old" sessions, leaving only top 5 ordered by CreateDate DESC. However, you use varchar for CreateDate column, and strings are not guaranteed to be ordered the same way as dates, if you are not using datetime formats which have this property. In your case you just do DateTime.Now.ToString(), which even depends on your culture. So in some cases, session you just inserted might not be in top 5 ordered by your criteria, and hence deleted right after creation. Even if that is not the case - don't use varchar to store dates.
Sample:
declare @d1 varchar(max) = '10/21/2016 00:00:00';
declare @d2 varchar(max) = '10/22/2015 00:00:00';
select (case when @d1 > @d2 then 1 else 0 end)
Here d1 is obviously later than d2, but query returns "0". Those dates are from DateTime.ToString() with invariant culture.
Upvotes: 2