Static variables in web applications - c#

Can I use static variables in my web application ? what are the alternatives to static ? When I use static variables in pages and more than one user use the application, it makes conflict data (incorrect data).
What are the limits of using static members?
Are static members shared in memory?

Consider storing your shared variables in the HttpApplication object or in the Cache object.
However, if you are trying to store values for each user separately, you should store those values in a Session variable.
Static variables inside Asp.Net are shared in the memory space of the w3svc.exe process and are NOT thread-safe. They can be accessed and modified by any user of the application. This could lead to unwanted modifications, unless you write your own lock mechanism around the storage of those values.
You should try a syntax like:
Application["KEY"] = value;
to store shared application-wide data and
Session["KEY"] = value;
to store data on a per-user basis
You can use the WebCache object to store data in the web server's memory with expiration conditions. Syntax for that looks similar to:
Page.Cache.Insert("KEY", "VALUE", null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
More on the syntax of managing the WebCache object can be found at:
http://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx

Just to add to what #Jeff Fritz has said, an IIS application creates an AppDomain in which your assemblies are loaded. Just like the rules of a normal windows application, if a class such as
public static class Something
{
public static string SomeString { get; set; }
}
...then only a single Something.SomeString property is available per AppDomain. The W3SVC process manages the AppDomain, but the is no guaruntee of thread safety (as an AppDomain can be service multiple requests). If you are using read-only static properties, it's probably fine (such as reading config values). If you are making mutable properties that change through the lifetime of a request, its better to use one of the storage mechanisms detailed in other questions here.

Related

Use static class in ASP.NET Web API

I am posting this question using an automatic translation.
Please forgive any grammatical errors.
I have built an application using the .NET framework and the ASP.net Web API.
I have split the virtual path for each customer region within a site running on IIS and copied the same binary to run as separate applications.
The applications run in the same application pool.
Recently, some customers have been making a very large number of requests in a matter of minutes.
(I suspect a glitch in the system on the customer's end).
I am thinking of adding a static class to my current application that keeps track of the number of requests per customer in a given time period and blocks them if the threshold is exceeded.
From past StackOverFlow articles I have found that "information in the static class is lost if the application pool is recycled", but I have determined that this is not a problem in this case.
For my purposes, I only need to be able to retain information for a few minutes.
However, I still have a few questions that I can't find answers to, so I'd like to ask you all a few questions.
Even if the same binary is running in the same application pool, will the static class information be kept separately for different applications?
Will the static constructor of a static class be executed even after the application pool is recycled?
Is there a problem if I reference a field in Global.asax from within a static class?
Is there a problem with referencing the contents of web.config from within a static class?
Attached below is the source of my experimental implementation.
I plan to call the static method "ExcessiveRequestCheck.isExcessiveRequest" of this static class after the Web API receives the request and identifies the user ID.
Any advice would be sincerely appreciated.
P.S.
I understand that this approach does not work well in a load balancing environment. Currently my system only runs on one virtual machine. If you are moving to the cloud or deploying a load balancer, you will probably need a different approach than this one.
public static class ExcessiveRequestCheck
{
private static Dictionary<string, ExcessiveRequestInfo> dicExcessiveRequestCheckInfo = new Dictionary<string, ExcessiveRequestInfo>();
private static object initLock = new object();
private static object dicExcessiveRequestCheckInfoLock = new object();
//If possible, I want this process to be a static constructor
public static Dictionary<int, int> dicExcessiveRequestSkipConditions
{
get
{
lock (initLock)
{
if (ExcessiveRequestCheck._dicExcessiveRequestSkipConditions == null)
{
//if possible, I want to set this value from Web.config.
ExcessiveRequestCheck._dicExcessiveRequestSkipConditions = new Dictionary<int, int>() {
{ 5, 3 }, { 15, 5 }, { 45, 10 }, { 120, 20 }
};
}
return ExcessiveRequestCheck._dicExcessiveRequestSkipConditions;
}
}
}
private static Dictionary<int, int> _dicExcessiveRequestSkipConditions = null;
public const int BUFFER_CLEAR_MINUTES = 5;
public static bool isExcessiveRequest(string userId)
{
ExcessiveRequestCheck.refreshExcessiveRequestCheckInfo();
lock (ExcessiveRequestCheck.dicExcessiveRequestCheckInfoLock)
{
if (ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.ContainsKey(userId) == false)
{
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.Add(userId, new ExcessiveRequestInfo() { countRequest = 1 });
return false;
}
bool doSkip = false;
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].countRequest++;
foreach (KeyValuePair<int, int> pair in ExcessiveRequestCheck.dicExcessiveRequestSkipConditions)
{
if (ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].lastRequesttTime.AddSeconds(pair.Key) > DateTime.Now)
{
if (ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].countRequest > pair.Value)
{
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].wasRequestSkip = true;
doSkip = true;
}
}
}
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[userId].lastRequesttTime = DateTime.Now;
return doSkip;
}
}
public static void refreshExcessiveRequestCheckInfo()
{
lock (ExcessiveRequestCheck.dicExcessiveRequestCheckInfoLock)
{
var keyList = ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.Keys;
foreach (string key in keyList)
{
if (ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.ContainsKey(key))
{
var value = ExcessiveRequestCheck.dicExcessiveRequestCheckInfo[key];
if (value.lastRequesttTime.AddMinutes(BUFFER_CLEAR_MINUTES) < DateTime.Now)
{
if (value.wasRequestSkip)
{
//this NLog instance was created in Global.asax.cs
WebApiApplication.logger.Fatal("skip request! user id=" + key);
}
ExcessiveRequestCheck.dicExcessiveRequestCheckInfo.Remove(key);
}
}
}
}
}
}
class ExcessiveRequestInfo
{
public DateTime requestStartTime { get; set; } = DateTime.Now;
public DateTime lastRequesttTime { get; set; } = DateTime.Now;
public int countRequest { get; set; } = 0;
public bool wasRequestSkip { get; set; } = false;
}
Your questions
Even if the same binary is running in the same application pool, will the static class information be kept separately for different applications?
Yes, they are separate
Will the static constructor of a static class be executed even after the application pool is recycled?
Yes, the static constructor is guaranteed to be called before any of the static methods are executed
Is there a problem if I reference a field in Global.asax from within a static class?
No more than accessing it from anywhere else
Is there a problem with referencing the contents of web.config from within a static class?
No more than accessing it from anywhere else
Your general approach
DoS
If you're trying to mitigate a denial-of-service attack or credential stuffing attack, your approach probably won't work, since requests to your service will still result in load being added to your server, and if they are performing a credential stuffing attack, it'll fill up your dictionary with millions of entries and possibly cause your application to crash.
If you want to mitigate a denial-of-service attack effectively, you will probably need a more network-oriented solution, such as a smart firewall or a WAF.
Rate limiting
If on the other hand you are attempting to throttle specific users' activities (i.e. rate limiting), again, your approach probably isn't the greatest, because it does not support load balancing-- your list is held in in-process memory. For per-user rate limiting you will probably need to track user activity in a central data store accessible to all of your servers.
Static constructors
As a general rule, you should try to avoid static constructors, or keep them very simple, as a failure in a static constructor will cause your entire application to fail to start. Be careful!
even if the same binary is running in the same application pool, will the static class information be kept separately for different applications?
If by different applications, you mean separate web sites? yes, it will be kept separate to each web site you have running for that app pool.
Will the static constructor of a static class be executed even after the application pool is recycled?
Hum, that's a bit confusing. The constructor will only be executed if you call the class and that given constructor. Since there is never a instance of the class created, then the "initialize/new" event is never used nor triggered. So, any method with parameters will run and work fine - including the constructor. I would suggest that there is not some "event" that gets triggered on first use - it would not and does not make sense in the context of a static class, since you never create an instance. So, if you have some methods with parameters then fine.
So, constructor in the context of new instance of the class makes no sense - (did not even think that is possible with static).
There is no concept of "new" event that triggers, so I fail to see how this issue can ever matter.
Is there a problem if I reference a field in Global.asax from within a static class?
Well, values in that class are global to ALL users. But, those values can go out of scope just about any old time you please. As a result, ZERO use of public members is practial. While a app-pool re-start will re-set those class values? They can go out of scope just about any old time. They are global to all and every user. So, persisting values, or attempting to persit values in a static class is NOT a viable choice for production code. You can have methods (code) in that class, but any public persisting values really can't be relied upon to persist correctly. I'm not 100% sure, but even just general .net garbage collection would likely cause a re-set.
If you need this information to persist, then you can't use static, you have to create a instance of that class and persist it in session(). And session is per user.
A static class public values will apply to EVERY user - not just the current user. In effect those values are global to all users - but without any real ccontrol or garrutee that the values will persit - you have no control over this and thus you can't adopt this concpet and design for any system of practial value.
Is there a problem with referencing the contents of web.config from within a static class?
Reading values? No problem. Update or modify values? - a MASSIVE different issue. You modify web.config, that will trigger a app pool restart.
So, you free to read any file - text files, xml or whatever, and that includes web.config. As long as you not modify such files, then no problems.
The main issue here?
It simple not practical to assume, or build a design in which public static class values are to persist. The ZERO control you have when such values may go out of scope is somthing you have ZERO control over, and thus such designs can't use nor rely on values persisting.
And of course on many web hosting systems? They are now adopting cloud computing. This means from one post back to the next, you might be using a different server, and again, that means such values can't persist in memory, since from one post-back to the next, or one web service call to the next? You may well be hitting a different server anyway (and they don't share memory) (so, this suggests say using SQL server based sessions, or at the very least persisting such values in a database).
In fact, if you need such persisting values and data? Then use a database. The WHOLE idea of web based software is you do NOT have state between post-backs. And you are attempting to go even down a worse road, but hope on a wing and a prayer that some global values "might" and "sort of" and "maybe" will persist between calls to the web site.
Answer:
You really can't do this with any realm of reliably.
So, most of your questions don't really matter. What matters is these values are to persist, and you can't rely on such a design. If you need some persisting values, then you have to adopt a system and design that supports that concept (viewstate, cookies, or session()).
Now, I suppose you can give this a try, and then come back with a detailed report and how your experience turned out. But, there are too many pit falls, and without any code or system control over persisting values in memory, I don't think I would go down this road.
In web land, it makes next to no sense to have public variables that you attempt to persist in a static class. You can have code, you can have cool methods, you can use session(). But, the concept of persisting values in static class is a design choice that does not make sense, and can't be relied upon.
Web software is assumed to be state-less, and that VERY much is the assumption you have to make in regards to a static class, or in fact general use of such code.

