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!
Related
EDIT (clarifying my question): Is there an API or method with which we can use the Out Of Process Asp.NET State Service from our own code or is that proprietary?
We are looking into implementing a custom session state module that re-uses the components of the module that comes stock with asp. Our main goal is to just prevent session locking (without changing the session state mode to ReadOnly). Is this possible?
One of the key pieces that we would like to make work is to be able to use the same Out of Proc Session storage provider (The ASP State service) that is used internally by .NET as we have a load-balanced environment that doesn't use sticky sessions.
I have dug into the code over in the reference source, and my findings are below. I am hoping somebody has a different utility that could potentially be used to integrate a custom session state module the ASP State Service.
The default session Module is System.Web.SessionState.SessionStateModule. This is a Sealed class. This class appears to be the only class that uses the SessionStateMode.StateServer enum value (which is specified in the web config).
When this flag is set, the module sets the _store variable to be a new System.Web.SessionState.OutOfProcSessionStateStore which is a Friend Sealed class.
I had initially had a few thoughts on how to do this, and because of the modifiers on the classes above I was unable to do these. Are there other approaches that could be taken?
Instantiate a new System.Web.SessionState.SessionStateModule and reference the _store variable. This did not work, obviously because the _store variable is private.
I tried creating a class which inherits from System.Web.SessionState.SessionStateModule but obviously since it is sealed that does not work.
Looked at copying the code from the .NET framework code. Realized that would be a very poor decision.
Are there any options I am missing?
I would recommend you reading this topic: I just discovered why all ASP.Net websites are slow, and I am trying to work out what to do about it.
It provides some starting points and info on the session topic, especially locking problem.
If you look for custom implementation of session module you can look here:
http://www.codeproject.com/Articles/11712/Custom-session-state-management-in-ASP-NET
I am in a situation where requirement is to keep an application level object in web api which can be accessed by all requests. I know one can use HttpContext.Current but that is not required since HttpContext is only for the liftime of request. I need a solution where i can keep an object that all requests can access and update as required.
Use a static class to hold your application level objects. static classes and static data members are created once for the application lifetime and all ASP.NET requests can access them.
I learnt it the hard way. Some time back, I mistakenly created a static field to hold customer-specific database connection string, in a ASP.NET Web API project and it became a mess. On each customer's login it was being set (overridden) in the code and the requests from the previously logged customers were using this newly set static SQL connection string for their queries. It was an embarrassing situation when customer's inadvertently saw each other's data.
You could use SessionState (per session).
I.e.
Session["YourDataKey"] = ApplicationLevelObject;
And then check the session state variable on each request that requires it.
However if you require the object for longer, I.e. every single user session, then I would suggest persisting your object to a database. You could use an ORM such as Entity Framework.
Cheers
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.
I was looking through an old project and wanted to see if anyone had a suggestion on how to hide certain methods from being called by various layers. This was a 3 tier project, webapplication -> web service -> database
In the application there is a User object for example. When a User was being updated, the webapplication would create a User object and pass it to the webservice. The webservice would use the DataAccessLayer to save the User object to the database. After looking at this I was wondering if instead I should have made a Save method in the User class. This way the service and simply call the Save on the User object which would trigger the db update.
However doing it this way would expose the Save to be called from the webapplication as well, correct? Since the webapplication also has access to the same User object.
Is there anyway around this, or is it better to avoid this altogether?
There is a separation of concerns by keepeing the User object as object that only holds data with no logic in it. you better keep it separated for the following reasons:
As you stated, it is a bad practice since the Save' functionality will be exposed to other places/classes where it is irrelevant for them (This is an important for programming generally).
Modifying the service layer - I guess you are using WCF web service as you can transfer a .NET object (c#/VB) to the service via SOAP. If you put the saving logic in the 'User' object, you can't replace it another webservice that receives a simple textual data structures like JSON or XML or simply doesn't support .NET objects.
Modifying the data storage layer - If you want, for example, to store the data inside a different place like other database such as MongoDB, RavenDB, Redis or what ever you want, you will have to reimplement each class that responsible for updating the data. This is also relevant for Unit Testing and Mocking, making them more complicated to interrogate.
I'm having trouble figuring out how to access a cookie from a compiled object. I'm trying to make a compiled (DLL) object that will check the users cookie and then compare that to a database to confirm they have the correct access.
I can pass in the cookie info fine and the component will work, but I'm trying to have the component check the users cookie as well. I'm not even sure what object to use. I've been searching all weekend and I've seen references to httprequest, httpcookie, cookie, and cookiecollection.
I can look up cookie values on the page itself using Request.Cookies("inet")("user_id") but this doesn't work in the component.
Objects (App_Code/ compiled dlls) can only access Request via the static HttpContext.Current object
HttpCookie cookie = HttpContext.Current.Request.Cookies["CookieName"];
(If it's not called from a web app, HttpContext.Current is null, so you may want to check for that when running in unit testing)
(If this isn't App_Code, you'll need to reference System.Web)
If the component is a separate DLL from your web app you'd need to pass in a reference to the Request object.
That said why not just read/check the cookie value in your ASP.NET code before calling into your DLL. It's not such a good idea to have your business logic coupled to your web tier like this.