Can I write something like the following (in an assembly being used in an ASP.NET web page)?
public static string CurrentAuthenticatedUserFromHttpRequest
{
get
{
if (HttpContext.Current.Items["AuthUser"] == null)
{
return string.Empty;
}
return HttpContext.Current.Items["AuthUser"].ToString(); //set in "TryAuthenticate"
}
}
It is going to be a static read-only property. The value (to HttpContext.Current.Items["AuthUser"]) is set through a httphandler.
Just wondering on how this would perform during multiple requests. Is the data going to be accurate when multiple users try to access the same property (in multiple requests), even when high volumes of requests come in?
Yes, this is threadsafe. The static HttpContext.Current property differs per thread and contains the context for the request that the thread is currently handling.
Related
I'm trying to create a Caching Class to cache some objects from my pages. The purpose is to use the Caching system of the ASP.NET framework but to abstract it to separate class.
It seems that the caching doesn't persist.
Any ideas what I'm doing wrong here? Is it possible at all to cache object out side the Page it self?
EDIT: added the code:
Insert to cache
Cache c = new Cache();
c.Insert(userid.ToString(), DateTime.Now.AddSeconds(length), null, DateTime.Now.AddSeconds(length), Cache.NoSlidingExpiration,CacheItemPriority.High,null);
Get from the cache
DateTime expDeath = (DateTime)c.Get(userid.ToString())
I get null on the c.Get, even after I did have the key.
The code is in a different class than the page itself (the page uses it)
Thanks.
There are numerous ways you can store objects in ASP.NET
Page-level items -> Properties/Fields on the page which can live for the lifetime of the page lifecycle in the request.
ViewState -> Store items in serialised Base64 format which is persisted through requests using PostBack. Controls (including the page itself - it is a control) can preserve their previous state by loading it from ViewState. This gives the idea of ASP.NET pages as stateful.
HttpContext.Items -> A dictionary of items to store for the lifetime of the request.
Session -> Provides caching over multiple requests through session. The session cache mechanism actually supports multiple different modes.
InProc - Items are stored by the current process, which means should the process terminate/recycle, the session data is lost.
SqlServer - Items are serialised and stored in a SQL server database. Items must be serialisable.
StateServer - Items are serialised and stored in a separate process, the StateServer process. As with SqlServer, items must be serialisable.
Runtime - Items stored in the runtime cache will remain for the lifetime of the current application. Should the applciation get recycled/stop, the items will be lost.
What type of data are you trying to store, and how do you believe it must be persisted?
Right at the beginning of last year I wrote a blog post on a caching framework I had been writing, which allows me to do stuff like:
// Get the user.
public IUser GetUser(string username)
{
// Check the cache to find the appropriate user, if the user hasn't been loaded
// then call GetUserInternal to load the user and store in the cache for future requests.
return Cache<IUser>.Fetch(username, GetUserInternal);
}
// Get the actual implementation of the user.
private IUser GetUserInternal(string username)
{
return new User(username);
}
That was nearly a year ago, and it has been evolved a bit since then, you can read my blog post about it, let me know if thats of any use.
Your cache reference needs to be accessible to all items in your code - the same reference.
If you are newing up the Cache class every time, you are doing it wrong.
I have done almost the same things, but with a different code (and it work for me) :
(CacheKeys is an enum)
using System;
using System.Configuration;
using System.Web;
using System.IO;
public static void SetCacheValue<T>(CacheKeys key, T value)
{
RemoveCacheItem(key);
HttpRuntime.Cache.Insert(key.ToString(), value, null,
DateTime.UtcNow.AddYears(1),
System.Web.Caching.Cache.NoSlidingExpiration);
}
public static void SetCacheValue<T>(CacheKeys key, T value, DateTime expiration)
{
HttpRuntime.Cache.Insert(key.ToString(), value, null,
expiration,
System.Web.Caching.Cache.NoSlidingExpiration);
}
public static void SetCacheValue<T>(CacheKeys key, T value, TimeSpan slidingExpiration)
{
HttpRuntime.Cache.Insert(key.ToString(), value, null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
slidingExpiration);
}
public static T GetCacheValue<T>(CacheKeys key)
{
try
{
T value = (T)HttpRuntime.Cache.Get(key.ToString());
if (value == null)
return default(T);
else
return value;
}
catch (NullReferenceException)
{
return default(T);
}
}
For a long time now I have noticed something annoying when working on Web Application projects involving databased images on my local machine. By local I mean that it's a typical environment with VS 2008 and SQL Server 2005 on my workstation. Whenever I use an HttpHandler to display the images on my local, only some of the images render on each page load.
However, when I push the application to a hosted environment, the problem usually disappears. However, I just pushed a new project out to a hosted environment and experienced the same problem as on my local - this time the site and the DB were on the same server in the hosting environment. Has anyone got a take on what's happening here?
Here's the handler:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class FeaturedHandler : IHttpHandler
{
Business biz = new Business();
public void ProcessRequest(HttpContext context)
{
if (context.Request.QueryString["ListingID"] != null)
{
int listingID = Convert.ToInt32(context.Request.QueryString["ListingID"]);
DataSet ds = biz.GetFeaturedImageByID(listingID);
DataRow row = ds.Tables[0].Rows[0];
byte[] featureImage = (byte[])row["Photo"];
context.Response.ContentType = "image/jpeg";
context.Response.OutputStream.Write(featureImage, 0, featureImage.Length);
}
else
throw new ArgumentException("No ListingID parameter specified");
}
public bool IsReusable
{
get
{
return false;
}
}
}
I have tried using a DB on a separate server but encountered the same problem. Should I be using a DataReader instead?
UPDATE
I should have used a DataReader initially since I am reading binary data.
I finally got all images to render by changing the value of the IsReusable property to true:
public bool IsReusable
{
get
{
return true;
}
}
Apparently, this keeps the handler in memory and able to handle multiple requests. When set to false, it had to create a new instance of the handler for each incoming request.
By this:
Whenever I use an HttpHandler to
display the images on my local, only a
portion of the images render on each
page load.
Do you mean that the same image appear on places where different images should appear or that some images appear and some doesn't show at all?
In your case the difference by switching isReusable to true is that new Business(); will be called once for multiple images. If isReusable is false the new Business(); will be called once per image. This means that if you have several images per page new Business(); will be called several times for this particular page.
Also I strongly suggest changing this:
if (context.Request.QueryString["ListingID"] != null)
{
int listingID = Convert.ToInt32(context.Request.QueryString["ListingID"]);
with:
string listingIdParam = context.Request.QueryString["ListingID"];
if (listingIdParam != null)
{
int listingID = Convert.ToInt32(listingIdParam);
This will save you null reference exceptions that usually surface only under heavy load. Also the above will prevent serving the wrong image to a request especially when isReusable is true.
I cannot determine what the problem was exactly but I can definitely say that setting the isReusable flag was just a workaround and doesn't fix your problem. Also when a problem like this is reproducible only in certain environment that means that either it's a thread problem or there is some difference in request handling (different web server - IIS6, IIS7, development server).
Maybe posting the Business class and it's constructor can shed some light.
Also I suggest implementing some kind of error logging to trap exceptions in the handler and review them.
If you are serving images directly, do not forget to set the correct caching headers, i.e. etags and expires. If you don't you are really going to hit your database hard and use up your bandwidth.
You will need to handle the following http headers:
ETag
Expires
Last-Modified
If-Match
If-None-Match
If-Modified-Since
If-Unmodified-Since
Unless-Modified-Since
For an example http handler that does this check out:
http://code.google.com/p/talifun-web/wiki/StaticFileHandler
The users of my web application may have more than one browser window (or tab) open and pointed to the same page. We're using cookie based session id's, and the user will usually work within the same session id in both browsers/tabs. I would like to be able to uniquely identify which browser window (and tab) that requested an ASP.NET page (in order to make sure, that data stored in the session does not get mixed up).
(e.g. I would be happy if the browser would generate and send a window/tab-id with the http request, as it publishes HTTP_USER_AGENT)
Any ideas?
--thomas
If I was going to implement something like this I would probably start with a Dictionary<Type, List<Guid>> and store this in the users session. I would also probably make this be a custom type that delegates the dictionary and have a factory method that works similar to
public Guid GeneratePageIdentifier(Page thepage)
{
var guid = Guid.New();
if(_dictionary[thepage.GetType()] == null)
_dictionary[thepage.GetType()] = new List<Guid> { guid };
else
((List<Guid>)_dictionary[thepage.GetType()]).Add(guid);
return guid;
}
Then embed the guid that's returned from that method on the VIewState of the page. On your page methods that execute actions that you need to validate which page it is you would be able to validate that guid is inside the collection do something. You might also want to implement a custom a type with a guid property to enscapulate more information about why you're doing this or what you need for it to be meaningful.
The Viewstate on each page will be different, maybe you can use some kind of unique identifier created on every page loaded?
It is by default not possible due to the stateless nature of the web, but you could add a "page identifier" that gets generated with each opened page and transmitted for every action.
I'd recommend that you refactor the application in a way that those mixups can't happen, no matter from which page/tab/window the request originates.
As Mark Redman said, you can use Viewstate + Session in order to store values specific to the page.
ViewState is good for storing the key (string), Session for storing whatever type of complex objects.
Use the ViewState or a hidden field in order to load at the first call a GUID.
public string PageUid
{
get
{
if (ViewState["UID"] == null)
ViewState.Add("UID", Guid.NewGuid().ToString());
return ViewState["UID"].ToString();
}
}
Then use the session to get/set your values using this key:
string MyPagesessionVariable
{
get
{
if (Session["MYVAR" + PageUid] == null)
{
Session["MYVAR" + PageUid] = "VALUE NOT SHARED WITH OTHER TABS/WINDOWS";
}
return Session["MYVAR" + PageUid];
}
set
{
Session["MYVAR" + PageUid] = value;
}
}
i have a HttpModule that creates an CommunityPrincipal (implements IPrincipal interface) object on every request. I want to somehow store the object for every request soo i can get it whenever i need it without having to do a cast or create it again.
Basically i want to mimic the way the FormsAuthenticationModule works.
It assigns the HttpContext.User property an object which implements the IPrincipal interface, on every request.
I somehow want to be able to call etc. HttpContext.MySpecialUser (or MySpecialContext.MySpecialUser - could create static class) which will return my object (the specific type).
I could use a extension method but i dont know how to store the object so it can be accessed during the request.
How can this be achieved ?
Please notice i want to store it as the specific type (CommunityPrincipal - not just as an object).
It should of course only be available for the current request being processed and not shared with all other threads/requests.
Right now i assign my CommunityPrincipal object to the HttpContext.User in the HttpModule, but it requires me to do a cast everytime i need to use properties on the CommunityPrincipal object which isnt defined in the IPrincipal interface.
I'd recommend you stay away from coupling your data to the thread itself. You have no control over how asp.net uses threads now or in the future.
The data is very much tied to the request context so it should be defined, live, and die along with the context. That is just the right place to put it, and instantiating the object in an HttpModule is also appropriate.
The cast really shouldn't be much of a problem, but if you want to get away from that I'd highly recommend an extension method for HttpContext for this... this is exactly the kind of situation that extension methods are designed to handle.
Here is how I'd implement it:
Create a static class to put the extension method:
public static class ContextExtensions
{
public static CommunityPrinciple GetCommunityPrinciple(this HttpContext context)
{
if(HttpContext.Current.Items["CommunityPrinciple"] != null)
{
return HttpContext.Current.Items["CommunityPrinciple"] as CommunityPrinciple;
}
}
}
In your HttpModule just put the principal into the context items collection like:
HttpContext.Current.Items.Add("CommunityPrincipal", MyCommunityPrincipal);
This keeps the regular context's user property in the natural state so that 3rd party code, framework code, and anything else you write isn't at risk from you having tampered with the normal IPrincipal stroed there. The instance exists only during the user's request for which it is valid. And best of all, the method is available to code as if it were just any regular HttpContext member.... and no cast needed.
Assigning your custom principal to Context.User is correct. Hopefully you're doing it in Application_AuthenticateRequest.
Coming to your question, do you only access the user object from ASPX pages? If so you could implement a custom base page that contains the cast for you.
public class CommunityBasePage : Page
{
new CommunityPrincipal User
{
get { return base.User as CommunityPrincipal; }
}
}
Then make your pages inherit from CommunityBasePage and you'll be able to get to all your properties from this.User.
Since you already storing the object in the HttpContext.User property all you really need to acheive you goal is a Static method that acheives your goal:-
public static class MySpecialContext
{
public static CommunityPrinciple Community
{
get
{
return (CommunityPrinciple)HttpContext.Current.User;
}
}
}
Now you can get the CommunityPrinciple as:-
var x = MySpecialContext.Community;
However it seems a lot of effort to got to avoid:-
var x = (CommunityPrinciple)Context.User;
An alternative would be an Extension method on HttpContext:-
public static class HttpContextExtensions
{
public static CommunityPrinciple GetCommunity(this HttpContext o)
{
return (CommunityPrinciple)o.User;
}
}
The use it:-
var x = Context.GetCommunity();
That's quite tidy but will require you to remember to include the namespace where the extensions class is defined in the using list in each file the needs it.
Edit:
Lets assume for the moment that you have some really good reason why even a cast performed inside called code as above is still unacceptable (BTW, I'd be really interested to understand what circumstance leads you to this conclusion).
Yet another alternative is a ThreadStatic field:-
public class MyModule : IHttpModule
{
[ThreadStatic]
private static CommunityPrinciple _threadCommunity;
public static CommunityPrinciple Community
{
get
{
return _threadCommunity;
}
}
// Place here your original module code but instead of (or as well as) assigning
// the Context.User store in _threadCommunity.
// Also at the appropriate point in the request lifecyle null the _threadCommunity
}
A field decorated with [ThreadStatic] will have one instance of storage per thread. Hence multiple threads can modify and read _threadCommunity but each will operate on their specific instance of the field.
I have an ASP.NET application with a lot of dynamic content. The content is the same for all users belonging to a particular client. To reduce the number of database hits required per request, I decided to cache client-level data. I created a static class ("ClientCache") to hold the data.
The most-often used method of the class is by far "GetClientData", which brings back a ClientData object containing all stored data for a particular client. ClientData is loaded lazily, though: if the requested client data is already cached, the caller gets the cached data; otherwise, the data is fetched, added to the cache and then returned to the caller.
Eventually I started getting intermittent crashes in the the GetClientData method on the line where the ClientData object is added to the cache. Here's the method body:
public static ClientData GetClientData(Guid fk_client)
{
if (_clients == null)
_clients = new Dictionary<Guid, ClientData>();
ClientData client;
if (_clients.ContainsKey(fk_client))
{
client = _clients[fk_client];
}
else
{
client = new ClientData(fk_client);
_clients.Add(fk_client, client);
}
return client;
}
The exception text is always something like "An object with the same key already exists."
Of course, I tried to write the code so that it just wasn't possible to add a client to the cache if it already existed.
At this point, I'm suspecting that I've got a race condition and the method is being executed twice concurrently, which could explain how the code would crash. What I'm confused about, though, is how the method could be executed twice concurrently at all. As far as I know, any ASP.NET application only ever fields one request at a time (that's why we can use HttpContext.Current).
So, is this bug likely a race condition that will require putting locks in critical sections? Or am I missing a more obvious bug?
If an ASP.NET application only handles one request at a time all ASP.NET sites would be in serious trouble. ASP.NET can process dozens at a time (typically 25 per CPU core).
You should use ASP.NET Cache instead of using your own dictionary to store your object. Operations on the cache are thread-safe.
Note you need to be sure that read operation on the object you store in the cache are threadsafe, unfortunately most .NET class simply state the instance members aren't thread-safe without trying to point any that may be.
Edit:
A comment to this answer states:-
Only atomic operations on the cache are thread safe. If you do something like check
if a key exists and then add it, that is NOT thread safe and can cause the item to
overwritten.
Its worth pointing out that if we feel we need to make such an operation atomic then the cache is probably not the right place for the resource.
I have quite a bit of code that does exactly as the comment describes. However the resource being stored will be the same in both places. Hence if an existing item on rare occasions gets overwritten the only the cost is that one thread unnecessarily generated a resource. The cost of this rare event is much less than the cost of trying to make the operation atomic every time an attempt to access it is made.
This is very easy to fix:
private _clientsLock = new Object();
public static ClientData GetClientData(Guid fk_client)
{
if (_clients == null)
lock (_clientsLock)
// Check again because another thread could have created a new
// dictionary in-between the lock and this check
if (_clients == null)
_clients = new Dictionary<Guid, ClientData>();
if (_clients.ContainsKey(fk_client))
// Don't need a lock here UNLESS there are also deletes. If there are
// deletes, then a lock like the one below (in the else) is necessary
return _clients[fk_client];
else
{
ClientData client = new ClientData(fk_client);
lock (_clientsLock)
// Again, check again because another thread could have added this
// this ClientData between the last ContainsKey check and this add
if (!clients.ContainsKey(fk_client))
_clients.Add(fk_client, client);
return client;
}
}
Keep in mind that whenever you mess with static classes, you have the potential for thread synchronization problems. If there's a static class-level list of some kind (in this case, _clients, the Dictionary object), there's DEFINITELY going to be thread synchronization issues to deal with.
Your code really does assume only one thread is in the function at a time.
This just simply won't be true in ASP.NET
If you insist on doing it this way, use a static semaphore to lock the area around this class.
you need thread safe & minimize lock.
see Double-checked locking (http://en.wikipedia.org/wiki/Double-checked_locking)
write simply with TryGetValue.
public static object lockClientsSingleton = new object();
public static ClientData GetClientData(Guid fk_client)
{
if (_clients == null) {
lock( lockClientsSingleton ) {
if( _clients==null ) {
_clients = new Dictionary``();
}
}
}
ClientData client;
if( !_clients.TryGetValue( fk_client, out client ) )
{
lock(_clients)
{
if( !_clients.TryGetValue( fk_client, out client ) )
{
client = new ClientData(fk_client)
_clients.Add( fk_client, client );
}
}
}
return client;
}