1

Closed

Make storage cache thread safe, make role provider use storage cache.

description

Attached are my changes to make the above happen.
Also included in the role provider is my previously published cached dbuser support.
 
Sorry it took so long to get this update to you, I had been procrastinating because I would have to separate out my other 'db attributes' feature from this change. Was actually pretty easy though. :-)
 
Using storagecache is now threadsafe, just use it like you did before.
 
Using the new attached roleprovider - it uses a storagecache now. Internally, it also caches the dbUser. This makes websites so much faster. Final result is zero database calls around security when browsing your website. Use it just as you did before, but there are a couple of extra methods I exposed. You can access these methods via something like this;
 
NetSqlAzManRoleProvider myNetRoleProvider = (NetSqlAzManRoleProvider)System.Web.Security.Roles.Provider; //this just gets the default provider. If you have multiple you can use Roles.Provider["ProviderName"].
 
Once you have the provider and have cast it, you can call the new methods on it.
 
myNetRoleProvider.InvalidateCache() -- This causes the cache in the provider to be rebuilt. While it is being rebuilt, it continues to use the one it already has. When the rebuilding is done, it switches to the new one. Since all the roles are cached now, this is necessary to 'refresh' permissions.
 
myNetRoleProvider.CheckAccess(operation, [dbUserNameWindowsIdentity], [operationsonly]) -- This function is overloaded with the bracketed parameters shown. In your application, if you need to check a particular access (operation/task/role), you can use this function.
 
Finally, there is a region called 'SpecificToMyProject' - please remove this from what you commit to the repository. This is just where I use attributes to determine additional security features and would not apply to most people.
 
 
I have attached a patch to apply against the source. It only changes the NetSqlAzManRoleProvider.cs and StorageCache.cs

file attachments

Closed Jun 28, 2010 at 4:21 PM by aferende

comments

WayneBrantley wrote Jun 24, 2010 at 4:00 PM

My last merge with the latest source evidently removed two 'usings' that need to be in the NetSqlAzManProvider.cs.
Please add
using System.Linq;
using NetSqlAzMan.LINQ;

aferende wrote Jun 27, 2010 at 9:40 PM

Will be fixed for the next release.
Regards,
Andrea.

aferende wrote Jun 28, 2010 at 8:00 AM

Hi WayneBrantley,
thx for your collaboration.

I have analyzed your solution (patch) and I think that use of ToDictionary(…) and Hashtable may reduce the scalability as well as to use a large amount of memory.
My considerations to solve this issue:
1) Make StorageCache class thread-safe except for Storage Property
2) Adopt StorageCache inside NetSqlAzManRoleProvider for all “read-operations” (thread-safe)
3) Cut “Storage” property from NetSqlAzManRoleProvider (because Storage is not thread-safe, because Linq2Sql (used by Storage) is not thread-safe
4) Add a thread-safe version of the GetDBUsers inside NetSqlAzManRoleProvider instead of cache all db users (not good for scalability) (agains a new db connection)
5) Make the NetSqlAzManRoleProvider thread-safe by doing all write-operations against a new db connection

I’m working on this solution.

Any considerations will be appreciated.

Regards,
Andrea.

Andrea Ferendeles
NetSqlAzMan Project Coordinator
E-mail aferende@hotmail.com Web http://netsqlazman.codeplex.com

wrote Jun 28, 2010 at 4:21 PM

Resolved with changeset 49757.

WayneBrantley wrote Jun 29, 2010 at 3:57 PM

Andrea,
Thanks for investigating.
  • Not sure where I used ToDictionary(). The hashtable is created brand new for each request - so that should be safe. Not sure why you are thinking that creating that hashtable on each call is not going to scale, but I am sure there are other solutions. I used that because you had a 'class scoped' hashtable that was used in methods. By making that declared in each method call and still passing it to the methods that need it - made this work across threads. It is working and scaling so far - with no issues of any kind.
  • I am storing the cached users in a dictionary - but that is thread safe wrapped and what is stored is very small, just sid and username.
1) You know best.
2) Yes, I only use the role provider for READ ONLY - so i do not use the 'add role' and such from the provider. If I want to do that, I will use your API, which is why I was not worried about that. The reason for caching in the provider is to speed up the constant reading/lookups - not for wirting, so this may be good solution.
3) The storage I did is thread safe for all the reading parts....but it may not be for the writing, which I think is what you are talking about.
4) I am caching the dbusers on purpose - I had previously contributed this code and others are using it successfully too. The same 'give me SID for this username' query is called all the time in the provider - on every request. So caching this actually is great. Caching all the dbusers actually scales quite nicely considering I am only storing a SID and username - which is very small.
5) Probably a good idea.

With the patch I submitted, users can hit my website and there is NO role/rights database activity - and this is a great performance boost (visually noticeable)