Where and How to "cache" ASP.NET Role Data - asp.net

Design Choices
Presume two ASP.NET MVC authorization/role design stories. Both are intended to minimize hits against a middle-tier or data store:
After fetching “MyRoleProvider” info from a database, it is subsequently stored in the AuthTicket user-data which in turn means that the auth-cookie holds role-info. Furthermore, in this story, storing and retrieving this role-info is done by a distinct implementation, entirely outside "MyRoleProvider."
Or...
After fetching “MyRoleProvider” info from a database, it is subsequently stored in session and accessed from there. More precisely, the class “MyRoleProvider” itself will internally access (and update) session when possible.
Again, both the above stories aim to minimize the latency of hitting an external store by "caching" role info. Both work fine. The question is, are both design-story choices equally valid? If not, why?
The Issue
There appears to be no "best practice" stated anywhere, which says "your (custom) RoleProvider should always know where role-info is found, whether in session, cache, the database, etc."
Also, there appears to be no (solid) guidance anywhere that explains what kinds of things you should not store in "userData" in the authCookie. What little documentation and guidance there is suggests only two things:
'userData' can store additional user information (a vague, broad statement). I've seen only one code example online, which involved storing additional 3rd party identity/authentication info.
Do not put too much data in 'userData', because it might make the cookie become too big to be transferred (some browsers limit cookie size).
That's it. From the above guidance, nobody is being expressly told "it is a best practice to limit the userData only to authentication info." And I certainly have not seen a document which says "it is a bad idea to put authorization or role-info into 'userData' because..."
Deduce a Best Practice?
My own answer about the two design choices being equal is “no.” I want to present my argument, and learn from you if:
You agree.
You disagree, because I'm making needless fuss.
You disagree; although my argument is valid, there are even better arguments of why my thinking ultimately is not right.
Hopefully a best-practice concept will emerge as an answer. Now for my argument(s)...
My Argument(s)
I believe the second design-story should be taken, because it represents better modularity: role information is handled completely inside “MyRoleProvider.” The first option needlessly intermingles authentication (extracting identify from a cookie) and authorization concerns. Indeed, all the built-in ASP.NET security mechanisms keep these two topics separate; base ASP.NET functionality never stores role-info in the authcookie. If anyone wants to confirm this, try reflecting these classes: FormsAuthenticationModule, FormsAuthentication, IPrincipal with RolePrincipal implementaion, and IIdentity with FormsIdentity implementation.
The ASP.NET RolePrincipal deserves a particular highlight. It permits that role-info is indeed stored in a cookie, but it is a second cookie separate from the auth-cookie. Furthermore, this peculiar idiom still involves consultation with the RoleProvider. See the example section of this MSDN documentation.
Investigating RolePrincipal further, let's look at RolePrincipal.IsInRole(). Although any such IPrincipal derived class combines identity and role information programmatically, the internal implementation still maintains the RoleProvider as the only source of role information (note the reference to Roles.RoleProviders...):
public bool IsInRole(string role)
{
if (this._Identity != null)
{
if (!this._Identity.IsAuthenticated || role == null)
{
return false;
}
else
{
role = role.Trim();
if (!this.IsRoleListCached)
{
this._Roles.Clear();
string[] rolesForUser = Roles.Providers[this._ProviderName].GetRolesForUser(this.Identity.Name);
string[] strArrays = rolesForUser;
for (int i = 0; i < (int)strArrays.Length; i++)
{
string str = strArrays[i];
if (this._Roles[str] == null)
{
this._Roles.Add(str, string.Empty);
}
}
this._IsRoleListCached = true;
this._CachedListChanged = true;
}
return this._Roles[role] != null;
}
}
else
{
throw new ProviderException(SR.GetString("Role_Principal_not_fully_constructed"));
}
}
This kind of ASP.NET “one-stop” deep-assumption of where role information is found, is why role info should be consolidated into the RoleProvider. In short I claim:
If you do store role info in a cookie, the reason why ASP.NET does not have a built-in capability to combine that into the auth-cookie, is precisely because ASP.NET maintains strongly a separation of concerns between the different providers.
Any RoleProvider should be aware of where role-info might be found, whether in a cookie, session, or otherwise.
Conclusion:
Do not put role-info into the auth-cookie, and ensure your (custom) RoleProvider knows all the places where role info is found, whether the database, a web service, session, cache, or a cookie.
Agree? Disagree? Thoughts?

