Confusion over Startup, Global, Application and Session - asp.net

I am trying to understand the various ways of storing and instantiating Application (i.e. objects available to every user) and Session level (objects created and available to users only for their session) variables. Also, how does OWIN fit into all of this?
Global.asax.cs - This can contain a bunch of different methods. I believe that Application_Start is only called during the first request. However, there are a few candidates here for methods to populate session level variables (e.g. Session_Start and Application_BeginRequest). What is the standard way of doing this?
There is also the Startup class used by OWIN. I get that OWIN lets you store Application level variables, but why wouldn't you just use the HttpApplicationState Application variable accessible from Global.asax.cs to accomplish this? Also - can OWIN handle Session variables?

"I believe that Application_Start is only called during the first
request."
Only for the first request after calling the web application. For instance, this is the case after deploying, ApplicationPool Recycling, restarting or coming out of sleep.
Let's assume 3 users visit your web application. Application_Start will only be called for one of them, specifically the first one that visits it. Therefore it is not suited for populating user-specific session values.
However, there are a few candidates here for methods to populate session level variables (e.g. Session_Start and Application_BeginRequest). What is the standard way of doing this?
In the past I've worked with Session_Start to initialize user-specific session values (like default values) on numerous projects and never had an issue with it.

I'm really not sure what the question is, as I said in the comments. I'm going to ignore the OWIN stuff since I don't know, frankly.
Firstly, try not to store state at all. Design to pass state back and forth between server and client in models, or the URL, even in the HTML on the client such as in the URLs in the <a> tags your rendering, or (rarely) in cookies, rather than keep things in memory. Stateless designs are way more scalable.
Storing state isn't "usually" done in the Global.asax but then what's usual? I store state as and when I need it, load it or otherwise come by that data. For me in MVC, that's usually downstream of a Controller action, maybe while logging someone in, or reading some data received in a model, like a customer clicking 'add to cart'.
Application state I rarely use, though I store long-lived and shared data within normal fields and properties in long-lived static classes. These die when the app is recycled, but I don't usually care since the apps are designed to work without it, stateless; its usually cached bits of data.
Also, Session_Start only fires when a new browser/agent hits the site. You don't know the user at that point.
The methods in the Global.asax were not specifically designed for 'bootstrapping' state-loading, they're just convenient events for doing whatever you want with. You don't have to use them at all, mine usually just contain logging so I know when sessions start etc.!
I don't know if this helps.
Once you have a plan, come back and ask a targeted question about the OWIN stuff.

Related

How can I slowly migrate to using Redis as a Session State Provider from in process?

Is it a bad idea to implement my own session state provider that conditionally switches based on key between the redis session provider and the inproc session provider?
I am working in a very large legacy asp.net application that currently uses the inproc session provider. We are migrating to Redis as a session state provider so that it persists deploys, however the application is chock full of session abuses (e.g. way too large objects, non-serializable object, I saw a thread in there for some reason?).
We plan to slowly correct these abuses but until they are all corrected we cannot really move to redis. I am hoping we can slowly start migrate serializable-safe keys into redis while the abuses remain in memory until we address them.
Does anyone have any advice on this? Or perhaps alternative suggestions for migrating to out of process from in process?
Thanks!
In ASP.NET Web Form and MVC, using Redis for Session State is just a couple of line of modification in Web.config. Then add SerializableAttribute to classes. There is no side effects of applying it to a class.
Based on my experience when migrating to Azure few years ago, Session State is not worth migrating slowly.
Caching is different story. It requires code changes, so we end up implementing two classes - MemoryCacheManager and RedisCacheManager, and register at run-time in IoC container. Then inject ICacheManager to dependent classes.
Source for the session state: https://github.com/Microsoft/referencesource/blob/master/System.Web/State/
Docs: https://learn.microsoft.com/en-us/dotnet/api/system.web.sessionstate?view=netframework-4.7.2
I'd start by checking out the reference source so you can search the codebase. One interface jumps out as potentially interesting.. IPartialSessionState (When implemented in a type, returns a list of zero or more session keys that indicate to a session-state provider which session-state items have to be retrieved.) Source is here
https://learn.microsoft.com/en-us/dotnet/api/system.web.sessionstate.ipartialsessionstate?view=netframework-4.7.2
I stumbled on https://www.wiktorzychla.com/2007/06/wrapped-inprocsessionstatestore.html
via ASPNET : Switch between Session State Providers ?‏.
This technique could theoretically be used with the Redis provider as well. You'd have to either maintain a list of keys suitable for storing in Redis or do some kind of try to serialize/catch/cache result of which types can be serialized and adaptively fall back to the InProc behavior. You should be able to use HttpContext.Current.Items to flow information between events in the request processing pipeline.
The SessionStateModule (the module responsible for retrieving session, locking, saving, unlocking, etc.) seems to treat InProc as special in a few places. Search its code for InProc. Essentially you're trying to plug in a magical provider that is Custom and yet still has all of the InProc semantics applied by the one and only SessionStateModule. You won't be able to/probably won't want to modify that module, but you may be able to hook up another one adjacent to it that hooks into related events in the request pipeline and does whatever needs to be done that is either In-Proc or Custom-specific. You'll probably run into internal/private methods for which you'd need to use reflection. Not sure how the licensing works on the reference source (MS-PL I think), but another option would be to copy & paste the code from SessionStateModule into your own, make adjustments as needed, unregister the original and register your replacement.
I think you're going to be stuck dealing with a lot of reflection code to get this to work.

