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.
Related
We have a web app that displays data from a couple of different web apps. In each of those web apps, the culture is configurable (it is set by a company admin at the app level for all users, not per user).
In our web app, we need to display the data from each of the other web apps, in the culture configured for that app. The only good news is that currently we don't display "mixed" data from both apps, in a single view. And generally, a controller and all of its actions will only work with data from a single app (meaning that all actions from that controller will use the same culture).
There are several things I'm struggling with:
Does .NET Core really not honor setting culture like in the old days? I've tried it but it doesn't work (unless I'm setting it in the wrong place in the pipeline).
Thread.CurrentThread.CurrentCulture = firstWebAppCultureInfo;
Thread.CurrentThread.CurrentUICulture = firstWebAppCultureInfo;
Does it really only check these to find and set the culture?
QueryStringRequestCultureProvider
CookieRequestCultureProvider
AcceptLanguageHeaderRequestCultureProvider
I know I could write a custom provider, but that wouldn't seem to help me. We already get the various culture settings for the apps, from a database and store them in session.
My first thought was to write out a Culture Cookie every time the user hits a controller. I'd read the culture from session and write the cookie. But there are a couple of issues I see with this.
Issue 1: If I write the cookie out in the controller action, it doesn't "take affect" the first time it is changed from one culture to another. Obviously the cookie has already been read and the culture has already been set for that request. I'm too late in the pipeline to do that.
I tried writing the cookie out in the constructor of the controller (or constructor of a base controller) but HttpContext is not yet set at that point (it is null).
I have worked a bit with Filters and I will write an Action Filter that writes the cookie to see if that works, but see Issue 2.
Issue 2: Another issue would surface if the user opened multiple instances of their browser. The last culture written will "win" I suspect. So if a user is displaying data in Culture fr-FR in one browser and en-US in another instance of a browser and navigates to a controller/view that writes that en-US cookie, and then from the other browser instance navigates to a page that is supposed to use the fr-FR culture, the user would get the en-US setting from the cookie and that's not acceptable.
I don't really want to use the QueryStringRequestCultureProvider, because having that show up in the url is ugly.
I'm definitely not an expert in this area.
What am I missing?
How would you all implement this?
Thanks in Advance.
UPDATE
I created an ActionFilter and TypeFilterAttribute that allows me to pass a parameter into the ActionFilter. Using the parameter I can decide which key to read from Session to give me the culture setting I've stored for each web app.
From there I can mark each controller with that attribute and the appropriate parameter to tell the action filter what culture to use (remember we don't mix data, so each controller displays views that show data from only one of the two web apps, not both).
In the ActionFilter I can look up the culture string from session and do the following and it works:
var ci = new CultureInfo(this.cultureSetting);
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
While that is encouraging, it feels hacky. So please comment on the solution...
I'd like to find a way to do all of this in a BaseController or somewhere, so I wouldn't need to put attributes on all of our controllers.
But whatever I've tried in a base controller seems like it is either:
a) too late in the pipeline to set the culture for that request, or
b) too early in the pipeline to get access to httpcontext.
Thoughts? Ideas?
UPDATE 2
I guess overriding OnActionExecuting in my base controller lets me do the same things as the ActionFilter...
So I guess I have a solution, but if anyone has a better idea, I'm listening.
We decided to go with an ActionFilter for our solution, so we can mark Controllers and/or Actions with an Attribute that indicates which app we are getting data from, so we can apply that app's culture setting...
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'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!
In my web application, I do something like this to read the session variables:
if (HttpContext.Current.Session != null && HttpContext.Current.Session["MyVariable"] != null)
{
string myVariable= (string)HttpContext.Current.Session["MyVariable"];
}
I understand why it's important to check why HttpContext.Current.Session["MyVariable"] is null (the variable might not have been stored in the Session yet or the Session has been reset for various reasons), but why do I need to check if HttpContext.Current.Session is null?
My understanding is that the session is created automatically by ASP.NET therefore HttpContext.Current.Session should never be null. Is this assumption correct? If it can be null, does it mean I should also check it before storing something in it:
if (HttpContext.Current.Session != null)
{
HttpContext.Current.Session["MyVariable"]="Test";
}
else
{
// What should be done in this case (if session is null)?
// Is it possible to force the session to be created if it doesn't exist?
}
Yes, the Session object might be null, but only in certain circumstances, which you will only rarely run into:
If you have disabled the SessionState http module, disabling sessions altogether
If your code runs before the HttpApplication.AcquireRequestState event.
Your code runs in an IHttpHandler, that does not specify either the IRequiresSessionState or IReadOnlySessionState interface.
If you only have code in pages, you won't run into this. Most of my ASP .NET code uses Session without checking for null repeatedly. It is, however, something to think about if you are developing an IHttpModule or otherwise is down in the grittier details of ASP .NET.
Edit
In answer to the comment: Whether or not session state is available depends on whether the AcquireRequestState event has run for the request. This is where the session state module does it's work by reading the session cookie and finding the appropiate set of session variables for you.
AcquireRequestState runs before control is handed to your Page. So if you are calling other functionality, including static classes, from your page, you should be fine.
If you have some classes doing initialization logic during startup, for example on the Application_Start event or by using a static constructor, Session state might not be available. It all boils down to whether there is a current request and AcquireRequestState has been run.
Also, should the client have disabled cookies, the Session object will still be available - but on the next request, the user will return with a new empty Session. This is because the client is given a Session statebag if he does not have one already. If the client does not transport the session cookie, we have no way of identifying the client as the same, so he will be handed a new session again and again.
The following statement is not entirely accurate:
"So if you are calling other functionality, including static classes, from your page, you should be fine"
I am calling a static method that references the session through HttpContext.Current.Session and it is null. However, I am calling the method via a webservice method through ajax using jQuery.
As I found out here you can fix the problem with a simple attribute on the method, or use the web service session object:
There’s a trick though, in order to access the session state within a web method, you must enable the session state management like so:
[WebMethod(EnableSession = true)]
By specifying the EnableSession value, you will now have a managed session to play with. If you don’t specify this value, you will get a null Session object, and more than likely run into null reference exceptions whilst trying to access the session object.
Thanks to Matthew Cosier for the solution.
Just thought I'd add my two cents.
Ed
If your Session instance is null and your in an 'ashx' file, just implement the 'IRequiresSessionState' interface.
This interface doesn't have any members so you just need to add the interface name after the class declaration (C#):
public class MyAshxClass : IHttpHandler, IRequiresSessionState
In my case ASP.NET State Service was stopped. Changing the Startup type to Automatic and starting the service manually for the first time solved the issue.
ASP.NET Technical Articles
SUMMARY: In ASP.NET, every Web page
derives from the System.Web.UI.Page
class. The Page class aggregates an
instance of the HttpSession object for
session data. The Page class exposes
different events and methods for
customization. In particular, the
OnInit method is used to set the
initialize state of the Page object.
If the request does not have the
Session cookie, a new Session cookie
will be issued to the requester.
EDIT:
Session: A Concept for Beginners
SUMMARY: Session is created when user
sends a first request to the server
for any page in the web application,
the application creates the Session
and sends the Session ID back to the
user with the response and is stored
in the client machine as a small
cookie. So ideally the "machine that
has disabled the cookies, session
information will not be stored".
I want to implement an ISAPI filter like feature using HttpModule in IIS7 running under IIS Integrated Request Processing Pipeline mode.
The goal is to look at the incoming request at the Web Server level, and inject some custom HttpHeaders into the request. (for ex: HTTP\_EAUTH\_ID)
And later in the page lifecycle of an ASPX page, i should be able to use that variable as
string eauthId = Request.ServerVariables["HTTP\_EAUTH\_ID"].ToString();
So implementing this module at the Web Server level, is it possible to alter the ServerVariables collection ??
HttpRequest.ServerVariables Property is a read-only collection. So, you cannot directly modify that. I would suggest storing your custom data in httpcontext (or global application object or your database) from your httpmodule and then reading that shared value in the aspx page.
If you still want to modify server variables, there is a hack technique mentioned in this thread using Reflection.
I believe the server variables list only contains the headers sent from the browser to the server.
You won't be able to modify either the HttpRequest.Headers or the HttpRequest.ServerVariables collection. You will however be able to tack on your information to any of:
HttpContext.Current.Items
HttpContext.Current.Response.Headers
Unfortunately, Request.Params, Request.QueryString, Request.Cookies, Request.Form (and almost any other place you'd think of stuffing it is read only.
I'd strongly advise against using reflection if this is a HttpModule you're planning on installing into IIS 7. Given that this code will be called for (potentially) every request that goes through the web server it'll need to be really fast and reflection just isn't going to cut it (unless you have very few users).
Good luck!