There are a LOT of different concerns and design choices that go into deciding where to actually cache information whether it be cookie, session or some other provider.
Of course, the first question is whether you should even cache it at all. Sure there are concerns with regards to constantly accessing the database for fairly static information. However, there are equal concerns of being able to lock someone out immediately.
Only if an immediate response isn't needed does caching become viable. Because of this there can be no best practice with regards to caching authorization.. and certainly no best practices on where to cache it if your application doesn't need that level of security.
Presuming the above isn't an issue then there are trade offs with location.
Cookie
If you put it in a cookie, then it can be captured and subsequently replayed. Also it slightly increases your internet traffic because the cookie is transferred on every request.
Session
If you put it in session, then you either limit yourself to a single web server OR you must have session state stored in a location accessible by the entire web farm. If you take the latter route, then it's entirely likely you are storing session in a database somewhere thereby completely trashing your reason for having it in session to begin with.
Memcache or other
This is similar to storing the roles in session; however it's typically stored in memory on a separate server and is generally fast. The drawback is that for a load balanced web farm this can add yet another point of failure... unless it is properly clustered. At which point you've increased project development, deployment and maintenance costs....
Ultimately, there isn't a best practice. Only a bunch of trade-offs that are very situation dependent. Quite frankly for this type of data, I wouldn't cache it at all. It's usually relatively small and queries for it are generally quite fast. I might consider it if we were talking tens of thousands of users, but at that level there are many other operational considerations that would ultimately make the choice here apparent.

It seems to me that you're asking an absurd question. Nobody in their right mind would store role data in the authentication cookie. ASP.NET doesn't do it that way precisely because they provide the RolePrincipal that will store it in an encrypted separate cookie.
The whole issue of cookie is kind of pointless anyhow, since this is an implementation detail of the RolePrincipal. The app should not be cognizant of where the role data is stored.
So my question to you is... Why are we even having this discussion? You're asking if it's best practice to do something contrary to how it's done by the system, and then arguing why you shouldn't do it in this way nobody would ever use.
Also, your comment about the RoleProvider having to deal with the cookie is not true. RoleProvider does not create the RolePrincipal, this is done inside the framework. The choice of whether to use cookies is not in the RoleProvider, but rather provided by the RoleManagerModule framework class, and the way IPrincipals are instantiated by the framework.
The example in the RolePrincipal has nothing to do with the RoleProvider. In fact, the RoleManagerModule controls this functionality. RoleManagerModule is an HttpModule that is installed into IIS and runs as part of the pipeline. It doesn't even know about the RoleProvider, and basically what this means is that the Roles are populated from the cookie at a very low level, and when `RoleProvider gets around to running, if it finds the roles already there, it just does nothing.

Related

ASP.NET Passing Data Between Multiple Pages Session

