I am building an ASP.NET application using nhibernate and I implemented the session per request architecture. Each request I am opening a session, using it, then closing it. I am using one large object across several views and I am storing the object in user session cache so it maintains state for them across several different pages. The users do not want to have to save their changes on each page, they want the ability to navigate between several pages making changes, then commit them to the DB. This works well except for when the users try to hit a page that triggers lazy loading on the proxy object (which fails due to the session per request design closing the nhibernate session in the previous request). I know that turning lazy loading off would fix it; however, that is not an option due to the performance issues it would cause in other areas. I have tried changing the session per request design but have had no luck since I do not know when it is "safe" to close the nhibernate session.
Has anyone else done anything similar to this or have any advice?
Thanks in advance!
Keeping any objects in user session - the server session, server resource is not the best approach. Just imagine, that accidently your application will be very very successful... and there will be many users... therefore many sessions == many resources.
I would suggest (based on some experience), try to re-think the architecture to avoid session. Extreme would be to go to single page application... but even some async during "...navigation among several pages..." will be better.
All that will mean, that:
we passs data to client (standard ASP.NET MVC way with rendered views or some Web Api JSON)
if needed we send data back to server (binding of forms or formatting JSON)
In these scenarios, standard NHiberante session will work. Why? Because we "reload and reassign" objects with standard NHibernat infrastructure. That would be the way I suggest to go...
But if you want to follow your way, then definitely check the merge functionality of NHibernate:
9.4.2. Updating detached objects
9.4.3. Reattaching detached objects
19.1.4. Initializing collections and proxies
Some cites:
In an application with a separate business tier, the business logic must "prepare" all collections that will be needed by the web tier before returning. This means that the business tier should load all the data and return all the data already initialized to the presentation/web tier that is required for a particular use case. Usually, the application calls NHibernateUtil.Initialize() for each collection that will be needed in the web tier (this call must occur before the session is closed) or retrieves the collection eagerly using a NHibernate query with a FETCH clause or a FetchMode.Join in ICriteria. This is usually easier if you adopt the Command pattern instead of a Session Facade.
You may also attach a previously loaded object to a new ISession with Merge() or Lock() before accessing uninitialized collections (or other proxies). No, NHibernate does not, and certainly should not do this automatically, since it would introduce ad hoc transaction semantics!
Related
i've a question regarding handling of user logon while porting an application to MVC:
in the "old" WebForm days, developers simply used the SessionState object to set a user to logged-on, by -for example- simply putting the userobject into the SessionState (and this userobject holds simple properties like name/lastlogon/etc.)
this stuff worked very well for us, and i've seen lots of applications doing it that way
yes, i know there is this MembershipProvide-thingy, but i've never used it
Now, in MVC, everybody tells me that "using SessionStat for this is bad" and "apps built that way are flawed in design" and that "there are tons of security risks" and so on.
I've used this method because it worked for the app very reliable, it was simple to implement and it covered all stuff we need.
(Sure, there is the thing with recycling web worker process and emptying the session - but thats not a problem in our case, since the app runs for each country on a dedicated machine)
I've read tutorials, telling me to put that stuff in the DB and -attention- doing a request to the DB to check if the user is logged in, per EACH request? But: Under no circumstances, this is a doable way since i want to keep DB requests on a minimum.
So my question is:
A) whats wrong using this way also in the new MVC app?
B) whats the best way to handle this scenario in a newly built MVC app?
Regarding the session-in-DB-idea: instead of doing this, i'd rater setup an additional service, like a "session-manager" thats get query over the network, but such simple requests should not go to the DB - isn't that a good idea?
Any idea, hint /etc. is highly appreciated since this scenario is really confusing me :-X
A)
A fundamental principal of the asp.net mvc framework is that its stateless. Data is passed around using http requests and sent to the views in viewmodels. Web forms tried to maintain state with viewstate etc thats why you would have seen the logged in user in session approach. Thats not to say session shouldnt be used completely in asp.net mvc, there are some circumstances when it can be useful. Like maintaining a 3 step form process that has to be persisted on the last step. But generally we already have a recommended way to handle the user logins, and thats forms authentication
B)
For accessing the user object, you can create a custom identity implementing the IPrincipal interface and add the required user fields you need. Then set the custom identity in a global filter and access it in your action results. Regarding not wanting to query the database for every request, why dont you just call it for the initial request, then cache the result until the user is updated where you then can reload the object and set it in the custom identity again.
What is the best way of persisting a collection of objects across multiple sessions in ASP.Net MVC? I'd like to have a collection in which many users can "take the next X" from the collection - e.g. process the next X records that someone else isn't using - so it will have to persist in the service layer across multiple sessions of the the application.
It's an internal website, so there's no worry of users getting to things they're not supposed to, it will only be used by those who should have access to the data.
Considering using a static object in the service layer, but I'm not sure how/whether that will persist across sessions, or am I approaching this entirely the wrong way and should I be using the database to store the information instead?
Yes, this definitely seems like a concern for the database - storing this in memory (ala your static variable approach) does not allow load balancing and the information will be lost each time IIS recycles the App Pool.
I would rather go the DB way. Always consuming from the same place and avoid having to keep track with multiple lists. You can get the Next X from the DB and flag them and move to the next ones
I am using the TempData in order to preserve my model in when using a RedirectToAction. It works fine, but I have a nagging feeling that it might not be the right thing to do. I really try to avoid using Session data, and I've read that TempData uses the Session. Is it safe to use? Are there issues which might arise in using it in a load balanced environment?
Trivia Question: "Is It Safe?"-- name the movie.
Yes, TempData is backed by session storage, so if you are in a load balanced environment extra care must be taken when using it (sticky sessions, persistent session state, etc).
TempData has been the de-facto choice when using the PRG pattern, and is what it was designed for.
As to whether it's the right thing to do... it depends on your use case!
PS Marathon Man.
Well, I would argue that it depends. If you handle lot of traffic with load balancers and multiple front end server, then session objects is something to avoid because it could degrade performance and make hotizontal scaling difficult (on farm request doesn't come always to same web server).
TempData is short-lived, and if you don't put there lot of objects there and think twice about whole architecture, I think then it's safe. There's lot of sites that use it extensively and don't have problems with it (I worked on shared and dedicated hosted sites with up to avarage 50-70k visitors/day that use session, often with web and db on same server).
I would go, whenever possible, for a fully stateless approach. It's more scalable and is not affected by problems with individual servers. Typically, you can just use a cookie (properly secured against tampering) to identify the user and pull the data from the database every time.
Besides that, I also suggest you to evaluate whether you can use View instead of RedirectToAction. This:
TempData["model"] = model;
return RedirectToAction("SomeAction");
Can be replaced with:
return View("SomeAction", model);
Of course assuming "SomeAction" is a valid view that is accessible from the current controller (it's either a view in the same ctrl or one defined in Shared) and that it's not just an intermediate action that redirects to another one.
Session state can work in a clustered environment, providing that one of two things happens
Your load balancer supports "sticky" sessions (i.e. all requests in a given session are routed to the same machine)
You configure the session provider to use an out of process session provider, you can use either the ASP.NET State Service or the SQL Session State Provider
The question of whether you should use tempdata or not is a different question altogether. I would argue that there is usually a way around it. If you are trying to avoid a hit to the database to reload an object that one action has already loaded, look at using a cache instead.
I have limited the use of TempData to pass model object validation message between views and action. I haven't looked into the usage of Tempdata from security perspective but following SO thread discuss the same : HttpContext.Items with ASP.NET MVC. See the last few thread comments and related discussions.
I have some big entities which are frequently accessed in the same session. For example, in my application there is a reporting page which consist of dynamically generated chart images. For each chart image on this page, the client makes requests to corresponding controller and the controller generates images using some entities.
I can either use asp.net's session dictionary for "caching" those entities or rely on nhibernate's second level cache support with using cached queries for example.
What is your opinion?
By the way I will use shared hosting, is nhibernate's second level cache hosting friendly?
Thanks.
I think you should use NHibernate's cache. If user makes distinct request to get each entity one by one then you probably should use different NHibernate ISession implementations to get them (bacause of session per web request strategy).
Also when using Nhibernate cache you won't have troubles with concurrency issues - it will handle them for you.
Be aware of caching an entity (from the session you loaded it from) in a static variable, that is then accessed by another session (eg, pulled from the cache system you made).
Entity instances are tied to a Session remember, so you shouldn't mix and match instances across Session boundaries.
I've solved this before by creating a light version of the class (that is not NH Session aware) and caching that basic class instead.
Alternatively, use the 2nd level cache, which doesn't have this problem.
I have been working with entity framework and ASP MVC for a while. I have stored the entity object in the HttpContext.Current.Session in order to use the same session at all times. Now I have encountered some problems and I am wondering if this may have been a bad idea and if so, how should I do it otherwise.
The problem I have now is that the entity object caches data and that one user cannot see changes that the other user has done.
The session is basically a hash table-like structure that is specific to a user. If you want to store data that can be seen by all users of the system, you either want to use the Application scope or caching.
This article from MS covers the different options for state management, including session and application:
http://msdn.microsoft.com/en-us/library/75x4ha6s.aspx
Caching is slightly different in that it allows you to do things like set expiration. If you don't need this kind of functionality, I would recommend sticking with application state. Article on caching from MS:
http://msdn.microsoft.com/en-us/library/6hbbsfk6(VS.71).aspx
The problem with storing Entities in memory between requests / sessions or whatever is that you have to be very careful if you have a new ObjectContext for each request / session whatever, because and entity can only be attached to one ObjectContext at a time, and can be easy to forget to detach (between requests in the same session) or to correctly share an object (between concurrent requests in different sessions).
Check out this Tip for clues on how to cache data between requests / users / sessions etc.
Hope this helps
Alex
By the book you would want your object context exist the shortest time possible.
so you create a context, grab some data, return your view to client.
and dispose everything.
Start caching when your db can't handle your load.