I have a project in Asp.Net MVC 5 with C# and use a custom session state customizing SessionStateStoreProviderBase class in Oracle, like this example. My problem is that when the session expires the screen goes blank page and only when the user presses the F5 is the second time that the login screen is loaded. Only after pressing twice the f5, it works.
Has anyone ever experienced error this?
Update
This is the class that use
public class ProvedorSessao : SessionStateStoreProviderBase
{
private SessionStateSection _pConfig;
private string _connectionString;
private ConnectionStringSettings _pConnectionStringSettings;
private const string EventSource = "AgpSessionDataProvider";
private const string EventLog = "Application";
private const string ExceptionMessage = "SessionCustom - Ocorreu um erro interno na sessão.";
private const int Timeout = 1; //One minute in test app default is 60
private bool _pWriteExceptionsToEventLog;
private bool WriteExceptionsToEventLog => _pWriteExceptionsToEventLog;
private string ApplicationName { get; set; }
public override void Initialize(string name, NameValueCollection config)
{
try
{
if (name.Length == 0)
name = "PortalCustomSessionProvider";
if (String.IsNullOrEmpty(config["description"]))
{
config.Remove("description");
config.Add("description", "Session State Store provider");
}
base.Initialize(name, config);
ApplicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;
Configuration cfg = WebConfigurationManager.OpenWebConfiguration(ApplicationName);
_pConfig = (SessionStateSection)cfg.GetSection("system.web/sessionState");
_pConnectionStringSettings = ConfigurationManager.ConnectionStrings[config["connectionStringName"]];
if (_pConnectionStringSettings == null || _pConnectionStringSettings.ConnectionString.Trim() == "")
{
throw new ProviderException("A string de conexão não pode ser vazia.");
}
_connectionString = "MyStringConection"; //My String Conection oracle
_pWriteExceptionsToEventLog = true;
if (config["writeExceptionsToEventLog"] != null)
{
if (config["writeExceptionsToEventLog"].ToUpper() == "TRUE")
_pWriteExceptionsToEventLog = true;
}
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "Initialize");
throw new ProviderException(ExceptionMessage);
}
throw new Exception(e.Message);
}
}
public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
{
//Serializar o SessionStateItemCollection como uma string.
var sessItems = Serialize((SessionStateItemCollection)item.Items);
var conn = new OracleConnection(_connectionString);
OracleCommand cmd;
OracleCommand deleteCmd = null;
if (newItem)
{
deleteCmd = new OracleCommand("DELETE FROM Sessions WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName AND Expires < :Expires", conn);
deleteCmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
deleteCmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
deleteCmd.Parameters.Add("Expires", OracleDbType.Date).Value = DateTime.Now;
// Insere um novo item na sessão.
cmd = new OracleCommand("INSERT INTO Sessions " +
"(SessionId, ApplicationName, Created, Expires, " +
"LockDate, LockId, Timeout, Locked, SessionItems, Flags, UsuarioId, Menuid) " +
"Values(:SessionId, :ApplicationName, :Created, :Expires, :LockDate, :LockId, :Timeout, :Locked, :SessionItems, :Flags, :UsuarioId, :Menuid)", conn);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.Parameters.Add("Created", OracleDbType.Date).Value = DateTime.Now;
cmd.Parameters.Add("Expires", OracleDbType.Date).Value = DateTime.Now.AddMinutes(item.Timeout);
cmd.Parameters.Add("LockDate", OracleDbType.Date).Value = DateTime.Now;
cmd.Parameters.Add("LockId", OracleDbType.Int32).Value = 0;
cmd.Parameters.Add("Timeout", OracleDbType.Int32).Value = item.Timeout;
cmd.Parameters.Add("Locked", OracleDbType.Int32).Value = Convert.ToInt32(false);
cmd.Parameters.Add("SessionItems", OracleDbType.Varchar2, sessItems.Length).Value = sessItems;
cmd.Parameters.Add("Flags", OracleDbType.Int32).Value = 0;
cmd.Parameters.Add("UsuarioId", OracleDbType.Varchar2, 50).Value = "";
cmd.Parameters.Add("Menuid", OracleDbType.Varchar2, 50).Value = "";
}
else
{
var usuarioid = "";
var menuid = "";
if (item.Items != null)
{
usuarioid = string.IsNullOrEmpty(item.Items["codUsuario"] + "")
? ""
: item.Items["codUsuario"].ToString();
menuid = string.IsNullOrEmpty(item.Items["codMenu"] + "")
? ""
: item.Items["codMenu"].ToString();
}
cmd = new OracleCommand("UPDATE Sessions SET Expires = :Expires, SessionItems = :SessionItems, Locked = :Locked, usuarioid = :usuarioid, menuid = :menuid " +
" WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName AND LockId = :LockId", conn);
cmd.Parameters.Add("Expires", OracleDbType.Date).Value = DateTime.Now.AddMinutes(item.Timeout);
cmd.Parameters.Add("SessionItems", OracleDbType.Varchar2, sessItems.Length).Value = sessItems;
cmd.Parameters.Add("Locked", OracleDbType.Int32).Value = Convert.ToInt32(false);
cmd.Parameters.Add("usuarioid", OracleDbType.Varchar2, 50).Value = usuarioid;
cmd.Parameters.Add("menuid", OracleDbType.Varchar2, 50).Value = menuid;
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.Parameters.Add("LockId", OracleDbType.Int32).Value = lockId;
}
try
{
conn.Open();
deleteCmd?.ExecuteNonQuery();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "SetAndReleaseItemExclusive");
throw new ProviderException(ExceptionMessage);
}
else
{
throw new Exception(e.Message);
}
}
finally
{
conn.Close();
}
}
public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
{
return GetSessionStoreItem(false, context, id, out locked, out lockAge, out lockId, out actionFlags);
}
public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
{
return GetSessionStoreItem(true, context, id, out locked, out lockAge, out lockId, out actionFlags);
}
private SessionStateStoreData GetSessionStoreItem(bool lockRecord, HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
{
//Valores iniciais de retorno e parâmetros de saída.
SessionStateStoreData item = null;
lockAge = TimeSpan.Zero;
lockId = null;
locked = false;
actionFlags = 0;
var conn = new OracleConnection(_connectionString); //Conexão com o banco
OracleDataReader reader = null;
var serializedItems = ""; //Variável para armazenar serialização SessionStateItemCollection.
var foundRecord = false; //True se um registro for encontrado na base de dados.
var deleteData = false; //True se o item de sessão retornou expirou e precisa ser eliminado.
var timeout = 0; //Valor do tempo limite de armazenamento de dados.
try
{
conn.Open();
// LockRecord se for True é chamado de GetItemExclusive e
// falso se for chamado de GetItem.
// Obtem um bloqueio, se possível. Ignorar o Registro se elemento expirou.
OracleCommand cmd;
if (lockRecord)
{
cmd = new OracleCommand(
"UPDATE Sessions SET" +
" Locked = :Locked1, LockDate = :LockDate " +
" WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName AND Locked = :Locked2 AND Expires > :Expires", conn);
cmd.Parameters.Add("Locked1", OracleDbType.Int32).Value = Convert.ToInt32(true);
cmd.Parameters.Add("LockDate", OracleDbType.Date).Value = DateTime.Now;
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.Parameters.Add("Locked2", OracleDbType.Int32).Value = Convert.ToInt32(false);
cmd.Parameters.Add("Expires", OracleDbType.Date).Value = DateTime.Now;
locked = cmd.ExecuteNonQuery() == 0;
}
cmd = new OracleCommand(
"SELECT Expires, SessionItems, LockId, LockDate, Flags, Timeout, Locked, usuarioid, menuid " +
"FROM Sessions " +
"WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName", conn);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
reader = cmd.ExecuteReader(CommandBehavior.SingleRow);
while (reader.Read())
{
DateTime expires = reader.GetDateTime(0);
if (expires < DateTime.Now)
{
locked = false; //O registro foi expirado. Marca como não locked.
deleteData = true; //O registro foi deletado. Marca como deletado.
}
else
foundRecord = true;
serializedItems = reader.IsDBNull(1) ? "" : reader.GetString(1);
lockId = reader.IsDBNull(2) ? 0 : Convert.ToInt32(reader[2]);
lockAge = DateTime.Now.Subtract(reader.GetDateTime(3));
actionFlags = (SessionStateActions)(reader.IsDBNull(4) ? 0 : Convert.ToInt32(reader[4]));
timeout = reader.IsDBNull(5) ? 60 : Convert.ToInt32(reader[5]);
if (!lockRecord)
locked = reader.GetBoolean(7);
}
reader.Close();
if (deleteData)
{
cmd = new OracleCommand("DELETE FROM Sessions " +
"WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName", conn);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.ExecuteNonQuery();
}
if (!foundRecord)
locked = false;
if (foundRecord && !locked)
{
lockId = (int)lockId + 1;
cmd = new OracleCommand("UPDATE Sessions SET " +
"LockId = :LockId, Flags = 0 " +
"WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName", conn);
cmd.Parameters.Add("LockId", OracleDbType.Int32).Value = lockId;
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.ExecuteNonQuery();
switch (actionFlags)
{
case SessionStateActions.InitializeItem:
item = CreateNewStoreData(context, (int)_pConfig.Timeout.TotalMinutes);
break;
default:
item = Deserialize(context, serializedItems, timeout);
break;
}
}
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "GetSessionStoreItem");
throw new ProviderException(ExceptionMessage);
}
else
{
throw new Exception(e.Message);
}
}
finally
{
reader?.Close();
conn.Close();
}
return item;
}
private string Serialize(SessionStateItemCollection items)
{
var ms = new MemoryStream();
var writer = new BinaryWriter(ms);
items?.Serialize(writer);
writer.Close();
return Convert.ToBase64String(ms.ToArray());
}
private SessionStateStoreData Deserialize(HttpContext context, string serializedItems, int timeout)
{
var ms = new MemoryStream(Convert.FromBase64String(serializedItems));
var sessionItems = new SessionStateItemCollection();
if (ms.Length > 0)
{
var reader = new BinaryReader(ms);
sessionItems = SessionStateItemCollection.Deserialize(reader);
}
return new SessionStateStoreData(sessionItems, SessionStateUtility.GetSessionStaticObjects(context), timeout);
}
public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
{
var conn = new OracleConnection(_connectionString);
var cmd = new OracleCommand("UPDATE Sessions SET Locked = 0, Expires = :Expires " +
"WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName AND LockId = :LockId", conn);
cmd.Parameters.Add("Expires", OracleDbType.Date).Value = DateTime.Now.AddMinutes(_pConfig.Timeout.TotalMinutes);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.Parameters.Add("LockId", OracleDbType.Int32).Value = lockId;
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "ReleaseItemExclusive");
throw new ProviderException(ExceptionMessage);
}
else
{
throw new Exception(e.Message);
}
}
finally
{
conn.Close();
}
}
public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
{
var conn = new OracleConnection(_connectionString);
var cmd = new OracleCommand("DELETE FROM Sessions " +
"WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName AND LockId = :LockId", conn);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.Parameters.Add("LockId", OracleDbType.Int32).Value = lockId;
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "RemoveItem");
throw new ProviderException(ExceptionMessage);
}
else
{
throw new Exception(e.Message);
}
}
finally
{
conn.Close();
}
}
public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
{
var conn = new OracleConnection(_connectionString);
var cmd = new OracleCommand("INSERT INTO Sessions " +
"(SessionId, ApplicationName, Created, Expires, " +
"LockDate, LockId, Timeout, Locked, SessionItems, Flags, UsuarioId, Menuid) " +
"Values(:SessionId, :ApplicationName, :Created, :Expires, :LockDate, :LockId, :Timeout, :Locked, :SessionItems, :Flags, :UsuarioId, :Menuid)", conn);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.Parameters.Add("Created", OracleDbType.Date).Value = DateTime.Now;
cmd.Parameters.Add("Expires", OracleDbType.Date).Value = DateTime.Now.AddMinutes(timeout);
cmd.Parameters.Add("LockDate", OracleDbType.Date).Value = DateTime.Now;
cmd.Parameters.Add("LockId", OracleDbType.Int32).Value = 0;
cmd.Parameters.Add("Timeout", OracleDbType.Int32).Value = timeout;
cmd.Parameters.Add("Locked", OracleDbType.Int32).Value = Convert.ToInt32(false);
cmd.Parameters.Add("SessionItems", OracleDbType.Varchar2).Value = "";
cmd.Parameters.Add("Flags", OracleDbType.Int32).Value = 1;
cmd.Parameters.Add("UsuarioId", OracleDbType.Varchar2, 50).Value = "";
cmd.Parameters.Add("Menuid", OracleDbType.Varchar2, 50).Value = "";
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "CreateUninitializedItem");
throw new ProviderException(ExceptionMessage);
}
else
{
throw new Exception(e.Message);
}
}
finally
{
conn.Close();
cmd.Dispose();
}
}
public override SessionStateStoreData CreateNewStoreData(HttpContext context, int i)
{
return new SessionStateStoreData(new SessionStateItemCollection(), SessionStateUtility.GetSessionStaticObjects(context), Timeout);
}
public override void ResetItemTimeout(HttpContext context, string id)
{
var conn = new OracleConnection(_connectionString);
var cmd = new OracleCommand("UPDATE Sessions SET Expires = :Expires " +
"WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName", conn);
cmd.Parameters.Add("Expires", OracleDbType.Date).Value = DateTime.Now.AddMinutes(_pConfig.Timeout.TotalMinutes);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "ResetItemTimeout");
throw new ProviderException(ExceptionMessage);
}
else
{
throw new Exception(e.Message);
}
}
finally
{
conn.Close();
}
}
public override void InitializeRequest(HttpContext context)
{
if (context != null)
{
if (context.Request.Cookies.Count <= 0) return;
//Verifica se a sessão é nula
if (context.Request.Cookies["ASP.NET_SessionId"] == null) return;
OracleDataReader reader = null;
var conn = new OracleConnection(_connectionString); //Get connection
try
{
var expireData = false;
var id = context.Request.Cookies["ASP.NET_SessionId"].Value; //get session id cookie
//Conexão com o banco
conn.Open();
//get data session oracle
var cmd = new OracleCommand("SELECT Expires, SessionItems, LockId, LockDate, Flags, Timeout, Locked, usuarioid, menuid " + "FROM Sessions " + "WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName", conn);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
//Recupera dados da sessão da fonte de dados.
reader = cmd.ExecuteReader(CommandBehavior.SingleRow);
while (reader.Read())
{
//Se estiver expirado marca flag true
DateTime expires = reader.GetDateTime(0);
if (expires < DateTime.Now)
{
expireData = true;
}
}
if (expireData)
{
cmd = new OracleCommand("DELETE FROM Sessions " +
"WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName", conn);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.ExecuteNonQuery();
context.Response.End();
}
}
catch (HttpException)
{
//Força httpexception caso não funcione
}
catch (Exception e)
{
//Se der erro generico da classe grava log e não prossegue dando throw exception
throw new Exception(e.Message);
}
finally
{
//Finaliza as conexões e objetos
reader?.Close();
conn.Close();
}
}
}
public override void EndRequest(HttpContext context)
{
//Não utilizado...
}
private static void WriteToEventLog(Exception e, string action)
{
//var log = new EventLog { Source = EventSource, Log = EventLog };
if (!System.Diagnostics.EventLog.SourceExists(EventSource))
System.Diagnostics.EventLog.CreateEventSource(EventSource, EventLog);
var message = "Ocorreu um erro ao tentar comunicação com o banco de dados.\n\n";
message += "Ação: " + action + "\n\n";
message += "Exceção: " + e;
System.Diagnostics.EventLog.WriteEntry(EventSource, message);
//log.WriteEntry(message);
}
public override void Dispose()
{
//Não utilizado
}
public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
{
return true;
}
}
I do not know if this class is the problem
Thanks
I discovered my problem. In inicializeRequest method had no action to force redirect to the login screen. Then I added the following command and it worked. I do not know if it was the best way, but it worked.
throw new HttpException((int)HttpStatusCode.Unauthorized, "Error Session, not authorized.");
So was the block of code in inicializerequest:
if (expireData)
{
cmd = new OracleCommand("DELETE FROM Sessions " +
"WHERE SessionId = :SessionId AND ApplicationName = :ApplicationName", conn);
cmd.Parameters.Add("SessionId", OracleDbType.Varchar2, 80).Value = id;
cmd.Parameters.Add("ApplicationName", OracleDbType.Varchar2, 255).Value = ApplicationName;
cmd.ExecuteNonQuery();
throw new HttpException((int)HttpStatusCode.Unauthorized, "Error session, not authorized");
context.Response.End();
}
I do not know if it was the best way, but if they want to help me improve my code I'm grateful. Thank you