So there seems not be any pretty answer to the question of how pass data between multiple pages. After having done a little homework here's why (or at least what I've gleaned):
ViewState variables don't persist across pages.
Session variables are volatile and must be used sparingly.
Cookies have potential safety issues and take time and must be kept small.
Storing vars in the URL has limits to the amount of data and can be unsafe.
Storing vars temporarily in a db is a real pita because you add one table per object that might be potentially passed to another page.
So far it is looking like I will be using hidden fields to pass a keyid and unique id to the next page and then retrieve the data from the db. What are your thoughts on all of this? What is the best way to go about doing any of it? I am early in the development of this app, so making changes now is preferred.
edit: I am anticipating a lot of users using this application at any one time, does that affect whether or not I should be using SQL Server based Session?
If you want to persist state, yes store it in the database since you don't have to worry about an expiration. The Session is similar except you have to worry about the Session expiring. In both cases concurrent calls that write similar data to the same area could cause problems and need to be accounted for.
Session is good when you don't have to worry about multiple web servers or timeout issues. The database gives you more scalability but at a cost of doing lots of db read/writes and you have to consider clean up.
Personally I would try to use the following decision tree:
Is the data simple, short and not private -> query string
Is the data less simple but only needs to exist for a short time -> session
Will the data be needed across multiple area and be persistent for long period of time -> database
Of course there is more to it that this but that should give you a basic outline of considerations since you are just starting out. Keep it simple. Don't try to over engineer a solution if a simple query string will suffice. You can always over engineer late as long as you have kept it simple to start.
I think context is important here, e.g. what are you trying to pass between pages and why?
If you are dealing with complex, multi-part forms, then you can implement the form in a single page, simply showing or hiding relevant element. Use usercontrols and custom controls as much as possible to facilitate isolation and reusability. This makes life a lot easier across the board.
Anything that is user-generated is almost certainly going to end up in a database anyway - so #5 does not seem relevant. That is you shouldn't have to store data "temporarily" in a database- what data would need to be persisted between pages that isn't part of your application.
Anything else would seem to be session related and not that much data.
I could add some more thoughts if I knew what specifically you were dealing with.
Oh - "cookies have potential safety issues and take time" - you're going to use cookies, unless you don't want to be able to identify return visitors. Any potential safety issues would only be a result of bad implementation, and certainly passing data in hidden fields is no better. And you really don't want to get into writing an ASP.NET app that is designed around pages posting to forms other than itself. That's just a headache for many reasons and I can't think of a benefit of doing this as part of basic application design.
Session variables should work fine for your needs.
I would go with StateServer or SQLServer Session state mode. Using mode InProc is the fastest, but it has some issues (including all user sessions getting dropped when a new binary is pushed, web.config changes, etc). Sessions are volatile, but you can control the volatility in several ways. Sessions require cookies unless they are configured as cookieless (which I highly recommend you stay away from), but I think that is a reasonable requirement.
Also, you can create a struct or serializable class from which you create objects that you can store in a session variable. The struct or class will allow you to keep all of your data in one place - you only have one session variable to worry about.
There is going to be advantages and disadvantages for any method, it's all about finding the best method. I hope this helps.
All methods have their pros and cons. It would all depend on the scenario you are working in.
Session variables work quite well if used within reason. InProc sessions in traffic heavy sites can quickly drain your resources but you can always switch to SQL Server based session that does most of the DB work for you.

ASP.NET 2 Session State Between Authenticated Users

I am developing a website for a client (ASP.NET, T-SQL). It is a data-entry website allowing many of their users to login and manipulate records in the same database.
There are instructions (basically a list of string) throughout the form, telling the users what to do for each section; these instructions are themselves present in the database.
On each login, I store these instructions in the Session[] object per authenticated user. The instructions are identical for everyone.
I've looked at a solution which suggested storing a common session identifier in the database and then querying it to re-use that particular session but this seems very hacky. What is a best-practices solution to accomplish this? Is there a 'common' object available to all users?
Firstly, does it matter at this point? Yes, it's bad practice and inefficent, but if you're storing 20Kb of strings in memory and have a maximum of 100 users, that's 2,000Kb of data. Hardly a lot of memory "wasted". Even at 200Kb of strings, that's 20,000Kb of data. Again, not a lot. Is it worth your time, and the client waiting for you to solve it, right now?
If you decide it is then you could:
Store the strings in the Application object or a static class so that they're retrieved once and used many times.
Retrieve the strings on every page view. This may not be as performance damaging as it seems.
Use something like the Cache class in System.Web.Caching.
Make use of Output Caching.
Make use of Windows Server AppFabric "Velocity" memory cache.
Sounds to me like you're looking for the Application Cache. Like the Session, it is an in-memory cache of data. Unlike the session, it is shared among all users; each user doesn't get their own individual copy of the data. Also, when you add data elements to the cache, you can specify criteria which will automatically invalidate that data, and cause it to be reloaded/refreshed (useful when your seldom-changing data actually does change :).
Here's some articles which should give you everything you need to know about using the Application cache (and some other caching options within ASP.NET as well):
ASP.NET Caching Overview
Using the ASP.NET Application Cache to Make Your Applications Scream
Caching Data at Application Startup
.NET Data Caching
I would suggest using the application-level Cache object. It is available everywhere as part of HttpContext. You can populate it on App_Start.
You can put any kind of object into Cache, though obviously, the smaller the better.
Here are some examples of how to populate it using C#:
1) Add items to the cache as you would add items to a dictionary by specifying the item's key & value.
Example: add the current Value property of a text box to the cache.
Cache["txt1"] = txtName.value;
or
Cache["result"] = dataset;
2) The Insert method is overloaded, allowing you to define values for the parameters of the version you're using.
Example: add only an item key & value:
Cache.Insert("MyData1", connectionString);
3) The Add method has the same signature as the Insert method, but it returns an object representing the item you added.
Cache.Add("MyData1", connectionString);
To retrieve the from cache:
stringName = Cache["MyData"];
If the cached data is not a string, you may need to cast it to the proper data type.
result = (DataSet)Cache["result"];
One of the benefits of using the Cache object as opposed to the Application object is that the CLR will dump contents of Cache if the system is in danger of running out of memory.