How to avoid passing a context reference among classes

Dynamics CRM 2011 on premise. (But this problem exists in many situations away from Dynamics CRM.)
CRM plugins have an entry point:
void IPlugin.Execute (IServiceProvider serviceProvider)
(http://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.iplugin.execute.aspx)
serviceProvider is a reference to the plugin execution context. Anything useful that a plugin does requires accessing serviceProvider, or a member of it.
Some plugins are large and complex and contain several classes. For example, I'm working on a plugin that has a class which is instantiated multiple times. This class needs to use serviceProvider.
One way to get access to serviceProvider from all the classes that need it would be to add a property to all those classes and then to set that property. Or to add properties for the parts of serviceProvider that each class needs. Either of these approaches would result in lots of duplicate code.
Another approach would be to have a global variable in the scope of the thread. However, according to http://msdn.microsoft.com/en-us/library/cc151102.aspx one "should not use global class variables in plug-ins."
So what is the best way to have access to serviceProvider without passing it around everywhere?
P.S. If an example helps, serviceProvider provides access to a logging object. I want almost every class to log. I don't want to pass a reference to the logging object to every class.
That's not quite what the warning in the documentation is getting at. The IServiceProvider isn't a global variable in this context; it's a method parameter, and so each invocation of Execute gets its own provider.
For improved performance, Microsoft Dynamics CRM caches plug-in instances. The plug-in's Execute method should be written to be stateless because the constructor is not called for every invocation of the plug-in. In addition, multiple threads could be running the plug-in at the same time. All per invocation state information is stored in the context. This means that you should not use global class variables in plug-ins [Emphasis mine].
There's nothing wrong with passing objects from the context to helper classes which need them. The warning advises against storing something in a field ("class variable") on the plugin class itself, which may affect a subsequent call to Execute on the same instance, or cause concurrency problems if Execute is called by multiple threads on the same instance simultaneously.
Of course, this "globalness" has to be considered transitively. If you store anything in either the plugin class or in a helper class in any way that multiple calls to Execute can access (using fields on the plugin class or statics on either plugin or helper classes, for example), you leave yourself open to the same problem.
As a separate consideration, I would write the helper classes involved to accept types as specific to their function as possible - down to the level of individual entities - rather than the entire IServiceProvider. It's much easier to test a class which needs only an EntityReference than one which needs to have an entire IServiceProvider and IPluginExecutionContext mocked up.
On global variables vs injecting values required by classes
You're right, this is something that comes up everywhere in object-oriented code. Take a look at these two implementations:
public class CustomEntityFrubber
{
public CustomEntityFrubber(IOrganizationService service, Guid entityIdToFrub)
{
this.service = service;
this.entityId = entityIdToFrub;
}
public void FrubTheEntity()
{
// Do something with service and entityId.
}
private readonly IOrganizationService service;
private readonly Guid entityId;
}
// Initialised by the plugin's Execute method.
public static class GlobalPluginParameters
{
public static IOrganizationService Service
{
get { return service; }
set { service = value; }
}
public static Guid EntityIdToFrub
{
get { return entityId; }
set { entityId = value; }
}
[ThreadStatic]
private static IOrganizationService service;
[ThreadStatic]
private static Guid entityId;
}
public class CustomEntityFrubber
{
public FrubTheEntity()
{
// Do something with the members on GlobalPluginParameters.
}
}
So assume you've implemented something like the second approach, and now you have a bunch of classes using GlobalPluginParameters. Everything is going fine until you discover that one of them is occasionally failing because it needs an instance of IOrganizationService obtained by calling CreateOrganizationService(null), so it accesses CRM as the system user rather than the calling user (who doesn't always have the required privileges).
Fixing the second approach requires you to add another field to your growing list of global variables, remembering to make it ThreadStatic to avoid concurrency problems, then changing the code of CustomEntityFrubber to use the new SystemService property. You have tight coupling between all these classes.
Not only that, all these global variables hang around between plugin invocations. If your code has a bug that somehow bypasses the assignment of GlobalPluginParameters.EntityIdToFrub, suddenly your plugin is inexplicably operating on data that wasn't passed to it by the current call to Execute.
It's also not obvious exactly which of these global variables the CustomEntityFrubber requires, unless you read its code. Multiply that by however many helper classes you have, and maintaining this code starts to become a headache. "Now, does this object need me to have set Guid1 or Guid2 before I call it?" On top of that, the class itself can't be sure that some other code won't go and change the values of global variables it was relying on.
If you used the first approach, you simply pass in a different value to the CustomEntityFrubber constructor, with no further code changes needed. Furthermore, there's no stale data hanging around. The constructor makes it obvious which dependencies the class has, and once it has them, it can be sure that they don't change except in ways they were designed for.
As you say, you shouldn't put a member variable on the plugin since instances are cached and reused between requests by the plugin pipeline.
The approach I take is to create a class that perform the task you need and pass a modified LocalPluginContext (making it a public class) provided by the Developer Toolkit (http://msdn.microsoft.com/en-us/library/hh372957.aspx) on the constructor. Your class then can store the instance for the purposes of executing it's work just in the same way you would with any other piece of code. You are essentially de-coupling from the restrictions imposed by the Plugin framework. This approach also makes it easier to unit test since you only need to provide the execution context to your class rather than mocking the entire plugin pipeline.
It's worth noting that there is a bug in the automatically generated Plugin.cs class in the Developer Toolkit where it doesn't set the ServiceProvider property - At the end of the constructor of the LocalPluginContext add the line:
this.ServiceProvider = serviceProvider;
I have seen some implementations of an IoC approach in Plugins - but IMHO it makes the plugin code way too complex. I'd recommend making your plugins lean and simple to avoid threading/performance issues.
There are multiple things I would worry about in this design request (not that it's bad, just that one should be aware of, and anticipate).
IOrganizationService is not multi-thread safe. I'm assuming that other aspects of the IServiceProvider are not as well.
Testing things at an IServiceProvider level is much more complicated due to the additional properties that have to be mocked
You'd need a method for handle logging if you ever decided to call logic that is currently in your plugin, outside of the plugin (e.g. a command line service).
If you don't want to be passing the object around everywhere, the simple solution is to create a static property on some class that you can set it upon plugin execution, and then access from anywhere.
Of course now you have to handle issue #1 from above, so it'd have to be a singleton manager of some sort, that would probably use the current thread's id to set and retrieve the value for that thread. That way if the plugin is fired twice, you could retrieve the correct context based on your currently executing thread. (Edit Rather than some funky thread id lookup dictionary, #shambulator's ThreadStatic property should work)
For issue #2, I wouldn't be storing the IServiceProvider as is, but split up it's different properties (e.g. IPluginExecutionContext, IOrganizationService, etc)
For issue #3, it might make sense to store an action or a function in your manager rather than the object values themselves. For example, if rather than storing the IPluginExecutionContext, store a func that accepts a string to log and uses the IPlurginExeuctionContext to log. This allows other code to setup it's own logging, without being dependent on executing from within a plugin.
I haven't made any of these plugins myself, but I would treat the IServiceProvider like an I/O device.
Get the data you need from it and convert that data to format that suits your plugin. Use the transformed data to set up the other classes. Get the the output from the other classes and then translate back to terms the IServiceProvider can understand and use.
Your input and output are dependent on the IServiceProvider, but the processing doesn't have to be.
From Eduardo Avaria at http://social.microsoft.com/Forums/en-US/f433fafa-aff7-493d-8ff7-5868c09a9a9b/how-to-avoid-passing-a-context-reference-among-classes
Well, as someone at SO already told you, the global variables restriction is there cause the plugin won't instantiate again if it's called within the same context (the object context and probably other environmental conditions), so any custom global variable would be shared between that instances, but since the context will be the same, there's no problem in assigning it to a global variable if you want to share it between a lot of classes.
Anyways, I'd rather pass the context on the constructors and share it have a little more control over it, but that's just me.

Pitfalls of IIS 7.5, thread agility and static variables

I have an application running in IIS (ASP.NET) and a significant amount of times, the page loads but rendered and populated with information for a user different than the user who actually requested the page.
The data used to render and populate the page belongs to a user who also initiated a request at roughly the same point in time.
Could this be due to static variables and what I am now seeing referred to as thread agility?
This isn't an issue with thread agility, it's an issue with using static variables. Static variables are static for the PROCESS, not one thread. So, a static variable in ASP.NET is shared by EVERY request being made to your site. So, ask yourself: is this static variable MEANT to be shared among every requester, or is it specific to ONE requester? For example:
static int TotalPageHits; //Count the number of times a page has been requested
Clearly, this is perfectly fine data to share for ALL users. On the other hand:
static string CurrentUserId; //DANGER WILL ROBINSON!!!!
Any variable specific to one requester you want to put in HttpContext.Current.Items.
Static variables that contain user-specific data would explain the behavior you are seeing.
Thread agility might exascerbate the problem (e.g. make it more noticeable or lead to different manifestations of the problem, cause issues with ThreadStatic usage, etc.), but I would start by examining your usage of static members.
// bad - any caller can access this in any sequence
public static int CurrentUserId
{
get;
set;
}
// okay, because the backing storage is safe/segmented
public static int CurrentUserId
{
get { return (int)Session["CurrentUserId"]; }
set { Session["CurrentUserId"] = value; }
}
// data that you want to be shared
public static List<string> SomeValuesToBeShared
{
// safe for reading (if properly initialized)
// safe for writing only if appropriate locks are used
}
IF your code is really thread-safe this won't happen...
Use of static variables in such a context might a good starting point for investigation...
IF you mean anything marked ThreadStatic then this is a good starting point too...
To help in any specific way you need to provide much more details...

Looking for advice on thread safety using static methods to 'process' a class instance

I have recently inherited a system that uses a very basic approach to processing workitems, basically, it does them one by one. To be honest, up until recently this worked well. However, we are looking to implement a similiar process for another type of workitem and I have been looking into Task Parallel Library and think that will fit the bill. However, I have some concerns about Thread Safety and to be honest, this is an area that I lack knowledge, so I am asking only my 2nd question on here in hope that someone can give me some good points as I have yet to find a definitive yes or no answer for this.
So we have our 'WorkItem' class
public class WorkItem
{
public int Id {get; set;}
public string data { get; set;}
}
A List<WorkItem> will be generated and these will then be processed using a Parallel.Foreach loop.
The Parallel.Foreach will call a private method, which in turn will call static methods from another assembly;
//Windows service that will run the Parallel.Foreach
private int MainMethod(WorkItem item)
{
item.Data = Processor.ProcessWorkItemDataProcess1(item.data);
item.Data = Processor.ProcessWorkItemDataProcess2(item.data);
SendToWorkFlow(item);
}
public static class Processor
{
public static string ProcessWorkItemDataProcess1(string data)
{
//Process it here
return string
}
public static string ProcessWorkItemDataProcess2(string data)
{
//Process it here
return string
}
}
And so on. All of these methods have logic in them to process the WorkItem instance at various different stages. Once complete, the MainMethod will send the processed WorkItem off to a Workflow System.
We will be processing these in batches of up to 30 in order not to overload the other systems. My concerns are basically the potential of 30 instances of WorkItem accessing the same static methods could cause some data integrity issues. For example, ProcessWorkItemDataProcess2 is called with WorkItem1.Data and is subsequently called with WorkItem2.Data and somehow WorkItem2.Data is returned when it should be WorkItem1.Data
All of the static methods are self-contained in so far as they have defined logic and will only (in theory) use the WorkItem that it was called with. There are no methods such as DB access, file access, etc.
So, hopefully that explains what I am doing. Should I have any concerns? If so, will creating an instance of the Processor class for each WorkItem solve any potential problems?
Thanks in advance
The scenario you describe doesn't sound like it has any blatant threading issues. Your worries about a static method being called on two different threads and getting the data mixed up is unfounded, unless you write code to mix things up. ;>
Since the methods are static, they don't have any shared object instance to worry about. That's good. You have isolated the work into self-contained work items. That is good.
You will need to check to make sure that none of the static methods access any global state, like static variables or properties, or reading from a file (the same file name for multiple work items). Reading of global state is less of a concern, writing is what will throw a wrench in the works.
You should also review your code to see how data is assigned to your work items and whether any of the code that processes the work items modifies the work item data. If the work items are treated as strictly read only by the methods, that's good. If the methods write changes back to fields or properties of the work items, you will need to double check that the data in the work items is not shared with any other work items. If the code that constructs the work item instances assigns a cached value to a property of multiple work items, and the static methods modify properties of that value, you will have threading conflicts. If the work item construction always constructs new instances of values that are assigned to properties of the work item, this shouldn't be an issue.
In a nutshell, if you have multiple threads accessing shared state, and at least one is writing, then you need to worry about thread safety. If not then you're golden.

Static class variable behavior in ASP.NET 2.0?

If I've got this class defined as part of an app in ASP.NET 2.0:
public class Foo
{
private static int _seed = 100;
private static object myLock = new object();
public Foo()
{
lock (myLock)
{
this.MyInt = _seed;
_seed++;
}
}
public int MyInt {get; set;}
}
(Edit: updated to account for thread safety concerns as pointed out by answers)
How will that static member behave? Will it start at 100 and increment separately for every session, or will it increment separately for every page refresh, or is it global...?
Note: I'm asking this because I'm using classes to model data for the first time in my ASP.NET app, and I've already discovered that C#'s by-reference nature appears to be ignored by ViewState serialization, so I want to know what other weirdness I can expect. For example, if I have this class defined (assume Bar is another class):
public class OtherFoo
{
public List<Bar> Bars {get; set;}
}
and I do this on my page:
OtherFoo _myFoo = new OtherFoo();
//Code here to instantiate the list member and add some instances of Bar
Bar b = _myFoo.Bars[0];
ViewState["myFoo"] = _myFoo; //Assume both are [Serializable]
ViewState["myBar"] = b;
When I get those out of ViewState on the next postback, b and _myFoo.Bars[0] are no longer the same object.
ASP.NET is not magic. It doesn't magically turn the C# programming language (or any other language) into a language that is aware of web development (sessions, requests, etc).
Your code will behave exactly as it would in any other kind of application, with the addition that it can be called by multiple threads at the same time (so that using "++" is not safe).
Again, there is no magic. Just like every other application, the lifetime of a static is restricted to the lifetime of the AppDomain in which the type containing the static is loaded.
An AppDomain in an ASP.NET application is created the first time the application is accessed (unless the IIS settings force it to pre-start), and only ends at certain times, like when an assembly in the bin folder is changed, or the web.config is changed, or when the IIS settings say that the AppPool needs to be recycled.
It will increase the seed every time the constructor is invoked. Note that this can happen in multiple threads, so you better make it thread safe.
Deserialization will cause the (default) constructor to be invoked. If you serialize it to the ViewState, then ASP.NET will deserialize the object on postback, and thus invoke the constructor.
Please note that the C# language and the asp.net framework are on a whole other level. The framework is written (largely) in C#, and it will do a lot for you behind the scenes, but it still follows the rules of the language and the runtime.
Serialization is nothing more than encoding the information of an object (or graph of objects) to a stream. If you deserialize it, you will have the same information back, but it is not the same object you started with. Again, it is no magic, you could write your own serialization library using attributes and reflection.

Categories

Resources