I've got a search function that on completion, stores data in a generic list (List<ViewModel>). Up until now, I've been assigning the viewmodel value to a static variable to allow me to re-use the data over any page requests that the user may use.
After some reading today though, it seems that the static variable value can be shared across threads, meaning that there is a possibility if I'm viewing the site, that the static variables that contain my search data could be modified by another user.
In the course of my reading I've seen solutions such as adding [ThreadStatic] attribute to the variable, although this not only didn't work, but was roundly dismissed by my further reading as an improper solution.
Others talked about storing variables in HttpContext.Current.Items, but my understanding of that is that it only lasts for a single request.
So, I'm unsure of the best solution here - ideally I 'd rather not make too many fundamental changes to my application, but in short I'd like to be able to share complex objects across many requests? What is the best method of doing this?
Thanks very much
You can store objects that should be persisted in memory for each user individually in a session (HttpContext.Session) object. Your deployment will of course have to support sessions.
Couldn't you just use the OutputCacheAttribute?
Static variable is a bad choise. You can use sessions or ViewState. As for me - the first one is better. As expample
if (Session["tmp"] == null) Session["tmp"]=new DataSet();
DataSet ds = (DataSet)Session["tmp"];
{
...Do something with ds
}
Session["tmp"] = ds;
You can pass this dataset between pages or handlers, but you have to look after the lifetime of your session
Related
I am developing a silverlight application (C#) in which I use a custom control Square and the following global variables.
Square[,] arrSquare = new Square[customRows,customColumns]
List<Square> lstSelection;
List<Square> lstEditable;
List<Square> lstSetSquares;
List<Square> lstCancelled;
The lists are time and again used for updating purposes.
The arrSquare comes in picture only when I have to update my above segregated lists.
I have two options in my mind:
follow my current architecture of having global variables and not using my primary array arrSquare frequently
Use LINQ (on arrSquare converted to locally declared Lists) in methods so that the local objects get destroyed when method gets completed?
If there is any better way, please suggest that.
Please note, the data that I will be dealing with, will be huge.
The question should not be about global vs local variables, it should rather be phrased as "is it better to keep cached copies of calculations or to produce them on the spot as needed?".
Since your dataset will be huge then obviously performing all calculations on demand is a no-go, so that question is easy to answer.
The problem is that I can't find a way to test anything stored in AppState["variableName"] (or App.variableName or HttpContext.Current.Application["variableName"], etc.) inside an if condition. (It only ever sees it as an object, even though I can plot it on the page with Razor as the string variable I thought it was)
So, I can't compare them to say an actual string value.
I've tried ToString(), among countless other attempts, to no avail.
My question is: How can I achieve full functionality with the AppState variable in WebMatrix Web-Pages with C#?
The problem here is that casting is needed, without a space between the cast and the AppState variable. At the time that I posted this question, I was still so new (well, still am really) to C# server side programming. An example of what works is:
if ((string)AppState["myVariable"] == "someString")
{
//do some stuff
}
Also, whether many people like the term "global variable" or not, the AppState variable is, in fact, considered a global variable. This is clearly stated in Mike Brind's Mikesdotnetting article "Tranferring Data Between ASP.NET Web Pages" in the very first line under Application Variables:
"Application variables are also known as global variables." --(Mikesdotnetting)
Also, if you (whoever you are) have not read this article and are either new to WebMatrix or want to see all of the options for transferring data between pages in WebMatrix, please do yourself a tremendous favor and read this easy-to-read, well-written, and highly educational article found here:
http://www.mikesdotnetting.com/Article/192/Transferring-Data-Between-ASP.NET-Web-Pages
I have a multi-user set of ASP.NET web pages. The pages use AJAX update panels so I can avoid updating the screen on every postback.
The lifecycle of each page is as follows:
1. During Page_Load, get relevant data for user from a web service.
2. Store the data (quite large), and a service reference in a static dataset.
3. allow various edits to parts of the data via the screen controls (grids, text boxes)
4. validate data captured via form
5. send updated data back to service
I am doing this using static variables in the Page class itself as follows:
public partial class MyPage : System.Web.UI.Page
{
static xxxx.DataCaptureServiceClient m_Service; //reference to web service
static string m_PersonID = string.Empty; //current person_id page is viewing
static ServResponse m_ServiceResult = null; // reference to our data to edit ( ServResponse is a large data contract)
static string m_SortExpression = "Reference"; //default sort expression for grid
const int PERSONID_COLUMN = 0; //column index in grid for the personID column
const int STATUS_COLUMN = 4; //column index in grid for the application status
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!Page.IsPostBack)
{
// Get new service instance.
m_Service = new xxxx.DataCaptureServiceClient();
ShowDataOnPage(); //get data in m_ServiceResult and bind to a grid on screen
}
}
catch (Exception ex)
{
Response.Redirect("ErrorPage.aspx", false);
}
}
protected void butNext_Click(object sender, EventArgs e)
{
try
{
Page.Validate();
if (Page.IsValid)
{
// Use m_ServiceResult and m_Service to send a packaged submission to the service.
SendDatatoService();
Response.Redirect("TheNextPage.aspx", false);
}
}
catch (Exception ex)
{
Response.Redirect("ErrorPage.aspx", false);
}
}
//Other methods which allow edits to m_ServiceResult
I am wondering if:
A) This is a good way to implement or are there better practices?
B) Should I clear down memory by setting all statics to NULL when I redirect to another page?
C) If I clear down the statics do I risk another user losing data?
UPDATE
I have rewritten removing the statics, keeping the const values and passing data I need around as parameters. Where I need to keep data for updates I have kept the minimal amount I need in session[] variables.
A) No - what happens if a 2nd user opens a page while another one is busy? The static dataset will be overwritten with the 2nd user's data, or is your static dataset somehow differentiating different users' data at the same time?
B) If you absolutely must use statics / server side data, then yes, you should clear them somehow. Guaranteeing that this happens is difficult however. (E.g. if one user just closes their browser)
C) Possibly, but if this is a concern then my question in A) is already going to cause greater problems for you.
As a general answer, storing large amounts of data in memory on the server is generally bad practice. It does not scale well, and opens you up for many different types of errors. Your back-end should be stateless, and there are a number of ways you could achieve that, for example storing the records in a separate table in the DB, which only get finalised (and thus moved into the "real" tables) at the end of the several screens you have.
In direct answer to your questions, without opening a can of worms
A) There is pretty much no worse way to implement data capture
B) Setting variables to null in .NET does not clear down memory.
C) Yes, yes you do. By definition every user is sharing the same static data.
I would keep your service delcarations local, and only use global variables for the constants. You're not saving much by declaring them globally. Also, I would use a const string instead of a static string.
I think the others have answered your questions. My suggestion to help fix your code would be to do some of the following:
m_PersonID should not be static - keep it an instance property/field of the page and have it as static. In fact, class-level variables in code behind can lend itself to fairly unreadable code very quickly. Does it really need to be class-level, or can it be defined in the method where you need it (and just, perhaps, passed as an argument to other methods)?
m_ServiceResult - same for this. Not sure why you have it, and it doesn't need to be static. Try to move it to a method-level variable.
m_SortExpression could just be a const
m_Service - again, I don't see the need for this to be a static. If it's just a proxy to a service, I don't think you need to keep it in memory to avoid unnecessary overhead. I think they problems keeping it static far outweigh the small overhead of having the service client be a method-level variable.
In regards to the static dataset, you may want to consider caching the large result set, if the data is fairly static for the user. Or, really take a look at what you're returning and evaluate if you really need all that data. If you're performing calculations in the code-behind, that's probably not the best place for it. Consider your service layer as the place for those calculations (or the db if you have a lot of your logic in stored procs - not saying that's the place for it, but just acknowledging that it's a possibility).
Also, a dataset is pretty large and bulky. Do you need this structure, or is a set of streamlined entity objects more appropriate? This item pretty much goes with #5, since you really should evaluate how you're retrieving data, storing it and acting upon it. A dataset may be the quick and dirty answer, but usually it's not the efficient answer.
In short, dump the statics and move to private, method-level variables where possible. Try to reduce the amount of data you have coming back from the database. Consider methods that take parameters instead of using class-level and/or global variables.
I hope this helps. Good luck!
Whenever I have to store anything in the session, I have picked up the habit of minimizing the number of times I have to access the session by doing something like this:
private List<SearchResult> searchResults;
private List<JobSearchResult> SearchResults
{
get
{
return searchResults ?? (searchResults = Session["SearchResults"] as List<SearchResult>);
}
set
{
searchResults = value;
Session["SearchResults"] = value;
}
}
My reasoning being that if the object is used several times throughout a postback, the object has to be retrieved from the Session less often. However, I have absolutely no idea if this actually helps in terms of performance at all, or is in fact just a waste of time, or perhaps even a bad idea. Does anyone know how computationally expensive constantly pulling an object out of the session would be compared to the above approach? Or if there are any best practices surrounding this?
Depends on what kind of session storage you are using (for more info, see: here).
If you're using InProc storage, then the performance difference is probably minimal unless you're accessing the object very frequently. However, the local copy doesn't really hurt either way.
it surely depends on your Storage Unit but it's a good approach in either case since it's preventing you from DeSerialization if the storage is not InProc... and even in case of InProc it's preventing from Boxing\UnBoxing... so my vote is in favour of your approach.
I see nothing wrong with your approach. The only drawback is that when some other piece of your (or somebody else's) code changes the session value after your private field has been initialized, your wrapper property will still return the old value. In other words there is no guarantee your property is actually returning the session value except for the first time.
As for performance, I think in case of InProc there is little or no gain. Probably similar to any other dictionary vs variable storage. However it might make a difference when you use other session storage modes.
And if you really want to know you can profile your app and find out;) You can even try something as simple as 2 trace writes and some looped session reads/writes between them.
And here's a read on session storage internals:
http://www.codeproject.com/KB/session/ASPNETSessionInternals.aspx
It depends on size of data to be stored, bandwidth (internet or LAN), scale of application. If data size is small, bandwidth is good enough (LAN), scale is worldwide (like Whitehouse.gov), we should store it on client side (as form hidden parameter). In other situations (data size is very large, bandwidth is very low, scale is small (only group of 3-4 people will use the application), then we can store it in server side (session). There are a lot of other factors to consider them in this decision choice.
Also I would not recommend you to use only one field in session object. Create something like Dictionary (HashMap in Java) in session, and use it as a storage and user should pass the key of this Dictionary to get this data. It is needed to provide user ability to open your web-site in several tabs.
Example of URL, accessing needed search:
http://www.mysite.com/SearchResult.aspx?search_result=d38e8df908097d46d287f64e67ea6e1a
Why use a GlobalClass? What are they for? I have inherited some code (shown below) and as far as I can see there is no reason why strUserName needs this. What is all for?
public static string strUserName
{
get { return m_globalVar; }
set { m_globalVar = value; }
}
Used later as:
GlobalClass.strUserName
Thanks
You get all the bugs of global state and none of the yucky direct variable access.
If you're going to do it, then your coder implemented it pretty well. He/She probably thought (correctly) that they would be free to swap out an implementation later.
Generally it's viewed as a bad idea since it makes it difficult to test the system as a whole the more globals you have in it.
My 2 cents.
When you want to use a static member of a type, you use it like ClassName.MemberName. If your code snippet is in the same class as the member you're referring (in this example, you're coding in a GlobalClass member, and using strUserName) you can omit the class name. Otherwise, it's required as the compiler wouldn't have any knowledge of what class you're referring to.
This is a common approach when dealing with Context in ASP.Net; however, the implementation would never use a single variable. So if this is a web app I could see this approach being used to indicate who the current user is (Although there are better ways to do this).
I use a simillar approach where I have a MembershipService.CurrentUser property which then pulls a user out from either SessionState or LogicalCallContext (if its a web or client app).
But in these cases these aren't global as they are scoped within narrow confines (Like the http session state).
One case where I have used a global like this would be if I have some data which is static and never changes, and is loaded from the DB (And there's not enough of the data to justify storing it in a cache). You could just store it in a static variable so you don;t have to go back to the DB.
One a side note why was the developer using Hungarian notation to name Properties? even when there was no intellisense and all the goodness our IDEs provide we never used hungarian notation on Properties.
#Jayne, #Josh, it's hard to tell - but the code in the question could also be a static accessor to a static field - somewhat different than #Josh's static helper example (where you use instance or context variables within your helper).
Static Helper methods are a good way to conveniently abstract stateless chunks of functionality. However in the example there is potential for the global variable to be stateful - Demeter's Law guides us that you should only play with state that you own or are given e.g. by parameters.
http://www.c2.com/cgi/wiki?LawOfDemeter
Given the rules there occasional times when it is necessary to break them. You should trade the risk of using global state (primarily the risk of creating state/concurrency bugs) vs. the necessity to use globals.
Well if you want a piece of data to be available to any other class running in the jvm then the Global Class is the way to go.
There are only two slight problems;
One. The implmentation shown is not thread safe. The set... method of any global class should be marked critical or wrapped in a mutex.
Even in the niave example above consider what happens if two threads run simultaniously:
set("Joe") and set("Frederick") could result in "Joederick" or "Fre" or some other permutation.
Two. It doesnt scale well. "Global" refers to a single jvm. A more complex runtime environment like Jboss could be runnning several inter communicating jvms. So the global userid could be 'Joe' or 'Frederick' depending on which jvm your EJB is scheduled.