Concurrent page processing/serving

I've created web application that has a sub that builds a contacts list. This sub fetches phone numbers and email address from a contacts db based on ids that are provided by a user. At it's fastest, the application will process about four ids per second. With 200-300 ids at any given time, the completion time is long.
Time is not really the problem, it's end user status updates. I've created a very crude web service that reads the "CurrentRecordNumber" that is stored in a session variable as the app loops through the ids. I intend to use javascript to call the webmethod from the app periodically to update status.
My problem is that when debugging, the webmethod call will complete successfully, but not until the app is finished processing.
This seems like a very simple problem. I must not be using the right terms because my results seem overly complicated.
I'm very new to asynchronous features of ASP.NET so please forgive. I have, however, written some Winforms that incorporate multiple threads so I have a basic understanding of threading.
This is due to the way ASP.NET treats session. You haven't said whether you are using webforms or MVC, but MVC has a quick workaround for this.
First, the problem:
SessionState is designed to be accessed by one request at a time, in the order received by the server. Think of this as a queue at the bank with only one bank teller available. The first person in line is the first to be helped (though this is on a per-session basis, not a per-user).
ASP.NET locks all other requests that require SessionState from executing until the previous one is done.
I haven't tried to correct this problem in web forms, but the easiest way I know of would be to not require SessionState on your progress check.
In MVC, there's a SessionState attribute that can be applied to the controller or method, indicating that there's no chance of a call to that method overwriting SessionState. As long as your call is read-only, you can make your controller code use this attribute to allow multiple async requests simultaneously:
<SessionState(SessionStateBehavior.ReadOnly)>
Public Class MyController

Attaching an event listener to all URLRequest's