Ways to store an object across multiple postbacks

For the sake of argument assume that I have a webform that allows a user to edit order details. User can perform the following functions:
Change shipping/payment details (all simple text/dropdowns)
Add/Remove/Edit products in the order - this is done with a grid
Add/Remove attachments
Products and attachments are stored in separate DB tables with foreign key to the order.
Entity Framework (4.0) is used as ORM.
I want to allow the users to make whatever changes they want to the order and only when they hit 'Save' do I want to commit the changes to the database. This is not a problem with textboxes/checkboxes etc. as I can just rely on ViewState to get the required information. However the grid is presenting a much larger problem for me as I can't figure out a nice and easy way to persist the changes the user made without committing the changes to the database. Storing the Order object tree in Session/ViewState is not really an option I'd like to go with as the objects could get very large.
So the question is - how can I go about preserving the changes the user made until ready to 'Save'.
Quick note - I have searched SO to try to find a solution, however all I found were suggestions to use Session and/or ViewState - both of which I would rather not use due to potential size of my object trees
If you have control over the schema of the database and the other applications that utilize order data, you could add a flag or status column to the orders table that differentiates between temporary and finalized orders. Then, you can simply store your intermediate changes to the database. There are other benefits as well; for example, a user that had a browser crash could return to the application and be able to resume the order process.
I think sticking to the database for storing data is the only reliable way to persist data, even temporary data. Using session state, control state, cookies, temporary files, etc., can introduce a lot of things that can go wrong, especially if your application resides in a web farm.
If using the Session is not your preferred solution, which is probably wise, the best possible solution would be to create your own temporary database tables (or as others have mentioned, add a temporary flag to your existing database tables) and persist the data there, storing a single identifier in the Session (or in a cookie) for later retrieval.
First, you may want to segregate your specific state management implementation into it's own class so that you don't have to replicate it throughout your systems.
Second, you may want to consider a hybrid approach - use session state (or cache) for a short time to avoid unnecessary trips to a DB or other external store. After some amount of inactivity, write the cached state out to disk or DB. The simplest way to do this, is to serialize your objects to text (using either serialization or a library like proto-buffers). This helps allow you to avoid creating redundant or duplicate data structure to capture the in-progress data relationally. If you don't need to query the content of this data - it's a reasonable approach.
As an aside, in the database world, the problem you describe is called a long running transaction. You essentially want to avoid making changes to the data until you reach a user-defined commit point. There are techniques you can use in the database layer, like hypothetical views and instead-of triggers to encapsulate the behavior that you aren't actually committing the change. The data is in the DB (in the real tables), but is only visible to the user operating on it. This is probably a more complicated implementation than you may be willing to undertake, and requires intrusive changes to your persistence layer and data model - but allows the application to be ignorant of the issue.
Have you considered storing the information in a JavaScript object and then sending that information to your server once the user hits save?
Use domain events to capture the users actions and then replay those actions over the snapshot of the order model ( effectively the current state of the order before the user started changing it).
Store each change as a series of events e.g. UserChangedShippingAddress, UserAlteredLineItem, UserDeletedLineItem, UserAddedLineItem.
These events can be saved after each postback and only need a link to the related order. Rebuilding the current state of the order is then as simple as replaying the events over the currently stored order objects.
When the user clicks save, you can replay the events and persist the updated order model to the database.
You are using the database - no session or viewstate is required therefore you can significantly reduce page-weight and server memory load at the expense of some page performance ( if you choose to rebuild the model on each postback ).
Maintenance is incredibly simple as due to the ease with which you can implement domain object, automated testing is easily used to ensure the system behaves as you expect it to (while also documenting your intentions for other developers).
Because you are leveraging the database, the solution scales well across multiple web servers.
Using this approach does not require any alterations to your existing domain model, therefore the impact on existing code is minimal. Biggest downside is getting your head around the concept of domain events and how they are used and abused =)
This is effectively the same approach as described by Freddy Rios, with a little more detail about how and some nice keyword for you to search with =)
http://jasondentler.com/blog/2009/11/simple-domain-events/ and http://www.udidahan.com/2009/06/14/domain-events-salvation/ are some good background reading about domain events. You may also want to read up on event sourcing as this is essentially what you would be doing ( snapshot object, record events, replay events, snapshot object again).
how about serializing your Domain object (contents of your grid/shopping cart) to JSON and storing it in a hidden variable ? Scottgu has a nice article on how to serialize objects to JSON. Scalable across a server farm and guess it would not add much payload to your page. May be you can write your own JSON serializer to do a "compact serialization" (you would not need product name,product ID, SKU id, etc, may be you can just "serialize" productID and quantity)
Have you considered using a User Profile? .Net comes with SqlProfileProvider right out of the box. This would allow you to, for each user, grab their profile and save the temporary data as a variable off in the profile. Unfortunately, I think this does require your "Order" to be serializable, but I believe all of the options except Session thus far would require the same.
The advantage of this is it would persist through crashes, sessions, server down time, etc and it's fairly easy to set up. Here's a site that runs through an example. Once you set it up, you may also find it useful for storing other user information such as preferences, favorites, watched items, etc.
You should be able to create a temp file and serialize the object to that, then save only the temp file name to the viewstate. Once they successfully save the record back to the database then you could remove the temp file.
Single server: serialize to the filesystem. This also allows you to let the user resume later.
Multiple server: serialize it but store the serialized value in the db.
This is something that's for that specific user, so when you persist it to the db you don't really need all the relational stuff for it.
Alternatively, if the set of data is v. large and the amount of changes is usually small, you can store the history of changes done by the user instead. With this you can also show the change history + support undo.
2 approaches - create a complex AJAX application that stores everything on the client and only submits the entire package of changes to the server. I did this once a few years ago with moderate success. The applicaiton is not something I would want to maintain though. You have a hard time syncing your client code with your server code and passing fields that are added/deleted/changed is nightmarish.
2nd approach is to store changes in the data base in a temp table or "pending" mode. Advantage is your code is more maintainable. Disadvantage is you have to have a way to clean up abandonded changes due to session timeout, power failures, other crashes. I would take this approach for any new development. You can have separate tables for "pending" and "committed" changes that opens up a whole new level of features you can add. What if? What changed? etc.
I would go for viewstate, regardless of what you've said before. If you only store the stuff you need, like { id: XX, numberOfProducts: 3 }, and ditch every item that is not selected by the user at this point; the viewstate size will hardly be an issue as long as you aren't storing the whole object tree.
When storing attachments, put them in a temporary storing location, and reference the filename in your viewstate. You can have a scheduled task that cleans the temp folder for every file that was last saved over 1 day ago or something.
This is basically the approach we use for storing information when users are adding floorplan information and attachments in our backend.
Are the end-users internal or external clients? If your clients are internal users, it may be worthwhile to look at an alternate set of technologies. Instead of webforms, consider using a platform like Silverlight and implementing a rich GUI there.
You could then store complex business objects within the applet, provide persistant "in progress" edit tracking across multiple sessions via offline storage and easily integrate with back-end services that providing saving / processing of the finalised order. All whilst maintaining access via the web (albeit closing out most *nix clients).
Alternatives include Adobe Flex or AJAX, depending on resources and needs.
How large do you consider large? If you are talking sessions-state (so it doesn't go back/fore to the actual user, like view-state) then state is often a pretty good option. Everything except the in-process state provider uses serialization, but you can influence how it is serialized. For example, I would tend to create a local model that represents just the state I care about (plus any id/rowversion information) for that operation (rather than the full domain entities, which may have extra overhead).
To reduce the serialization overhead further, I would consider using something like protobuf-net; this can be used as the implementation for ISerializable, allowing very light-weight serialized objects (generally much smaller than BinaryFormatter, XmlSerializer, etc), that are cheap to reconstruct at page requests.
When the page is finally saved, I would update my domain entities from the local model and submit the changes.
For info, to use a protobuf-net attributed object with the state serializers (typically BinaryFormatter), you can use:
// a simple, sessions-state friendly light-weight UI model object
[ProtoContract]
public class MyType {
[ProtoMember(1)]
public int Id {get;set;}
[ProtoMember(2)]
public string Name {get;set;}
[ProtoMember(3)]
public double Value {get;set;}
// etc
void ISerializable.GetObjectData(
SerializationInfo info,StreamingContext context)
{
Serializer.Serialize(info, this);
}
public MyType() {} // default constructor
protected MyType(SerializationInfo info, StreamingContext context)
{
Serializer.Merge(info, this);
}
}

what will happen if not lock the dictionary when i modify it? about asp.net cache

sorry i have many questions about the lock/cache.=_=..
->1. about cache, i know that the cache in asp.net is threadsafe, the simple code i usually use is
IList<User> user= HttpRuntime.Cache["myCacheItem"] as IList<User>;
if (user == null)
{
//should i have a lock here?
//lock(some_static_var){...}
HttpRuntime.Cache["myCacheItem"] = GetDateFromDateBase();
}
return user;
should use a lock in the code?
->->1.1 if i use, maybe i should declare many lockitem? i have seen some implementation in community server, it use a static dictionary to store the lockitem, is it a good idea? cause i am worried that it maybe too many lockitems in the dictionary and it maybe slow down the system.
->->1.2 if i don't use, what will happen? just maybe two or more threads access the GetDateFromDateBase()? if just this, i think maybe i can give up the lock.
->2.i have a generic dictionary stored in the cache, i have to modify(add/update/delete) it. and i just use it to get the value like dic.trygetvalue(key), don't loop it.
->->2.1 if i can guarantee that the modify is just happen in only one thread, the scene like
a.aspx -> read the dictionary from cache, and display on the page, public for user
b.ashx -> will modify the dictionary when call it.(loop in 5 minutes),private used
should i use lock in a/b? lock reader and writer?
->->->2.11 if i don't use any lock, what will happened? will it throw exception when the reader and writer access on the same time?
->->->2.12 if i just lock the writer in b.ashx, what will happen? will the reader in a.aspx blocked? and what's the best practice to deal with this situation?
->->2.2 if the reader and writer both occured in the multi threads access. they are both the in public page.
a.aspx -> just read from cache
b.aspx -> modify the dictionary
what to do? lock all?
->->2.3 if i implement a new dictionary add function:
it just copy the current dictionary to a new dictionary and then add the new item or modify
and at last return the new dic,,will it solve the concurrency problem?
will the hashtable solve these problem?
how to determine a item need be locked? i think i'm wrong in these things=_=.
->3.the last question..i have two web application
a -> show the web
b -> mamage some settings
they both have own cache, what can i concurrent the two cache?
will the operation in [2.1] right or other operation?(i test memcached but it too slow than in the web application, so i just use two)
thank you for reading all-_-...
wish you can know what i say:)
Update======================================================
Thanks for Aaron's answer. after read his answer, i try to answer myself:)
1. about cache, if the data will not modify, it can read into cache first in Application_Start(global.asax).
1.1 If lock, i should add lock start when reading the data, not only writing. the lock item should static but i also feel uncerrain about 1.1.
1.2 Yes, if you can premise that the code is just read date from database and then insert into cache and will not modify(right?-_-). the result of this maybe read several times from database. i think this is not a big problem.
2. the generic dictionary write is not threadsafe, so it should be lock when modify. To solve this, i can use a immutable dictionary.
but if i use a ConcurrentDictionary(threadsafe when read/write) in .net4.0 or i implement a new dictionary(use reader-writer lock) myself, will it solve? Do i need lock it again when modify? the code is like
ConcurrentDictionary user= HttpRuntime.Cache["myCacheItem"] as ConcurrentDictionary;
if (user == null)
{
//is it safe when the user is ConcurrentDictionary?
HttpRuntime.Cache["myCacheItem"] = GetDateFromDateBase();
}
else
{
//is it safe when the user is ConcurrentDictionary?
user["1"] = a_new_user;
}
3.the question is that, i have a small application like a stroe, it have two web application one is the store show site(A) and the other is the management site(B), so i need to concurrnt two web cache, like that if i modify a product price in B, how can i notify site A to change/delete cache?(i know that the cache in A can set shortor, but it not quickly, so i want to know wheather there have a inner support in asp.net or just like question 2.1? have a aspx/ashx page to call?)
Thread-safe means that you do not have to worry about multiple threads reading and writing the same individual cache item at the same time. You do not need any kind of lock for simple reads and writes.
However, if you are trying to perform what should be an atomic operation - for example, checking for the presence of an item and adding it if it doesn't exist - then you need to synchronize or serialize access. Because the lock needs to be global, it is usually best to declare a static readonly object in your global.asax and lock that before performing the atomic operation. Note that you should lock before the read and only release the lock after the write, so your hypothetical lock in your example above is actually happening too late.
This is why many web applications don't lazy-load the cache; instead, they perform the load in the Application_Start method. At the very least, putting an empty dictionary into the cache would save you the trouble of checking for null, and this way you wouldn't have to synchronize because you would only be accessing the cache item once (but read on).
The other aspect to the problem is, even though the cache itself is thread-safe, it does not make any items you add to it thread-safe. That means that if you store a dictionary in there, any threads that retrieve the cache item are guaranteed to get a dictionary that's fully-initialized, but you can still create race conditions and other thread-safety issues if you have multiple requests trying to access the dictionary concurrently with at least one of them modifying it.
Dictionaries in .NET can support multiple concurrent readers but not writers, so you definitely can run into issues if you have a single dictionary stored in the ASP.NET cache and have multiple threads/requests reading and writing. If you can guarantee that only one thread will ever write to the dictionary, then you can use the Dictionary as an immutable type - that is, copy the dictionary, modify the copy, and replace the original in the cache with the copy. If the dictionary is infrequently-modified, then this would indeed save you the trouble of synchronizing access, because no request will ever be trying to read from the same dictionary that is being modified. On the other hand, if the dictionary is very large and/or frequently modified, then you could run into performance issues making all those copies - the only way to be sure is profile, profile, profile!
If you find that performance constraints don't allow to use that approach, then the only other option is to synchronize access. If you know that only one thread will ever modify the dictionary at a time, then a reader-writer lock (i.e. ReaderWriterLockSlim) should work well for you. If you can't guarantee this, then you need a Monitor (or just a simple lock(...) clause around each sequence of operations).
That should answer questions 1-2; I'm sorry but I don't quite understand what you're asking in #3. ASP.NET applications are all instantiated in their own AppDomains, so there aren't really any concurrency issues to speak of because nothing is shared (unless you are actually using some method of IPC, in which case everything is fair game).
Have I understood your questions correctly? Does this help?

