I like to create a session value that expires in 5 minutes.
How to do that, do I need to manually compare creation time when I read it?
Session("sessionval") = myvariable
Session("sessioncreated") = now
If you are asking how to do it on a single variable I do not think it is possible, but you can define the session timeout period using the web.config
<system.web>
<sessionState timeout="5" />
<system.web>
this would affect all of your session objects, not just a single one.
My suggestion for giving a custom expiration date to a single item is to create a cookie, that way you can actually set it's expiration value.
Response.Cookies.Add(New Web.HttpCookie("AdminID", admin.AdminID))
Response.Cookies("AdminID").Expires = Now.AddMinutes(5)
you can not define custom timeout to a session variable.
Maybe you can use cache for this, with a unique key dependent to session.
You can set timeout to a cached item.
Cache.Insert("key_dependent_to_session", value, Nothing,
DateTime.Now.AddMinutes(5), TimeSpan.Zero)
If you want to use the SessionState you could create your own wrapper so instead of caching the actual item, you can cache the wrapper. Here is a quick dirty untested example of a wrapper that checks if the item is null, or if it has expired it will call a Func that you can provide a refreshed item.
The Func takes the last set value so if you can determine if the value is still valid you could avoid reloading it.
public class TimeExpirationItem<T>
{
private T _item=default(T);
private TimeSpan _expirationDuration;
private Func<T> _getItemFunc;
private DateTime _expiresTime;
public TimeExpirationItem(TimeSpan expirationDuration, Func<T, T> getItemFunc)
{
this._getItemFunc = getItemFunc;
this._expirationDuration = expirationDuration;
}
public T Item
{
get
{
if (_item == null || ItemIsExpired())
{
_item = _getItemFunc(_item);
_expiresTime = DateTime.Now.Add(_expirationDuration);
}
return _item;
}
}
public bool ItemIsExpired()
{
return DateTime.Now > _expiresTime;
}
}
Again this code is provided as is with no warranty and it is untested but is an example of the things you can do.
Using it would be something like the following:
Session.Add("ObjectKey",new TimeExpirationItem<MyObject>(new TimeSpan(0,0,5),mo=>MyObjectRepository.GetItemByLogin(Request.User.Identity.Name));
That is correct. Session state doesn't have an Expiration concept.
If your data are not per-user, you can use Cache instead. You could even use Cache, but include the user name as part of the key, which would sort of give you an expiring session state.
I tend to agree with TheTXI.
Although a single Session item cannot be assigned a custom timeout, you should note that in InProc session mode, Sessionstate is itself added as an item to the ASP.NET cache. This enables it to have a "timeout".
In your particular scenario, a Cache object is the best suited solution.
Sorry to resurrect an old question, but I faced exactly the same problem and had to create an extension-class for the HttpSession object.
Here's my blog article on this
PS. the code:
public static class SessionExtender
{
public static void AddWithTimeout(this HttpSessionState session,
string name,
object value,
TimeSpan expireAfter)
{
session[name] = value;
session[name + "ExpDate"] = DateTime.Now.Add(expireAfter);
}
public static object GetWithTimeout(
this HttpSessionState session,
string name)
{
object value = session[name];
if (value == null) return null;
DateTime? expDate = session[name + "ExpDate"] as DateTime?;
if (expDate == null) return null;
if (expDate < DateTime.Now)
{
session.Remove(name);
session.Remove(name + "ExpDate");
return null;
}
return value;
}
}
1) Put this in web.config
<configuration>
<system.web>
<sessionState mode="InProc" timeout="5">
</sessionState>
</system.web>
</configuration>
2) Set System.Web.SessionState.HttpSessionState.Timeout = 5 mins.
Related
Is it ok to get/set session variable inside a private/public property?
private List<FileAttachment> fileAttachments;
public List<FileAttachment> FileAttachments
{
get
{
if (Session["key"] != null)
{
fileAttachments = (List<FileAttachment>)Session["key"];
}
return fileAttachments;
}
set
{
fileAttachments = value;
Session["key"] = fileAttachments;
}
}
The goal here is I'd like for the container class (of this user control the property is in) to be able to set the List<T> depending on what entity and show existing attachments that's stored in the database.
That's not very safe; List<T> is not thread-safe.
You can never modify the list after assigning it to the property, since some other request thread might be reading it.
Therefore, you should make it a ReadOnlyCollection<T> rather than List<T>.
(and make sure your FileAttachment class is immutable or thread-safe)
Other than that, it depends where the property is.
If it's on a control or page, it's fine.
I dunno whether I described my question well but I'm trying to send some element to other page either with a hyperlink or a Response.Redirect() and it's a key which make some access to the DB so I don't want to send it via url and get it. what should I do? thanks.
You can store it in session, or you could use some type of encoding and pass it in the QueryString.
Another option would be to store the value in ViewState and use Server.Transfer to direct the user to the other page. With Server.Transfer you'll still be able to access the ViewState from the other page like this:
private string ValueFromOtherPage
{
get
{
if (ViewState["value"] != null)
{
return ViewState["value"].ToString();
}
else
{
string value;
if (Context.Handler != null)
{
value = (Context.Handler as PreviousPageName).MyStoredValue;
ViewState["value"] = value;
}
return value;
}
}
}
Take a look at this article for encoding/encrypting the QueryString:
http://www.codeproject.com/KB/web-security/QueryStringEncryptionNET.aspx
You can use session variables to store objects:
Session["VariableName"] = yourObject;
Note that overusing these session variables may lead to memory leaks.
You can save it in a session
You can send a GUID which represent some info (in the QS)
You can use cookies.
Is this possible to set different timeout for different session in ASP.Net?
Edited
I mean that in the same page i have 2 session variable Session["ss1"] and Session["ss2"], is there possible to set timeout for each session? Or is there anyway to do the same like save session to cookie and set expire?
Sry im just new to ASP.Net
I wrote a very simple extender class that does that. You can find the source code here
Usage:
//store and expire after 5 minutes
Session.AddWithTimeout("key", "value", TimeSpan.FromMinutes(5));
Set any timeout at login time, you can set different timeout for different users...
HttpContext.Current.Session.Timeout = 540;
If you are talking about session timeout for different users then
You can use Global.asax in this you can use Session_Start event and in this event you can set session timeout differently for different users
The answer is no the session timeout applies to ALL session variables per user. You can however use the cache or a cookie which both support timeout on an individua(per key) level.
But hang on those solutions don't come without some major drawbacks. If you use the cache you lose the privacy the session provides and if you use the cookie you are constrained with file size and serialization issues.
One workaround for this is to use the cache and make sure you include the user's session id in every key you use. This way you'll end up with a cache storage that mimics the session itself.
If you want further functionality and don't want to bother about implementing this however you can use the API from this little project on CodePlex:
http://www.univar.codeplex.com
The version 2.0 offers many storage type options out of the box including a session bound cache.
/// <summary>
/// this class saves something to the Session object
/// but with an EXPIRATION TIMEOUT
/// (just like the ASP.NET Cache)
/// (c) Jitbit 2011. MIT license
/// usage sample:
/// Session.AddWithTimeout(
/// "key",
/// "value",
/// TimeSpan.FromMinutes(5));
/// </summary>
public static class SessionExtender
{
public static void AddWithTimeout(
this HttpSessionState session,
string name,
object value,
TimeSpan expireAfter)
{
session[name] = value;
session[name + "ExpDate"] = DateTime.Now.Add(expireAfter);
}
public static object GetWithTimeout(
this HttpSessionState session,
string name)
{
object value = session[name];
if (value == null) return null;
DateTime? expDate = session[name + "ExpDate"] as DateTime?;
if (expDate == null) return null;
if (expDate < DateTime.Now)
{
session.Remove(name);
session.Remove(name + "ExpDate");
return null;
}
return value;
}
}
Usage:
//store and expire after 5 minutes
Session.AddWithTimeout("key", "value", TimeSpan.FromMinutes(5));
//get the stored value
Session.GetWithTimeout("key");
by Alex. CEO, founder https://www.jitbit.com/alexblog/196-aspnet-session-caching-expiring-values/
I developed a asp.net website where I log error information using log4net with format:
"%-5p %d - %m%n"
It logs datetime by current machine's datetime.
For example:
FATAL 2011-04-10 01:08:11,759 - message
But I want to convert datetime to another region or add additional time with it. For example I want to add 3 hours with previous example and want output as:
FATAL 2011-04-10 **04**:08:11,759 - message
Any idea on how to achieve this?
This might not answer your question, because I'm not sure exactly what you are trying to achieve. Maybe if you could provide more details on exactly why you want to do this, you might get a better answer.
If you are trying to correlate multiple log files (or other sources) that have been generated in different regions, it might help...
You could try log4net's utctime PatternLayout as described here.
This will get your log times in universal time, which might be easier for you to correlate. If you have control over the sources of timestampes (like your asp.net website), then by normalizing them to universal time, they should be easier to compare.
If you really do want to change the time to a different region or add/substract an arbitrary time span from the timestamp as it is logged, you might have to write your own custom PatternLayout or PatternLayoutConverter. That might be a little bit tricky as I think that neither the log4net DatePatternConverter nor the UtcDatePatternConverter is available for customization (i.e. they are declared internal so you can't subclass them and add your behavior).
You could write your own from scratch, using log4net's implementation from the log4net code repository, but that seems like a lot of trouble to me.
One more note, maybe it would be useful to log time again in a separate column using one of these Custom Date format specifiers: z, zz, zzz, K.
UPDATE:
See this answer for another idea that might help. The question asks for a way to capture username with log4net. Ultimately, the best solution for him was to write a very small class that will return the information the he needs (username). An instance of the class can be stored in the MDC (or GlobalDiagnosticContext) and referenced in the configuration. When log4net gets the value from the MDC (i.e. the object), it calls ToString and logs the result. This approach is a lot easier, if somewhat less flexible, than writing a whole new PatternLayoutConverter.
Towards the bottom of the answer is some sample code like this:
public class HttpContextUserNameProvider
{
public override string ToString()
{
HttpContext context = HttpContext.Current;
if (context != null &&
context.User != null &&
context.User.Identity.IsAuthenticated)
{
return context.Identity.Name;
}
return "";
}
}
You would store the object in the MDC/GlobalDiagnosticContext.Properties like this:
MDC.Set("user", new HttpContextUserNameProvider());
You could probably write something similar to return a different time. You could use this time instead of the log4net-provided time, or you could make this "custom" time an additional column. Your "custom time" object might look like this:
public class MyLocalTimeProvider
{
public override string ToString()
{
DateTime myLocalTime = GetUtcTimeInMyTimeZone(DateTime.UtcNow);
return myLocalTime;
}
}
Then you could reference it like this:
MDC.Set("myLocalTime", new MyLocalTimeProvider());
I'm not sure if you can apply formats to items from the MDC/GlobalDiagnosticContext.Properties (I think you can) or not, but you could try it and see.
You could always use a hardcoded format or add a format property to the object like this:
public class MyLocalTimeProvider
{
public MyLocalTimeProvider(string format)
{
Format = format;
}
public MyLocalTimeProvider()
: this ("G")
{
}
public string Format { get; set; }
public override string ToString()
{
DateTime myLocalTime = GetUtcTimeInMyTimeZone(DateTime.UtcNow);
return myLocalTime.ToString(Format);
}
}
You might take a look at this article for how to convert a UTC time to an arbitrary time zone.
If you need just "shift" date to your timezone, you can write your own ForwardingAppender, which will change DateTime of logged event:
namespace Olekstra
{
using System;
using log4net.Appender;
using log4net.Core;
public class TimeShiftForwardingAppender : ForwardingAppender
{
private TimeSpan shift;
private TimeSpan targetOffset;
public TimeShiftForwardingAppender()
{
TargetOffset = TimeZoneInfo.Local.BaseUtcOffset;
}
public TimeSpan TargetOffset
{
get
{
return targetOffset;
}
set
{
targetOffset = value;
shift = targetOffset.Subtract(TimeZoneInfo.Local.BaseUtcOffset);
}
}
protected override void Append(LoggingEvent loggingEvent)
{
var eventData = loggingEvent.GetLoggingEventData();
eventData.TimeStamp = eventData.TimeStamp.Add(shift);
base.Append(new LoggingEvent(eventData));
}
protected override void Append(LoggingEvent[] loggingEvents)
{
for (var i = 0; i < loggingEvents.Length; i++)
{
var eventData = loggingEvents[i].GetLoggingEventData();
eventData.TimeStamp = eventData.TimeStamp.Add(shift);
loggingEvents[i] = new LoggingEvent(eventData);
}
base.Append(loggingEvents);
}
}
}
And in .config
<log4net>
<appender name="FileAppender" type="log4net.Appender.RollingFileAppender">
<!-- Your real appender here -->
</appender>
<appender name="TimeShiftAppender" type="Olekstra.TimeShiftForwardingAppender">
<targetOffset>06:00:00</targetOffset> <!-- your desired (local) UTC offset value -->
<appender-ref ref="FileAppender" /> <!-- real appender(s) -->
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="TimeShiftAppender" />
</root>
</log4net>
I am wondering how the HttpContext is maintained given that the request-response nature of the web is essentially stateless.
Is an identifier being for the HttpContext object being sent as part of the __EVENTTarget / __EVENTARGUMENTS hidden fields so that the HttpRuntime class can create the HttpContext class by reading this section from the request (HttpWorkerRequest)? I don't think
Please let me know as I am trying to fill some holes in my understanding of the http pipeline and I was unable to find any information about this.
I understand something like
HttpContext.Current.Session["myKey"] = Value;
just works but if I had to do something similar in a different language (say perl), I would have to use hidden fields for the same, wouldn't I?
Thanks
-Venu
The HttpContext is recreated for each request. The HttpSession, however, is stored on the server across requests. Basically, HttpSession is a Dictionary<string, Dictionary<string, object>>. The initial key, the session id, is provided by either a cookie or a query string parameter (if using cookie-less sessions). If you use Fiddler, you'll see the ASP.NET_SessionId cookie that contains the key for that user's session.
In code:
class HttpSessionState {
private static readonly Sessions =
new Dictionary<string, Dictionary<string, object>>();
public object this(string key) {
get {
return GetCurrentUserSession()[key]
}
set {
GetCurrentUserSession()[key] = value;
}
}
private Dictionary<string, object> GetCurrentUserSession() {
var id = GetCurrentUserSessionId[]
var d = Sessions[id];
if (d == null) {
d = new Dictionary<string, object>();
Sessions[id] = d;
}
return d;
}
private string GetCurrentUserSessionId() {
return HttpContext.Current.Request.Cookies["ASP.NET_SessionId"].Value;
}
}
The real implementation also handles session timeouts, abandons, and cookieless sessions - but the basic idea is the same.
I don't think there is one answer to your question, because I don't think everything under the HttpContext umbrella works the same way. In the example you chose, session state, both the key and value are stored on the server side. The way it knows how to hook up future requests to that session state is by using a cookie that has a (totally different) key in it. When the browser makes another request, it sends this cookie with the request and the server uses it to figure out which session to map to. Once it figures it out, you've again got access to your dictionary, across responses.
So, to do it in perl, you'd want to manually create a cookie and store a unique key in it, have a server-side mapping of those unique keys to session state dictionaries, and pretty much do what I described above.