We have a flex application that connects to a proxy server which handles authentication. If the authentication has timeout out the proxy server returns a json formatted error string. What I would like to do is inspect every URLRequest response and check if there's an error message and display it in the flex client then redirect back to login screen.
So I'm wondering if its possible to create an event listener to all URLRequests in a global fashion. Without having to search through the project and add some method to each URLRequest. Any ideas if this is possible?
Unless you're only using one service, there is no way to set a global URLRequest handler. If I were you, I'd think more about architecting your application properly by using a delegate and always checking the result through a particular service which is used throughout the app.
J_A_X has some good suggestions, but I'd take it a bit farther. Let me make some assumptions based on the limited information you've provided.
The services are scattered all over your application means that they're actually embedded in multiple Views.
If your services can all be handled by the same handler, you notionally have one service, copied many times.
Despite what you see in the Adobe examples showing their new Service generation code, it's incredibly bad practice to call services directly from Views, in part because of the very problem you are seeing--you can wind up with lots of copies of the same service code littered all over your application.
Depending on how tightly interwoven your application is (believe me, I've inherited some pretty nasty stuff, so I know this might be easier said than done), you may find that the easiest thing is to remove all of those various services and replace them by having all your Views dispatch a bubbling event that gets caught at the top level. At the top level, you respond to that event by calling one instance of your service, which is again handled in one place.
You may or may not choose to wrap that single service in a delegate, but once you have your application archtected in a way where the service is decoupled from your Views, you can make that choice at any time.
Would you be able to extend the class and add an event listener in the object's constructor? I don't like this approach but it could work.
You would just have to search/replace the whole project.

Session information in .net (asp and webservice)

I'm making a .net component, resulting in a dll assembly, that will be referenced by an asp.net site, and in another project by an asmx webservice. All code is version 2.0.
The component has a few functions that call an external webservice, which returns an object. One of these functions is for example Login(username, password), which generates amongst others a unique session id for this user. The resulting information and session id are stored in variables in the component.
The issue in the website is:
When the user logs in in the frontend, and my component gets called and checks the login and generates the session id, I want that information in my component to persist when the user browses to another page in the site.
The issue in the web service using my component is:
I don't really care much about session state, but I want the component to just work. If per call a new session id is generated, that's okay.
The combination of the two environments causes the following problem for me:
I can't use the asp.net Session() variable in my component without referencing system.web, which is kinda silly and might not be available in the web service project that includes my component
I can't program my component as a singleton, because then in the website application, it's shared amongst all visitors, overwriting sessions and whatnot
making an array of "session information" in my component and maintaining that is hard to program (when does it get invalidated?) and might not work in a web farm environment
Is there a solution to this situation? Or should I make two instances of my component, one for use in websites, and one for use in web services?
Perhaps I'm not understanding what your asking but why can't you do something like:
Component.Login(user,pass);
Session["Component"] = Component.SessionID
I've created an extra class "Factory" which has a .Create(byref Session as HttpSessionState), that looks if the passed in session object is Nothing, if not, it checks if there is a Component object in it, if so, it uses it, if not, it creates it and adds it to the session.
In the case of the webservice call, the factory gets the Nothing-parameter, so it doesn't check in the session object. It seems to work.
Thanks for your answers!

Request-local storage in ASP.NET (accessible to the code from IHttpModule implementation)

I need to have some object hanging around between two events I'm interested in: PreRequestHandlerExecute (where I create an instance of my object and want to save it) and PostRequestHandlerExecute (where I want to get to the object). After the second event the object is not needed for my purposes and should be discarded either by storage or my explicit action. So the ideal context where my object should be stored is per request (with guaranteed no sharing issues when different threads are serving requests... or processes/servers :) )
Take into account that actual implementation I can do is being made from a HttpModule and is supposed to be a pluggable solution for already written web apps (so the option to provide some state using static/instance variables in Global.asax doesn't look good - I will have to modify Global.asax on every web application).
Cache seems to be too broad for this use. I tried to see whether httpContext.Application (of type HttpApplicationState) is good for me or not, but cannot get whether it is exactly per HttpApplication instance or not (AFAIK you can have several instances of HttpApplications used on different threads and therefore serving several requests simultaneously - then using storage shared between threads will not work correctly; otherwise I would use it because one HttpApplication instance serves exactly one request at a time). Something could be done with storing state on the HttpModule instances if I know for sure that it's exactly bound 1-to-1 with every HttpApplication instance running (but again I need a proof that HttpApplication instance is 1-to-1 with my HttpModule's instance). Any valuable and reputable links on these topics are much appreciated...
Would be great to find something particularly well-suited for per request situation (because otherwise I may end up with something ulgy... probably either some 'broader' scoped storage and some hacks to have different keys in the storage for different requests, OR using a thread-local thing and in this way commit to the theory that IIS/ASP.NET will not ever serve first event from one thread and the second event from the other thread and so on)
try HttpContext.Current.Items collection. It is per Request.
as Fahad had mentioned, HttpContext.Current.Items is the way to go. Be aware that it is per-request and if there are multiple threads serving the request (which sometimes happens - different modules are served by different thread) HttpContext.Current.Items is still shared between them. Some info which you might find helpful

Resources