storing state across postback

What is the best way to store string data across postback. I need to store an ID and name for multiple entities. I was thinking of using a datatable in viewstate, but would that make viewstate grow too large? I can't use a database yet because I'll be inserting a record that those other records need to be related to. So I'll just be storing them temporarily until the user submits the form.
You actually have a lot of options - the one you choose will entirely depend on the requirements of your own application.
ViewState - you can add the data to the page's viewstate. The advantages of this is that the data will live only for the lifetime of the user being on the page and posting it back to the server. Another advantage of it over hidden fields is that it is harder for users to hack into it and alter your values (I believe, in fact, that you can encrypt your viewstate). The disadvantage, of course, lies in page sizes - everything you add to the view state is one more thing that gets dropped on a user's page and then gets posted back to the server. This makes it non-optimal for storing large amounts of data.
Cookies - You can toss the information back to the user in the form of cookies. In this case, you can declare how long the information will last - for the scope of the user having their browser open, or for a specific calendar time. The information will be available to any page of your application each time the user hits that page. The bad news is that you are limited in the amount of information you can store, and that users can very readily alter their own cookies.
Session - You're storing the user's information on your own server's memory (I'll leave aside the discussion of various types of session storage). In this case the information will live as long as your user's session lives, and will be available to all pages of your application. There is no risk of user's modifying those values directly, though session hijacking is a risk you may want to explore. The disadvantage, though, is that you are using precious server resources in this case - if your application has a large load, it may affect your scalability in the future.
As I said - what you choose to do will entirely depend on the needs and requirements of your application.
several ways (though not an exhaustive list):
ViewStatehidden fieldssessionquery stringcookies
ViewState is fine. If you are storing it across postbacks, a client-side solution is best. So, you'd be adding size somewhere--either in ViewState or hidden fields.
If you want to do this server-side, you can use the Session, but remember to clean it up when you can.
you could just store them to a cookie, this would allow you to access them from Javascript too. Alternatively you could store a simple string array to the view state. A lot depends on what and how much information you wish to store.
When I have this scenario I create a structure for my fields that I stuff into Viewstate. I'm okay with having a small structure added into the page size and lifecycle considering the entire page's controls set is there already :)
Furthermore it cleans up after itself after you're done with the page, so there's no worrying about filling your Session with crap.
I concur with the accepted answer but I would also add that if you only want to keep track of a simple key/value collection you would be better putting a generic Dictionary into either ViewState or Session:
Dictionary<int, string> myValues = new Dictionary<int, string>();
myValues.Add(1, "Apple");
maValues.Add(2, "Pear");

Resources