Suppose one has an HttpHandler that processes each request, and suppose each HttpHandler computes an intermediate result for each request and potentially wants to pass this to a page handler eg via Server.Transfer or Server.Execute via the HttpContext.Items collection
Will each request have a separate copy of HttpContext.Items["sameKey"] when they each reach the same .aspx page?
My concern arises from the fact HttpContext.Current is itself a static property
HttpContext Encapsulates all HTTP-specific information about an individual HTTP
request.
Hence each request HttpContext.Items["sameKey"] will be a different copy.
HttpContext.Items is stateless the only way to "share" between requests is Session or higher level state (database)
Related
I have an mvc webapi service setup that pulls and pushes data from an sql server database.
Within the Web project holding the webapi I have a Static class that just holds some global variables that are accessed from the webapi methods. Following is a very cutdown example of the static class:
public static class SystemProperties
{
public static int currentContactID;
}
When the WebApi is accessed I strip the ContactID from the Http Headers of the call and set the SystemProperties.CurrentContactID to it.
Than in the methods of the webapi I access SystemProperties.CurrentContactID for data calls.
I have found a problem when there is concurrent webapi calls the currentContactID is getting mixed up.
My question is, how is the static class members shared between calling sessions? Is it going to be pretty much last in best dressed and if the previous person is still in there than they will get screwed over by the new person who will overwrite the variables with their details?
Should I be using a different method to store these details?
Thanks in advance
You can use the Current HttpContext to store items to use across the lifetime of an HttpRequest
HttpContext.Current.Items["currentContactID"] = value
So you can grab the data from the Request header, and store it here and it will be available for the duration of the current http web request for that user. Every http request has its own Items dictionary so it won't be overwritten by simultaneous requests
If you need to store a variable across several requests for the same user you need to look into cookies or sessions.
Yes, you should be using different method.
With Web API the request comes in as HttpRequestMessage. You can implement a HTTP message handler (inheriting from DelegatingHandler) and from there strip the CurrentContactID from HTTP Headers. You can also take your CurrentContactID value you've stripped out and add it to the HttpRequestMessage objects Properties dictionary.
Here's article on implementing HTTP message handler: http://www.asp.net/web-api/overview/working-with-http/http-message-handlers
Here's article on the Properties property of HttpRequestMessage: http://msdn.microsoft.com/en-us/library/system.net.http.httprequestmessage.properties.aspx
Keep in mind that the Properties property on HttpRequestMessage is available to you at controller as well which is why it is suitable for use in lieu of static class or session.
I really can't find out what is really the differences between these two methods in C#/.NET.
In fact they should do the same actions!
The first contains a safe read/write storage location that could be used throughtout the entire HTTP request. You could use it for example to store some object in the Begin_Request method and it will be available up until the page renders. It's like a Session but that lives only for the lifetime of a single HTTP request. You can access it from everywhere during during this request and it is specific to the context of the current request only.
The second is readonly storage for query string, POSTed form parameters, server variables and cookies.
Items is a NameValueCollection useful for storing and sharing data for the life of the HTTP Request. The Request meanwhile provides access and methods specific to the HTTP Request. Neither are methods however.
Consider a user making multiple requests at the same time, do I have to lock all code that works with the Session?
If for example I have the following scenario, where in one tab of his browser the user opens a page and in the second he logs out.
Request 1:
if(Session["user"] != null)
lblName.Text = Session["user"].Name;
Request 2:
if(logout)
Session["user"] = null;
Is it possible that Request 1 throws a NullPointerException when accessing the Name property? Do i need to lock the code in Request 1, to make sure user still exists after checking for null? Or does ASP.NET deal with this automatically somehow?
Two requests to an ASP.NET application for the same same session, where the handlers do not use the IReadOnlySessionState marker interface or have the EnableSessionState="ReadOnly" turned on for your pages, will be serialized by the ASP.NET runtime to guarantee consistency of the state. So if you have two pages that are able to write to the session state, they will be accessed serially no matter what the client does on their side.
It's up to your application code to signal to ASP.NET with the afforementioned techniques whether or not a page/handler is going to write to the session state. If you do not, all requests will be serialized and the performance of your web application will suffer.
As always, the answer depends on what you mean by "safety." In ASP .NET, each request gets exclusive access to its session state. This means that you don't have to worry about synchronizing access within the scope of a single request. If Session["user"] is non-null, then it will be non-null for the entire duration of the current request. In your example, request 1 will never throw a null reference exception.
In ASP.NET, the Session module uses a pair of reader/writer locks per session, so Request 1 will have consistent reads, and Request 2 will block until Request 1 completes.
Yes, Session is thread-safe.
There's no need to lock anything. However, the need to check the values never cease to be essential.
Update
Check #Peter Ruderman's answer :)
I will have the decency of not copying it :)
I've the following doubt. I've a page "MyPage" and i've declared few dictionary objects in the page class.
My doubt is
If i declare the dictionary as a private non-static object i'm not able to use it across the functions in that page class (the object is getting nulled)
But if i declare the dictionary to be static i'm able to across the object across the functions. But will that object be same across all the users who have opened the page right now (guessing that each user will have an instance of the page in turn has an instance for the page class and static variables of a class are invariable across all the instances of the class)
Is my understanding right? How to declare the object to be available across all the functions within the page class and unique for each instance of the page (user).
Update1
Okie, i find that the initialization of the dictionary object in the page class is done in a different thread (WCF Duplex callback). But in the main page thread the dictionary object is still remaining as null (uninitialized). Any ideas?
Update2
Marshalling - useful by any chance?
Update3
In reply to John-
Thanks for your reply. The problem i'm facing now is to pass the data from the WCF callback class at the client side(which will be invoked in a separate thread) to the asp.net page. So how can i do that? View state may help me to persist the data across requests. But when the callback is invoked by the server notifying for a change how should i pass the changes (data) to the UI thread (asp.net page)?
Don't do things like this.
If you need to maintain data between pages, use Session state. That's what it's for. You should remember that you get a new instance of your page class on every request. Do not use statics to keep changing data around for subsequent requests. You will probably get into trouble with multiple requests updating the data at the same time.
You can't do things like this with ASP.NET!
You seem to be treating this as though it were a desktop program - as though your class instance and all state will still be there for you next time you execute a method on the page. That's not true - when the request is complete, your page will be Disposed. Nothing about the page will remain valid.
In particular, if the callback doesn't happen before the request ends, then the callback method had better not reference anything having to do with the request, like your page. That's because the callback might fire after the request is already over! The state is corrupt or worse.
Unless you are going to have the page wait for the callback, you'd really better not use them in your pages. Instead, create a separate Windows Service or something and have it issue the requests and await the callback. The page can then use Ajax or something to ask if the request is complete, and to get the response once complete.
If you think you heard me say to call back to an ASP.NET page, then you misunderstood.
Create a Windows Service. Your Windows Service will host a WCF service that the ASP.NET application will talk to. The WCF Service will keep track of things like who's joined a chat, who's typing, etc.
The web application cannot be notified when something interesting happens. Instead, the web application will have to poll the WCF service, asking if anything interesting has happened. When something happens, the WCF service will pass the "something" back to the ASP.NET application (or possibly, back to the page, called by AJAX).
I misspoke earlier. You simply cannot use a callback contract at all in this situation. It's not like the web pages are like a desktop application, one per user, waiting to be notified. They're more like a desktop application where, when the user makes a request, you take his PC and give him a new one just like it, before the response arrives.
You are right in the second case. In your first case I'm guessing you mean that if a user clicks multiple controls on your page then the event handlers are seeing that the dictionary is null (instead of having the result from the previous event handler).
Remember that every request on a page (even from the same user) creates a new instance of your page class. That means that each time a request starts, your dictionary will be null. The only way for a variable to maintain its value between subsequent requests is to persist it server-side (for example, in user-specific session information on the server) or to push it to the client with the page content so that it can be part of the subsequent request data (so it's stored in ViewState or other storage at the client's browser between requests).
Rereading this question, there are three seperate state machines, and none of them are being coupled together - hence the problem :)
State of the "user state" - these are the key/value pairs in the dictionary, their lifetime spans multiple page requests and callbacks
State of a "page", which needs to consume the data from "user state". Pages are destroyed after each and every page request.
State of the "service call" which needs to populate the data in "user state" Service calls are generally destroyed after each invocation.
There are a few strategies that could enable you to couple the systems:
ViewState such that the state machine for "user state" is sent down as part of the state of the page, and sent back on postbacks. This may constrain how you perform service callbacks
Session such that the state machine for "user state" is stored server side, and can be accessed by key.
Static dictionary of user states, where the key for the outer dictionary would be the identity of the "user state", where the 1st page request would create the "user state" entry, and you'd need to manage teardown. (v.similar to session - though works without ASP.NET).
There are lots of nuances to each solution - I'd advise light reading :)
you are right that a static member will be the same for all instances of the page, and thus all individual users. You need to make it a non-static member if you want to access it from every method in the class. You should look into why the object is null. Are you properly instantiating it at the proper time?
How would you access the cache from a jQuery ajax call?
I'm using jquery to do some data verification and quick data access. I have a static web-method that jquery is calling via json to return a value. I don't want to call to the database everytime so I'd like to cache the data I'm hitting, but I can't determine how to call the asp.net cache from within javascript, or a static method.
I'd like to send the page object through to the static method, which would allow me to access page.cache, but don't know how. Barring that, maybe a way to access the cache from javascript itself?
System.Web.HttpContext.Current.Cache
Cache is shared per app domain - not per Page. Page just has a convenience property of Page.Cache to get the current Cache, which means you can just do Cache["key"] from a method in a page.
As you've noticed, if you're in a static method - then you have no Page instance, and you have no Page.Cache property. So, you need to use HttpContext.Cache. But, wait - you have no HttpContext instance either! That's ok, the currently executing instance is stored at the static property of HttpContext.Current.
So - to answer your question - in a static method, use HttpContext.Current.Cache. BTW, you can also access the Request and Response properties from there.
I think calling a PageMethod may be the best you can really do, if you really want to do this:
http://encosia.com/2008/05/29/using-jquery-to-directly-call-aspnet-ajax-page-methods/
Javascript is client side, the Cache is on the Server Side, so you need to do a callback to a method in your asp.net application, that returns the content of the cache.
The ASP.NET Cache API is really good, you can use Cache["Key"] to get the cached content that you like. Read more here : http://msdn.microsoft.com/en-us/library/ms972379.aspx